android应用Theme(二)
另外一种实现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(); } } } }