Android更換皮膚解決方案,android解決方案

來源:互聯網
上載者:User

Android更換皮膚解決方案,android解決方案
Android更換皮膚解決方案

轉載請註明出處:IT_xiao小巫

本篇部落格要給大家分享的一個關於Android應用換膚的Demo,大家可以到我的github去下載demo,以後博文涉及到的代碼均會上傳到github中統一管理。
github地址:https://github.com/devilWwj/Android-skin-update

思路

換膚功能一般有什嗎?
元素一般有背景顏色、字型顏色、圖片、布局等等

我們知道Android中有主題Theme還有style,theme是針對整個activity的,而style可以針對指定控制項,如果比較少的替換可以在app內做,但如果需要動態來做,可以選擇下面這種思路:
把app和skin分開,將skin做成一個apk,作為一個外掛程式來提供給app使用,這樣可以做到線上下載皮膚,然後動態更換皮膚

下面這個demo,小巫是建立了一個res的工程項目,簡單提供了一個colors.xml,在裡面指定了背景顏色和按鈕顏色:

<?xml version="1.0" encoding="utf-8"?><resources>    <color name="day_btn_color">#E61ABD</color>    <color name="day_background">#38F709</color>    <color name="night_btn_color">#000000</color>    <color name="night_background">#FFFFFF</color></resources>

裡面沒有任何邏輯代碼,只提供資源檔,然後我們匯出為skin.apk檔案,複製到目標項目的assets中去。

因為這裡不涉及到下載皮膚這個操作,所以直接放到assets目錄下,然後在程式中把assets下的apk檔案複製到sd卡中.
在程式中提供一個皮膚包管理器

package com.devilwwj.skin;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Method;import android.content.Context;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.content.res.AssetManager;import android.content.res.Resources;import android.os.AsyncTask;/** * 皮膚包管理器 *  * @author devilwwj *  */public class SkinPackageManager {    private static SkinPackageManager mInstance;    private Context mContext;    /**     * 當前資源套件名     */    public String mPackageName;    /**     * 皮膚資源     */    public Resources mResources;    public SkinPackageManager(Context mContext) {        super();        this.mContext = mContext;    }    /**     * 擷取單例     *      * @param mContext     * @return     */    public static SkinPackageManager getInstance(Context mContext) {        if (mInstance == null) {            mInstance = new SkinPackageManager(mContext);        }        return mInstance;    }    /**     * 從assets中複製apk到sd中     *      * @param context     * @param filename     * @param path     * @return     */    public boolean copyApkFromAssets(Context context, String filename,            String path) {        boolean copyIsFinish = false;        try {            // 開啟assets的輸入資料流            InputStream is = context.getAssets().open(filename);            File file = new File(path);            // 建立一個新的檔案            file.createNewFile();            FileOutputStream fos = new FileOutputStream(file);            byte[] temp = new byte[1024];            int i = 0;            while ((i = is.read(temp)) > 0) {                fos.write(temp, 0, i); // 寫入到檔案            }            fos.close();            is.close();            copyIsFinish = true;        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }        return copyIsFinish;    }    /**     * 非同步載入皮膚資源     *      * @param dexPath     *            需要載入的皮膚資源     * @param callback     *            回調介面     */    public void loadSkinAsync(String dexPath, final loadSkinCallBack callback) {        new AsyncTask<String, Void, Resources>() {            @Override            protected void onPreExecute() {                super.onPreExecute();                if (callback != null) {                    callback.startloadSkin();                }            }            @Override            protected Resources doInBackground(String... params) {                try {                    if (params.length == 1) {                        //                        String dexPath_tmp = params[0];                        // 得到包管理器                        PackageManager mpm = mContext.getPackageManager();                        // 得到包資訊                        PackageInfo mInfo = mpm.getPackageArchiveInfo(                                dexPath_tmp, PackageManager.GET_ACTIVITIES);                        mPackageName = mInfo.packageName;                        // AssetManager執行個體                        AssetManager assetManager = AssetManager.class                                .newInstance();                        // 通過反射調用addAssetPath方法                        Method addAssetPath = assetManager.getClass()                                .getMethod("addAssetPath", String.class);                        addAssetPath.invoke(assetManager, dexPath_tmp);                        // 得到資源執行個體                        Resources superRes = mContext.getResources();                        // 執行個體化皮膚資源                        Resources skinResource = new Resources(assetManager,                                superRes.getDisplayMetrics(),                                superRes.getConfiguration());                        // 儲存資源路徑                        SkinConfig.getInstance(mContext).setSkinResourcePath(                                dexPath_tmp);                        return skinResource;                    }                } catch (Exception e) {                    return null;                }                return null;            }            @Override            protected void onPostExecute(Resources result) {                super.onPostExecute(result);                mResources = result;                // 這裡執行回調方法                if (callback != null) {                    if (mResources != null) {                        callback.loadSkinSuccess();                    } else {                        callback.loadSkinFail();                    }                }            }        }.execute(dexPath);    }    public static interface loadSkinCallBack {        public void startloadSkin();        public void loadSkinSuccess();        public void loadSkinFail();    }}

重點關注這個類,裡面提供了一個非同步方法呼叫對包和asset進行操作,這裡用到了反射機制,反射調用addAssetPath來添加assets的路徑,這個路徑就是我們skin.apk的路徑。具體細節,各位查看代碼。

我們在Activity介面中使用上面提供的方法:

package com.devilwwj.skin;import android.app.Activity;import android.content.res.Resources;import android.os.Bundle;import android.os.Environment;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;import com.devilwwj.skin.SkinPackageManager.loadSkinCallBack;/** * 功能:切換皮膚 * @author devilwwj * */public class MainActivity extends Activity implements OnClickListener,        ISkinUpdate {    private static final String APK_NAME = "skin.apk";    private static final String DEX_PATH = Environment            .getExternalStorageDirectory().getAbsolutePath() + "/skin.apk";    private Button dayButton;    private Button nightButton;    private TextView textView;    private boolean nightModel = false;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        dayButton = (Button) findViewById(R.id.btn_day);        nightButton = (Button) findViewById(R.id.btn_night);        textView = (TextView) findViewById(R.id.text);        // 把apk檔案複製到sd卡        SkinPackageManager.getInstance(this).copyApkFromAssets(this, APK_NAME,                DEX_PATH);    }    @Override    protected void onResume() {        super.onResume();        if (SkinPackageManager.getInstance(this).mResources != null) {            updateTheme();        }    }    @Override    public void onClick(View v) {        switch (v.getId()) {        case R.id.btn_day:            nightModel = false;            loadSkin();            break;        case R.id.btn_night:            nightModel = true;            loadSkin();            break;        default:            break;        }    }    /**     * 載入皮膚     */    private void loadSkin() {        SkinPackageManager.getInstance(this).loadSkinAsync(DEX_PATH,                new loadSkinCallBack() {                    @Override                    public void startloadSkin() {                        Log.d("xiaowu", "startloadSkin");                    }                    @Override                    public void loadSkinSuccess() {                        Log.d("xiaowu", "loadSkinSuccess");                        // 然後這裡更新主題                        updateTheme();                    }                    @Override                    public void loadSkinFail() {                        Log.d("xiaowu", "loadSkinFail");                    }                });    }    @Override    public void updateTheme() {        Resources mResource = SkinPackageManager.getInstance(this).mResources;        if (nightModel) {            // 如果是黑夜的模式,則載入黑夜的主題            int id1 = mResource.getIdentifier("night_btn_color", "color",                    "com.devilwwj.res");            nightButton.setBackgroundColor(mResource.getColor(id1));            int id2 = mResource.getIdentifier("night_background", "color",                    "com.devilwwj.res");            nightButton.setTextColor(mResource.getColor(id2));            textView.setTextColor(mResource.getColor(id2));        } else {            // 如果是白天模式,則載入白天的主題            int id1 = mResource.getIdentifier("day_btn_color", "color",                    "com.devilwwj.res");            dayButton.setBackgroundColor(mResource.getColor(id1));            int id2 = mResource.getIdentifier("day_background", "color",                    "com.devilwwj.res");            dayButton.setTextColor(mResource.getColor(id2));            textView.setTextColor(mResource.getColor(id2));        }    }}

我們可以儲存一個模式,比如黑夜白天模式,每次啟動按照前面儲存的模式來顯示皮膚。我們可以看到上面是通過調用getIdentifier方法來得到指定的資源的id,name是我們在資源檔中指定的名字。

最後,各位自己跑一遍這樣的流程:
1. 匯出res的apk檔案
2. 複製到目標項目的assets目錄下
3. 查看切換皮膚的效果

參考博文:http://blog.csdn.net/yuanzeyao/article/details/42390431

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.