Android插件化的思考仿QQ一键换肤思考比实现更重要.docx
- 文档编号:2889902
- 上传时间:2022-11-16
- 格式:DOCX
- 页数:15
- 大小:489.67KB
Android插件化的思考仿QQ一键换肤思考比实现更重要.docx
《Android插件化的思考仿QQ一键换肤思考比实现更重要.docx》由会员分享,可在线阅读,更多相关《Android插件化的思考仿QQ一键换肤思考比实现更重要.docx(15页珍藏版)》请在冰豆网上搜索。
Android插件化的思考仿QQ一键换肤思考比实现更重要
Android插件化的思考——仿QQ一键换肤,思考比实现更重要!
关于QQ的换肤,他们的实现思路我不是很清楚,但是你可以看一下这张换肤的截图
我们想使用哪个主题就直接下载就好了,这一实现的过程我们大致的可以猜想:
首选是下载到本地指定文件夹,然后通过插件加载到我们的apk,最后应用为皮肤,逻辑大致是这样的逻辑了,那我们是不是应该动动手啊动动脑?
首选我们新建一个工程好了——PlugInSample
一.实现思路
其实说起来,这个插件的实现思路,确实是比较的麻烦,思来想去,还是一种办法比较靠谱,首先,我们刻意去获取手机上所有的安装的/未安装的程序,过滤掉没用的,留下我们的插件apk,我们的插件apk怎么去辨别呢?
我们可用通过设置sharedUserId,然后用实体类把插件名称和包名保存下来,有了包名,就比较好说了,我们可用获取插件的上下文,也就是createPackageContext,然后就可以做点坏事了,我们可以去剖析我们的R文件
因为R文件里面都是静态的原因,我们很容易联想到反射机制,是的,我们可以再一次过滤掉无用的信息,通过我们的PathClassLoader去加载,访问我们的内加载器反射到我们的图片ID,也就是后面的那段数字,然后,嘿嘿,就可以使用了,是不是思路比较清晰了?
这里要注意的就是图片命名统一,这样就比较号过来,那具体我们应该怎么做?
二.PlugIn主程序
我们写一个Spinner,每次切换就直接换肤怎么样?
OK,每次换的时候就从插件APK里加载我们的图片资源,看起来是比较顺畅的逻辑,那我们具体该怎么做呢?
xmlversion="1.0"encoding="utf-8"?
>
android: id="@+id/mLinearLayout" xmlns: android=" android: layout_width="match_parent" android: layout_height="match_parent" android: gravity="center" android: orientation="vertical"> android: id="@+id/mSpinner" android: layout_width="wrap_content" android: layout_height="wrap_content"/>
1.初始化
/**
*初始化View
*/
privatevoidinitView(){
//初始化控件
mSpinner=(Spinner)findViewById(R.id.mSpinner);
}
当然,我这刚应用就一个View,但是实际开发当中可不止,所以步骤一定要明了
2.获取所有的插件
/**
*获取手机里的插件
*
*@return
*/
privateList
mList=newArrayList<>();
//获取相关信息
PackageManagermPackageManager=getPackageManager();
//获取卸载/未安装的安装包信息
List
//遍历拿到我们的信息
for(PackageInfoinfo:
mUninstallPackage){
StringpkgNmae=info.packageName;
//获取shareId,根据id判断是否是我们的ID
StringshareUserId=info.sharedUserId;
if(!
TextUtils.isEmpty(shareUserId)){
//如果id相同
if(shareUserId.equals("com.liuguilin.share")){
//且排除自己的包名
if(!
pkgNmae.equals(getPackageName())){
//这个就是我们的插件了
Stringlable=mPackageManager.getApplicationLabel(info.applicationInfo).toString();
PlugInBeanbean=newPlugInBean();
bean.setLabelNmae(lable);
bean.setPackagNmae(pkgNmae);
mList.add(bean);
}
}
}
}
returnmList;
}
这里就是过滤了一下,通过sharedUserId去拿到我们的插件APK了,然后就可以拿到我们的包名和应用名,他返回给我们一个数据集
//所有的插件
List
3.加载皮肤数据
/**
*加载皮肤
*
*@paramallPlugIn
*/
privatevoidLoadSkin(List
//遍历
for(PlugInBeanbean:
allPlugIn){
HashMap
mMap.put("lable",bean.getLabelNmae());
mMap.put("package",bean.getPackagNmae());
mData.add(mMap);
}
//建立Adapter并且绑定数据源
mAdapter=newSimpleAdapter(this,mData,android.R.layout.simple_list_item_1,newString[]{"lable"},newint[]{android.R.id.text1});
//设置数据
mSpinner.setAdapter(mAdapter);
//设置监听事件
mSpinner.setOnItemSelectedListener(this);
}
我们通过刚才的数据集便可以把我们拿到的数据给直接显示出来了,这里其实可以判断一下size是否为0,如果为0的话也就没有插件,OK,我们设置adapter和监听,做到这里,其实你可以运行一下,虽然我们现在什么都没有,我们要做的还有很多
4.获取插件Context
/**
*选中监听事件
*
*@paramadapterView
*@paramview
*@parami
*@paraml
*/
@Override
publicvoidonItemSelected(AdapterView
>adapterView,Viewview,inti,longl){
PlugInBeanbean=mList.get(i);
//插件的包名
StringpackageNmae=bean.getPackagNmae();
ContextmContext=null;
try{
//无视警告访问代码
mContext=createPackageContext(packageNmae,CONTEXT_IGNORE_SECURITY|CONTEXT_INCLUDE_CODE);
}catch(PackageManager.NameNotFoundExceptione){
e.printStackTrace();
}
//获取图片
getImg(packageNmae,mContext);
//通过ID加载插件的图片
getWindow().setBackgroundDrawable(mContext.getResources().getDrawable(mListId.get(i)));
}
@Override
publicvoidonNothingSelected(AdapterView
>adapterView){
}
这里的代码就比较有意思,一定要仔细看,我们首先拿到选中的item的包名,通过我们的createPackageContext拿到我们的上下文,通过这两个我们可用拿到我们的资源ID,也就是R清单里面的ID,然后直接设置window的背景,这里为了好看才设置window的背景,实际上你要设置的是你根布局的背景,那好,我们来看一下如何通过插件的上下文和包名拿到R清单的资源ID
5.获取插件图片/返回图片R文件ID/反射R文件
/**
*获取插件图片/返回图片R文件ID/反射R文件
*
*@parampackageNmae
*@parammContext
*/
privatevoidgetImg(StringpackageNmae,ContextmContext){
//类加载器反射插件
PathClassLoaderpathClass=newPathClassLoader(mContext.getPackageResourcePath(),ClassLoader.getSystemClassLoader());
//反射$访问类加载器
try{
Class
>forNmae=Class.forName(packageNmae+".R$drawable",true,pathClass);
//拿到所有图片的id
Field[]files=forNmae.getDeclaredFields();
for(Fieldid:
files){
//过滤/这里的命名可以注意一下
if(id.getName().startsWith("img")){
intdrawId=0;
////这就是我们图片R下的ID
drawId=id.getInt(R.drawable.class);
mListId.add(drawId);
}
}
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}catch(IllegalAccessExceptione){
e.printStackTrace();
}
}
这里我们做了很多事情,首选是拿到我们的类加载器去反射我们的插件,然后通过Class去拿我们的资源,这里注意packageNmae是我们的文件目录,他下面的R文件,$代表类部类的意思,他下面的drawable子节点,然后再一次过滤,过滤之后我们可用遍历一遍拿到我们的ID用List保存起来,也就有了我们选中的时候的设置,好的,到这里主程序算是编写完成了,不过要注意的是,记住要添加sharedUserId啊,至关重要!
!
!
android:
sharedUs
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 插件 思考 QQ 一键换肤 实现 重要