转:Android更换皮肤-APK方式

第二种实现android应用Theme的方式是通过apk来实现的。下面是一个demo。

1.首先必须新建一个apk,类似的插件,然后在该apk的AndroidManifest.xml文件的application加上一个meta-data。这个是下一步查找是否是自己的插件的apk做一个标记。

<meta-data android:name="skin_demo2_plugin" android:value="com.example.skindemo2.icon"/>

 2.在该apk添加一些图片,也可以用其他(包括style等)这里主要是为了演示。在该apk的MainActivity定义一个方法。这里主要为了方便主apk快速调用这个方法。

static int allDrawableId[] = {R.drawable.img_apparel_accessories,R.drawable.img_computers_software  
        ,R.drawable.img_electro,R.drawable.img_electronics,R.drawable.img_entertaiment  
        ,R.drawable.img_food_beverage,R.drawable.img_kids_baby,R.drawable.img_sport,R.drawable.img_toys_games};  
      
    public int getDrawableIdForOtherApp(int position){  
          
        if(position < allDrawableId.length){  
            return allDrawableId[position];  
        }  
        return 0;     
    }

3.在主apk中通过读取所有安装的应用,通过分析applicationInfo的meta-data,然后判断是否是自己的插件apk。

然后通过context.createPackageContext(packageName,int flag)得到相应插件的context。然后通过类加载器得到MainActivity的class类,然后通过反射得到方法返回的值。然后就可以得到drawable对象。

package com.example.skindemo2;  
import java.lang.reflect.Method;  
import java.util.ArrayList;  
import java.util.List;  
import android.os.AsyncTask;  
import android.os.Bundle;  
import android.app.Activity;  
import android.content.Context;  
import android.content.pm.ApplicationInfo;  
import android.content.pm.PackageInfo;  
import android.content.pm.PackageManager;  
import android.content.pm.PackageManager.NameNotFoundException;  
import android.graphics.drawable.Drawable;  
import android.view.View;  
import android.widget.Button;  
import android.widget.ImageView;  
  
public class MainActivity extends Activity {  
  
    private Button mSwtichImgBgBtn;  
    private ImageView mShowImg;  
    private Context context;  
    private ArrayList<String> mPluginPackageNameList = new ArrayList<String>();  
    private int position = 0;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        context = this;  
        mSwtichImgBgBtn = (Button) this.findViewById(R.id.swtichImgBgBtn);  
        mSwtichImgBgBtn.setOnClickListener(new View.OnClickListener() {  
              
            @Override  
            public void onClick(View v) {  
                swtichImgUsePlugin();  
            }  
        });  
        mShowImg = (ImageView) this.findViewById(R.id.myShowImg);  
        new AsyncTask<Void, Void, Void>() {  
  
            @Override  
            protected Void doInBackground(Void... params) {  
                findPluginPackageName();  
                return null;  
            }  
              
            @Override  
            protected void onPostExecute(Void result) {  
                swtichImgUsePlugin();  
                super.onPostExecute(result);  
            }  
        }.execute();  
  
    }  
  
    private void findPluginPackageName() {  
        PackageManager pm = context.getPackageManager();  
        List<PackageInfo> list = pm.getInstalledPackages(0);//得到所有安装的apk的PackageInfo   
        String meta = null;  
        ApplicationInfo aInfo = null;  
        for (PackageInfo pi : list) {  
            String pkgName = pi.packageName;  
            try {  
                aInfo = pm.getApplicationInfo(pkgName,  
                        PackageManager.GET_META_DATA);  
            } catch (NameNotFoundException e) {  
                e.printStackTrace();  
            }  
            if (aInfo == null || aInfo.metaData == null)  
                continue;  
            meta = aInfo.metaData.getString("skin_demo2_plugin");  
            if (meta == null || "".equals(meta))  
                continue;  
            if ("com.example.skindemo2.icon".equals(meta)) {  
                //通过meta的值判断是否是自己的插件apk   
                mPluginPackageNameList.add(aInfo.packageName);  
            }  
        }  
    }  
    //必须在主线程中操作   
    private void swtichImgUsePlugin() {  
        //我这里为了方便直接就取了第一个插件apk数据,实际中是通过用户选择的apk来切换   
        if (mPluginPackageNameList.size() != 0) {  
            try {  
                //通过createPackageContext方法得到插件apk的context   
                Context otherplusContext = context.createPackageContext(  
                        mPluginPackageNameList.get(0),  
                        Context.CONTEXT_INCLUDE_CODE  
                                | Context.CONTEXT_IGNORE_SECURITY);  
                //通过得到插件apk的context类加载器,然后得到MainActvity的类对象   
                Class<?> mainClass = otherplusContext  
                        .getClassLoader()  
                        .loadClass(mPluginPackageNameList.get(0) + ".MainActivity");  
                //通过反射得到相应位置的drawable   
                Method m = mainClass.getMethod("getDrawableIdForOtherApp",  
                        int.class);  
                int imgBgId = (Integer) m.invoke(mainClass.newInstance(), position);  
                //为了可以循环切换img   
                 if(imgBgId == 0){  
                     position = 0;  
                 }else{  
                     position += 1;  
                 }  
                 //得到drawable对象   
                Drawable drawable = otherplusContext.getResources()  
                        .getDrawable(imgBgId);  
                mShowImg.setImageDrawable(drawable);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
  
    }  
}

转:Android更换皮肤-APK方式

相关推荐