在android的项目开发中,都会遇到后期功能拓展增强与主程序代码变更的现实矛盾,也就是程序的灵活度。 由于linux平台的安全机制,再加上dalvik的特殊机制,各种权限壁垒,使得开发一个灵活多变的程序,变得比较困难,不像pc平台下那么容易。

这里实际上可以借鉴传统软件中扩展程序的方法: 也就是插件的实现. 如目前所有的浏览器,比如我们使用的eclipse,以及很多优秀的软件,都使用了此种方式. 这样轻松实现了软件的功能扩展,而升级功能时只用更新对应插件, 而不是需要更新整个应用,降低了程序的耦合度.

而在Android中的实现思路,即为将一个较大的APK,分离为一个主程序的APK,和其他各种较小的APK.

典型的应用为手机QQ换肤的实现方式:

QQ的皮肤是一个无界面APK应用,这个皮肤应用中的资源和主程序的资源命名一致,通过主程序和皮肤程序共享进程实现主程序对皮肤程序中资源的访问,在程序运行时通过代码显示指定皮肤资源,缺点是在主程序中每个activity要增加复杂的使用哪种皮肤逻辑

本例实现效果如下:

下面分析下具体思路:

android下,默认的情况是,每个apk相互独立的,基本上每个应用都是一个dalvik虚拟机,都有一个uid,再配合上linux本身的权限机制,使得apk互通很难直接进行。但作为一个独立应用的集成,不管多少个apk,都可以并为一个单独的dalvik虚拟机,直观的反映给开发人员就是在shell下列出进程,那几个apk同时加载后,会一个进程存在。

可以在清单文件中加入如下配置:

     android:sharedUserId="com.tony.test"

android:sharedUserId是指共用一个uid,也就是,凡是这个属性相同的工程,都会共用同一个uid,这样,权限壁垒就消除了,dalvik也会融合为一个,可以测试一下,写几个工程,没有这个属性和有这个属性的情况下,同时运行,在列出当前进程,就直观的说明了。

下面还是用代码说明,一共分为两部分. 主程序 Re_Skin和皮肤程序Re_Skin1

首先是主应用程序代码:

1. 清单文件AndroidManifest.xml:

[java] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.tony.reskin"
  4. android:versionCode="1"
  5. android:versionName="1.0"<spanstyle="color:#FF0000;">android:sharedUserId="com.tony.skin"</span>>
  6. <uses-sdkandroid:minSdkVersion="7"/>
  7. <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
  8. <activityandroid:name="com.tony.reskin.Re_SkinActivity"
  9. android:label="@string/app_name">
  10. <intent-filter>
  11. <actionandroid:name="android.intent.action.MAIN"/>
  12. <categoryandroid:name="android.intent.category.LAUNCHER"/>
  13. </intent-filter>
  14. </activity>
  15. </application>
  16. </manifest>


2. 布局文件:

[java] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. android:id="@+id/layout">
  7. <TextView
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"
  10. android:text="@string/hello"
  11. />
  12. <Buttonandroid:text="Set"android:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button>
  13. </LinearLayout>


3. Re_SkinActivity;(主要的皮肤更换逻辑实现类)

[java] view plain copy
  1. packagecom.tony.reskin;
  2. importandroid.app.Activity;
  3. importandroid.content.Context;
  4. importandroid.content.pm.PackageManager.NameNotFoundException;
  5. importandroid.os.Bundle;
  6. importandroid.os.Handler;
  7. importandroid.view.View;
  8. importandroid.view.View.OnClickListener;
  9. importandroid.widget.Button;
  10. importandroid.widget.LinearLayout;
  11. publicclassRe_SkinActivityextendsActivity{
  12. privateLinearLayoutlayout;
  13. privateButtonbtnSet;
  14. <spanstyle="color:#FF0000;">privateContextfriendContext;</span>
  15. /**Calledwhentheactivityisfirstcreated.*/
  16. @Override
  17. publicvoidonCreate(BundlesavedInstanceState){
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.main);
  20. btnSet=(Button)findViewById(R.id.button1);
  21. layout=(LinearLayout)findViewById(R.id.layout);
  22. layout.setBackgroundResource(R.drawable.bg);
  23. try{
  24. <spanstyle="color:#FF0000;">friendContext=createPackageContext("com.tony.reskin1",Context.CONTEXT_IGNORE_SECURITY);</span>
  25. }catch(NameNotFoundExceptione){
  26. e.printStackTrace();
  27. }
  28. btnSet.setOnClickListener(newOnClickListener(){
  29. @Override
  30. publicvoidonClick(Viewv){
  31. newHandler().post(newRunnable(){
  32. @Override
  33. publicvoidrun(){
  34. layout.setBackgroundDrawable(<spanstyle="color:#FF0000;">friendContext.getResources().getDrawable(R.drawable.bg</span>));
  35. }
  36. });
  37. }
  38. });
  39. }
  40. }


皮肤应用中不需要界面显示

这个皮肤应用中的资源和主程序的资源命名一致即可.

清单文件:

[java] view plain copy
    1. <?xmlversion="1.0"encoding="utf-8"?>
    2. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
    3. package="com.tony.reskin1"
    4. android:versionCode="1"
    5. android:versionName="1.0"<spanstyle="color:#FF0000;">android:sharedUserId="com.tony.skin"</span>>
    6. <uses-sdkandroid:minSdkVersion="7"/>
    7. <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
    8. <activityandroid:name=".Re_Skin1Activity"
    9. android:label="@string/app_name">
    10. <intent-filter>
    11. <actionandroid:name="android.intent.action.MAIN"/>
    12. <categoryandroid:name="android.intent.category.LAUNCHER"/>
    13. </intent-filter>
    14. </activity>
    15. </application>
    16. </manifest>

更多相关文章

  1. Android一次性退出多个Activity的方法
  2. Android是怎么给你自己的程序选择语言的
  3. 应用程序签名
  4. Android(安卓)性能优化典范(六)
  5. Android(安卓)怎么退出整个应用程序?
  6. android 为一个apk设置多个ICON图标和执行入口
  7. My Magic Android(安卓)Tour —— 处女作
  8. Android(安卓)Developers:向其它应用发送用户
  9. Android(安卓)上,用普通的 am-linux-gcc 编译 C 程序。

随机推荐

  1. sql 查询慢的原因分析
  2. 模糊查询的通用存储过程
  3. SQL Server 中查看SQL句子执行所用的时间
  4. MySql 安装时的1045错误
  5. 数据库Left join , Right Join, Inner Jo
  6. SQL Server 排序函数 ROW_NUMBER和RANK
  7. sql server 常用的几个数据类型
  8. SQLServer EVENTDATA()函数来获取DDL 触
  9. SQLServer Top语句参数化方法
  10. SQL server 随机数函数