Android插件化的思考——仿QQ一键换肤,思考比实现更重要_第1页
Android插件化的思考——仿QQ一键换肤,思考比实现更重要_第2页
Android插件化的思考——仿QQ一键换肤,思考比实现更重要_第3页
Android插件化的思考——仿QQ一键换肤,思考比实现更重要_第4页
Android插件化的思考——仿QQ一键换肤,思考比实现更重要_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Android插件化的思考仿QQ一键换肤,思考比实现更重要!关于QQ的换肤,他们的实现思路我不是很清楚,但是你可以看一下这张换肤的截图我们想使用哪个主题就直接下载就好了,这一实现的过程我们大致的可以猜想:首选是下载到本地指定文件夹,然后通过插件加载到我们的apk,最后应用为皮肤,逻辑大致是这样的逻辑了,那我们是不是应该动动手啊动动脑?首选我们新建一个工程好了PlugInSample一.实现思路其实说起来,这个插件的实现思路,确实是比较的麻烦,思来想去,还是一种办法比较靠谱,首先,我们刻意去获取手机上所有的安装的/未安装的程序,过滤掉没用的,留下我们的插件apk,我们的插件apk怎么去辨别呢?我

2、们可用通过设置sharedUserId,然后用实体类把插件名称和包名保存下来,有了包名,就比较好说了,我们可用获取插件的上下文,也就是createPackageContext,然后就可以做点坏事了,我们可以去剖析我们的R文件因为R文件里面都是静态的原因,我们很容易联想到反射机制,是的,我们可以再一次过滤掉无用的信息,通过我们的PathClassLoader去加载,访问我们的内加载器反射到我们的图片ID,也就是后面的那段数字,然后,嘿嘿,就可以使用了,是不是思路比较清晰了?这里要注意的就是图片命名统一,这样就比较号过来,那具体我们应该怎么做?二.PlugIn主程序我们写一个Spinner,每次切

3、换就直接换肤怎么样?OK,每次换的时候就从插件APK里加载我们的图片资源,看起来是比较顺畅的逻辑,那我们具体该怎么做呢? 1.初始化 /* * 初始化View */ private void initView() /初始化控件 mSpinner = (Spinner) findViewById(R.id.mSpinner); 当然,我这刚应用就一个View,但是实际开发当中可不止,所以步骤一定要明了2.获取所有的插件 /* * 获取手机里的插件 * * return */ private List findPlugIn() mList = new ArrayList(); /获取相关信息 Pa

4、ckageManager mPackageManager = getPackageManager(); /获取卸载/未安装的安装包信息 List mUninstallPackage = mPackageManager.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES); /遍历拿到我们的信息 for (PackageInfo info : mUninstallPackage) String pkgNmae = info.packageName; /获取shareId,根据id判断是否是我们的ID String shareU

5、serId = info.sharedUserId; if (!TextUtils.isEmpty(shareUserId) /如果id相同 if (shareUserId.equals(com.liuguilin.share) /且排除自己的包名 if (!pkgNmae.equals(getPackageName() /这个就是我们的插件了 String lable = mPackageManager.getApplicationLabel(info.applicationInfo).toString(); PlugInBean bean = new PlugInBean(); bean.

6、setLabelNmae(lable); bean.setPackagNmae(pkgNmae); mList.add(bean); return mList; 这里就是过滤了一下,通过sharedUserId去拿到我们的插件APK了,然后就可以拿到我们的包名和应用名,他返回给我们一个数据集/所有的插件 List allPlugIn = findPlugIn();3.加载皮肤数据 /* * 加载皮肤 * * param allPlugIn */ private void LoadSkin(List allPlugIn) /遍历 for (PlugInBean bean : allPlugIn)

7、 HashMap mMap = new HashMap(); mMap.put(lable, bean.getLabelNmae(); mMap.put(package, bean.getPackagNmae(); mData.add(mMap); /建立Adapter并且绑定数据源 mAdapter = new SimpleAdapter(this, mData, android.R.layout.simple_list_item_1, new Stringlable, new intandroid.R.id.text1); /设置数据 mSpinner.setAdapter(mAdapte

8、r); /设置监听事件 mSpinner.setOnItemSelectedListener(this); 我们通过刚才的数据集便可以把我们拿到的数据给直接显示出来了,这里其实可以判断一下size是否为0,如果为0的话也就没有插件,OK,我们设置adapter和监听,做到这里,其实你可以运行一下,虽然我们现在什么都没有,我们要做的还有很多4.获取插件Context /* * 选中监听事件 * * param adapterView * param view * param i * param l */ Override public void onItemSelected(AdapterVie

9、w adapterView, View view, int i, long l) PlugInBean bean = mList.get(i); /插件的包名 String packageNmae = bean.getPackagNmae(); Context mContext = null; try /无视警告 访问代码 mContext = createPackageContext(packageNmae, CONTEXT_IGNORE_SECURITY | CONTEXT_INCLUDE_CODE); catch (PackageManager.NameNotFoundException

10、 e) e.printStackTrace(); /获取图片 getImg(packageNmae, mContext); /通过ID加载插件的图片 getWindow().setBackgroundDrawable(mContext.getResources().getDrawable(mListId.get(i); Override public void onNothingSelected(AdapterView adapterView) 这里的代码就比较有意思,一定要仔细看,我们首先拿到选中的item的包名,通过我们的createPackageContext拿到我们的上下文,通过这两个

11、我们可用拿到我们的资源ID,也就是R清单里面的ID,然后直接设置window的背景,这里为了好看才设置window的背景,实际上你要设置的是你根布局的背景,那好,我们来看一下如何通过插件的上下文和包名拿到R清单的资源ID5.获取插件图片 / 返回图片R文件ID / 反射R文件 /* * 获取插件图片 / 返回图片R文件ID / 反射R文件 * * param packageNmae * param mContext */ private void getImg(String packageNmae, Context mContext) /类加载器反射插件 PathClassLoader pat

12、hClass = new PathClassLoader(mContext.getPackageResourcePath(), ClassLoader.getSystemClassLoader(); /反射 $ 访问类加载器 try Class forNmae = Class.forName(packageNmae + .R$drawable, true, pathClass); /拿到所有图片的id Field files = forNmae.getDeclaredFields(); for (Field id : files) /过滤 / 这里的命名可以注意一下 if (id.getNam

13、e().startsWith(img) int drawId = 0; /这就是我们图片R下的ID drawId = id.getInt(R.drawable.class); mListId.add(drawId); catch (ClassNotFoundException e) e.printStackTrace(); catch (IllegalAccessException e) e.printStackTrace(); 这里我们做了很多事情,首选是拿到我们的类加载器去反射我们的插件,然后通过Class去拿我们的资源,这里注意packageNmae是我们的文件目录,他下面的R文件,$代

14、表类部类的意思,他下面的drawable子节点,然后再一次过滤,过滤之后我们可用遍历一遍拿到我们的ID用List保存起来,也就有了我们选中的时候的设置,好的,到这里主程序算是编写完成了,不过要注意的是,记住要添加sharedUserId啊,至关重要!android:sharedUserId=com.liuguilin.share11我们现在运行也是空的,无意义,我们直接来写我们的插件吧!三PlugInApk插件插件的编写很简单,我们新建一个PlugInApk的工程工程里要做的事情就三件1.添加sharedUserIdandroid:sharedUserId=com.liuguilin.shar

15、e2.更改name这就取决于你了,比如我这里是Angelababy的主题,我就把名字改成Angelababy3.把图片放在drawable文件夹下好的,做完这三部,我们本能的把插件运行一下,运行之后,我们再次启动主程序,你会看到.其实我们主程序里啥也没有,对吧,但是的却加载进来了,这就说明我们的插件化算是圆满实现了,那我们多来点主题看看最终的效果是什么样子的?通过这个思路确实可以加载到图片,但是这个逻辑依旧有些不完美,不过最重要的,思考比实现更重要,对吧,后续的也就是一步步的优化了,希望大家和我一起探讨一下!当上完整的代码MainActivitypackage com.liuguilin.pl

16、uginsample;import android.content.Context;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.text.TextUtils;import android.view.View;import android.widget.AdapterView;import android.wi

17、dget.SimpleAdapter;import android.widget.Spinner;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import dalvik.system.PathClassLoader;public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelecte

18、dListener /下拉 private Spinner mSpinner; /数据源 private SimpleAdapter mAdapter; /插件数据 private List mList; /加载的皮肤数据 private ListMap mData = new ArrayList(); /资源id private int drawId = 0; Override protected void onCreate(Bundle savedInstanceState) super.onCreate(InstanceState); setContentView(R.layout.ac

19、tivity_main); initView(); /所有的插件 List allPlugIn = findPlugIn(); /加载皮肤数据 LoadSkin(allPlugIn); /* * 加载皮肤 * * param allPlugIn */ private void LoadSkin(List allPlugIn) /遍历 for (PlugInBean bean : allPlugIn) HashMap mMap = new HashMap(); mMap.put(lable, bean.getLabelNmae(); mMap.put(package, bean.getPacka

20、gNmae(); mData.add(mMap); /建立Adapter并且绑定数据源 mAdapter = new SimpleAdapter(this, mData, android.R.layout.simple_list_item_1, new Stringlable, new intandroid.R.id.text1); /设置数据 mSpinner.setAdapter(mAdapter); /设置监听事件 mSpinner.setOnItemSelectedListener(this); /* * 获取手机里的插件 * * return */ private List find

21、PlugIn() mList = new ArrayList(); /获取相关信息 PackageManager mPackageManager = getPackageManager(); /获取卸载/未安装的安装包信息 List mUninstallPackage = mPackageManager.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES); /遍历拿到我们的信息 for (PackageInfo info : mUninstallPackage) String pkgNmae = info.packageN

22、ame; /获取shareId,根据id判断是否是我们的ID String shareUserId = info.sharedUserId; if (!TextUtils.isEmpty(shareUserId) /如果id相同 if (shareUserId.equals(com.liuguilin.share) /且排除自己的包名 if (!pkgNmae.equals(getPackageName() /这个就是我们的插件了 String lable = mPackageManager.getApplicationLabel(info.applicationInfo).toString(

23、); PlugInBean bean = new PlugInBean(); bean.setLabelNmae(lable); bean.setPackagNmae(pkgNmae); mList.add(bean); return mList; /* * 初始化View */ private void initView() /初始化控件 mSpinner = (Spinner) findViewById(R.id.mSpinner); /* * 选中监听事件 * * param adapterView * param view * param i * param l */ Override

24、 public void onItemSelected(AdapterView adapterView, View view, int i, long l) PlugInBean bean = mList.get(i); /插件的包名 String packageNmae = bean.getPackagNmae(); Context mContext = null; try /无视警告 访问代码 mContext = createPackageContext(packageNmae, CONTEXT_IGNORE_SECURITY | CONTEXT_INCLUDE_CODE); catch

25、 (PackageManager.NameNotFoundException e) e.printStackTrace(); /获取图片 getImg(packageNmae, mContext); /通过ID加载插件的图片 getWindow().setBackgroundDrawable(mContext.getResources().getDrawable(drawId); /findViewById(R.id.mLinearLayout).setBackgroundDrawable(mContext.getResources().getDrawable(drawId); Overrid

26、e public void onNothingSelected(AdapterView adapterView) /* * 获取插件图片 / 返回图片R文件ID / 反射R文件 * * param packageNmae * param mContext */ private void getImg(String packageNmae, Context mContext) /类加载器反射插件 PathClassLoader pathClass = new PathClassLoader(mContext.getPackageResourcePath(), ClassLoader.getSystemClassLoader(); /反射 $ 访问类加载器 try Class forNmae = C

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论