之前没有听过app插件式开发今天就做一下学习的笔记。这里的插件式开发通俗的讲就是把一个很大的app分成n多个比较小的app,其中有一个app是主app。网上查了一下采用了这种开发模式的有支付宝客户端、QQ换肤其他的就不得而知了有人说微信也是基于插件的但是微信在更新的时候会下载全部的应用程序把旧的完全覆盖所以猜想应该目前不是吧。
基于插件的开发列举两个比较突出的优点:
1、应用程序非常容易扩招,比如有一个新的领域要加到旧的应用程序中来只需把这个新的领域做为一个插件,只开发这个小的app就可以了旧的应用程序可能会原分不动,就连编译打包都不需要。
2、下载更新特别省流量,假如一个应用程序有10M把它分成两个的话可能每次更新只需要花费5M或者更少的流量就可以更新完。对于我每月只有30M的流量去更新一个10M大的应用却是有些心疼,只要用户不能及时更新我们的应用那么应用中赚钱的项目就不能及时传达到客户的手中,客户是上帝啊我们赚客户钱的同事还要想着为客户节省哈哈哈。
有优点的东西也是有缺点的这是必然,就和人无完人一样,记得有个软件工程的老师给我们说过“追求完美本来就是一种性格缺陷”话的意思是说在做软件方面没有近乎完美。基于插件开发当然不是插件越多越好能掌控好内聚和耦合度就更好了。插件增加了主应用程序中的逻辑难过。
这次学习需要了解以下概念:
1、 进程:
当时学习操作系统的时候就书上是这么解释的,进程就是程序的一次执行过程,进程是操作系统分配资源的基本单位。当然进程还有很多属性这里就不多说了。在android中当某一个组件第一次运行的时候android就启动了一个进程,默认时所有的组件运行在这一个进程中,当然也可以自己指定运行在哪一个进程中。组件运行的进程由manifest file控制。组件的节点 、、 和 都包含一个 process 属性。这个属性可以设置组件运行的进程:可以配置组件在一个独立进程运行,或者多个组件在同一个进程运行。甚至可以多个程序在一个进程中运行,如果这些程序共享一个User ID并给定同样的权限。节点也包含 process 属性,用来设置程序中所有组件的默认进程。
所有的组件在此进程的主线程中实例化,系统对这些组件的调用从主线程中分离。并非每个对象都会从主线程中分离。一般来说,响应例如View.onKeyDown()用户操作的方法和通知的方法也在主线程中运行。这就表示,组件被系统调用的时候不应该长时间运行或者阻塞操作(如网络操作或者计算大量数据),因为这样会阻塞进程中的其他组件。可以把这类操作从主线程中分离。
当更加常用的进程无法获取足够内存,Android可能会关闭不常用的进程。下次启动程序的时候会重新启动进程。
当决定哪个进程需要被关闭的时候, Android会考虑哪个对用户更加有用。如Android会倾向于关闭一个长期不显示在界面的进程来支持一个经常显示在界面的进程。是否关闭一个进程决定于组件在进程中的状态。
2、 线程
当时学习的时候书上是这么说的线程是进程的基本单元,一个进程可以有多个线程,每个进程至少有一个主线程。在android中即使为组件分配了不同的进程,有时候也需要再分配线程。比如用户界面需要很快对用户进行响应,因此某些费时的操作,如网络连接、下载或者非常占用服务器时间的操作应该放到其他线程。
3、 进程间通信
我们知道,Android系统是基于Linux内核的,在Linux中进程间通信有好多种(管道、信号、消息队列、共享内存、信号量、套接字)。很不幸啊Android系统没有采用上述提到的各种进程间通信机制。关于进程间通信可以看看http://blog.csdn.net/luoshengyang/article/details/6618363博客。
以上说了一大堆就想说明插件app和主程序要解决通信的问题,这个看起来很难但是很幸运android可以把好几个app合并到同一个dalvik虚拟机中这样实质上是将很多个app放在同一个进程中运行了(每一个android应用程序都在自己的进程中运行,都拥有一个dalivk虚拟机实例。而每一个dalivk都是在linux的一个进程。所以说android dalivk和linux 进程可以认为是同一个概念)。直观的反应给我们程序开发人员就更简单了只需要将所有的app manifest的android:sharedUserId="com.liu.plugintest"配置成一致就可以了。
主程序manifest.xml:
1
2
3
4
5
6
7
8
9
10
11
12
|
<!--?xml version=
"1.0"
encoding=
"utf-8"
?-->
<manifest android:shareduserid=
"com.liu.plugintest"
android:versioncode=
"1"
android:versionname=
"1.0"
package
=
"com.liu.zhen"
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<uses-sdk android:minsdkversion=
"14"
android:targetsdkversion=
"19"
>
<intent-filter>
<category android:name=
"android.intent.category.LAUNCHER"
>
</category></action></intent-filter>
</activity>
</application>
</uses-sdk></manifest>
|
插件manifest.xml:
1
2
3
4
5
6
7
8
9
10
11
12
|
<!--?xml version=
"1.0"
encoding=
"utf-8"
?-->
<manifest android:shareduserid=
"com.liu.plugintest"
android:versioncode=
"1"
android:versionname=
"1.0"
package
=
"com.liu.zhen.plugin1"
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<uses-sdk android:minsdkversion=
"14"
android:targetsdkversion=
"19"
>
<intent-filter>
<category android:name=
"android.intent.category.DEFAULT"
>
</category></action></intent-filter>
</activity>
</application>
</uses-sdk></manifest>
|
可以看出来插件app是没有启动的activity的。
主程序定义插件的实体:
1
2
3
4
|
public
class
PluginBean {
public
String pakageName;
public
String label;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/**
* 查找插件
* @return
*/
private
List<pluginbean> findPlugins(){
List<pluginbean> plugins=
new
ArrayList<pluginbean>();
//遍历包名,来获取插件
PackageManager pm=getPackageManager();
List<packageinfo> pkgs=pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
for
(PackageInfo pkg :pkgs){
//包名
String packageName=pkg.packageName;
String sharedUserId= pkg.sharedUserId;
//sharedUserId是开发时约定好的,这样判断是否为自己人
if
(!
"com.liu.plugintest"
.equals(sharedUserId)||
"com.liu.zhen"
.equals(packageName))
continue
;
//进程名
String prcessName=pkg.applicationInfo.processName;
//label,也就是appName了
String label=pm.getApplicationLabel(pkg.applicationInfo).toString();
PluginBean plug=
new
PluginBean();
plug.label=label;
plug.pakageName = packageName;
plugins.add(plug);
}
return
plugins;
}
</packageinfo></pluginbean></pluginbean></pluginbean>
|
主程序添加插件导航到主程序的activity中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/**
* 加载插件列表
* @param plugins
*/
private
void
attachPlugin(
final
List<pluginbean> plugins){
Log.e(
"liu"
,
"----- 列出插件"
);
this
.plugins=plugins;
for
(
final
PluginBean plugin:plugins){
System.out.println(plugin.pakageName);
Button btn=
new
Button(
this
);
btn.setTextColor(Color.RED);
btn.setText(plugin.label);
llMainLayout.addView(btn);
//添加事件
btn.setOnClickListener(
new
OnClickListener() {
@Override
public
void
onClick(View v) {
Intent it=
new
Intent();
it.setAction(plugin.pakageName);
startActivity(it);
}
});
}
}
</pluginbean>
|
这里新建了三个android项目,其中一个作为主程序,其它两个为插件程序。