摘要:本文将带你了解Android应用开发Android 多进程开发教程,希望本文对大家学Android有所帮助。
本文将带你了解Android应用开发Android 多进程开发教程,希望本文对大家学Android有所帮助。
前言
正常情况下,一个apk启动后只会运行在一个进程中,其进程名为AndroidManifest.xml文件中指定的应用包名,所有的基本组件都会在这个进程中运行。但是如果需要将某些组件(如Service、Activity等)运行在单独的进程中,就需要用到android:process属性了。我们可以为android的基础组件指定process属性来指定它们运行在指定进程中。android使用多进程重构项目架构,可以分担主进程压力以免因资源消耗过大被crash掉,另外多进程相互监听唤醒,可以使应用程序长期驻守后台接受即时消息和通知,防止应用被系统回收。下面就总结一下多进程开发的经验及优化。
一、多进程概念
一般情况下,一个应用程序就是一个进程,这个进程名称就是应用程序包名。我们知道进程是系统分配资源和调度的基本单位,所以每个进程都有自己独立的资源和内存空间,别的进程是不能任意访问其他进程的内存和资源的。
二、多进程机制
四大组件在AndroidManifest文件中注册的时候,有个属性android:process这里可以指定组件的所处的进程。
对process属性的设置有两种形式:
第一种形式:如android:process=:remote,以冒号开头,冒号后面的字符串原则上是可以随意指定的。如果我们的包名为“com.example.processtest”,则实际的进程名为“com.example.processtest:remote”。这种设置形式表示该进程为当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中。
第二种形式:如android:process=com.example.processtest.remote,以小写字母开头,表示运行在一个以这个名字命名的全局进程中,其他应用通过设置相同的ShareUID可以和它跑在同一个进程。
下面通过一个例子来进行一下验证。我们定义两个类:ProcessTestActivity和ProcessTestService,然后在AndroidManifest.xml文件中增加这两个类,并为我们的Service指定一个process属性,代码如下:
运行代码,通过DDMS进行观察
\
我们可以看到两个进程,名字分别是“com.example.processtest”和“com.example.processtest:remote”,进程ID分别为2722和2739。
ProcessTestService运行在一个单独的私有进程中,如果想让ProcessTestService运行在一个全局进程中,那么只需修改android:process=com.example.processtest.remote即可。Android为每一个应用程序分配了一个独立的虚拟机,或者说为每个进程都分配了一个独立的虚拟机,不同的虚拟机在内存分配上 有不同的地址空间,这就会导致在不同的虚拟机中访问同一类的对象会产生多份副本。在一个进程中修改某个值只会影响当前进程,对其他进程不会造成任何影响。
三、多进程优点
一般来说,Android应用多进程有三个好处:
1)我们知道Android系统对每个应用进程的内存占用是有限制的,而且占用内存越大的进程,通常被系统杀死的可能性越大。让一个组件运行在单独的进程中,可以减少主进程所占用的内存,降低被系统杀死的概率.
2)如果子进程因为某种原因崩溃了,不会直接导致主程序的崩溃,可以降低我们程序的崩溃率。
3)即使主进程退出了,我们的子进程仍然可以继续工作,假设子进程是推送服务,在主进程退出的情况下,仍然能够保证用户可以收到推送消息。
四、多进程缺点
我们已经开启了应用内多进程,那么,开启多进程是不是只是我们看到的这么简单呢?其实这里面会有一些陷阱,稍微不注意就会陷入其中。我们首先要明确的一点是进程间的内存空间时不可见的。
从而,开启多进程后,我们需要面临这样几个问题:
1)Application的多次重建。运行在同一个进程中的组件是属于同一个虚拟机和同一个Application的,运行在不同进程中的组件是属于两个不同的虚拟机和Application的。
2)静态成员和单例模式完全失效。
3)文件共享问题。比如SharedPreferences 的可靠性下降。
4)断点调试问题。
1、Application的多次重建
我们先通过一个简单的例子来看一下第一种情况。
Manifest文件如上面提到的,定义了两个类:ProcessTestActivity和ProcessTestService,我们只是在Activity的onCreate方法中直接启动了该Service,同时,我们自定义了自己的Application类。代码如下:
public class MyApplication extends Application {
public static final String TAG = viclee;
@Override
public void onCreate() {
super.onCreate();
int pid = android.os.Process.myPid();
Log.d(TAG, MyApplication onCreate);
Log.d(TAG, MyApplication pid is + pid);
}
}
public class ProcessTestActivity extends Activity {
public final static String TAG = viclee;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_process_test);
Log.i(TAG, ProcessTestActivity onCreate);
this.startService(new Intent(this, ProcessTestService.class));
}
}
public class ProcessTestService extends Service {
public static final String TAG = viclee;
@Override
public void onCreate() {
Log.i(TAG, ProcessTestService onCreate);
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
执行上面这段代码,查看打印信息:
\
我们发现MyApplication的onCreate方法调用了两次,分别是在启动ProcessTestActivity和ProcessTestService的时候,而且我们发现打印出来的pid也不相同。由于通常会在Application的onCreate方法中做一些全局的初始化操作,它被初始化多次是完全没有必要的。出现这种情况,是由于即使是通过指定process属性启动新进程的情况下,系统也会新建一个独立的虚拟机,自然需要重新初始化一遍Application。那么怎么来解决这个问题呢?
我们可以通过在自定义的Application中通过进程名来区分当前是哪个进程,然后单独进行相应的逻辑处理。
public class MyApplication extends Application {
public static final String TAG = viclee;
@Override
public void onCreate() {
super.onCreate();
int pid = android.os.Process.myPid();
Log.d(TAG, MyApplication onCreate);
Log.d(TAG, MyApplication pid is + pid);
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List runningApps = am.getRunningAppProcesses();
if (runningApps != null && !runningApps.isEmpty()) {
for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {
if (procInfo.pid == pid) {
if (procInfo.processName.equals(com.example.processtest)) {
Log.d(TAG, process name is + procInfo.processName);
} else if (procInfo.processName.equals(com.example.processtest:remote)) {
Log.d(TAG, process name is + procInfo.processName);
}
}
}
}
}
}
运行之后,查看Log信息:
\
图中可以看出,不同的进程执行了不同的代码逻辑,可以通过这种方式来区分不同的进程需要完成的初始化工作。
2、静态变量和单例模式完全失效
下面我们来看第二个问题,将之前定义的Activity和Service的代码进行简单的修改,代码如下:
public class ProcessTestActivity extends Activity {
public final static String TAG = viclee;
public static boolean processFlag = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_process_test);
processFlag = true;
Log.i(TAG, ProcessTestActivity onCreate);
this.startService(new Intent(this, ProcessTestService.class));
}
}
public class ProcessTestService extends Service {
public static final String TAG = viclee;
@Override
body{ }
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号