概述
应用启动过程:
ActivityThread
ActivityThread就是主线程或UI线程,ActivityThread的main方法是整个APP的入口。
public final class ActivityThread {
//...
final H mH = new H();
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
final ApplicationThread mAppThread = new ApplicationThread();
private class ApplicationThread extends ApplicationThreadNative {
//...
}
private class H extends Handler {
//...
}
//...
}
Activity信息全部被存储在ActivityThread的成员变量mActivities中。mServices则保存了所有service的信息。
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
ActivityThread有三个重要的类,Instrumentation、H和ApplicationThread
- mInstrumentation是Instrumentation类的对象,Instrumentation类为ActivityThread的一个工具类,在ActivityThread中初始化,一个进程只存在一个Instrumentation对象,在每个Activity初始化时,会通过Activity的Attach方法,将该引用传递给Activity。Activity所有生命周期的方法都有该类来执行。最后mInstrumentation调用了Application的onCreate方法。
- H继承于Handler,mH负责处理ApplicationThread发送到消息队列的消息,Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施。
- ApplicationThread是ActivityThread的内部类,ApplicationThread内部继承自Binder并实现IApplicationThread接口。Binder是C/S结构,Binder是Service,AMS是Client,ApplicationThread主要用于应用进程和AMS进程间通信,并用于AMS的调用,通过H类将消息发送到消息队列,然后进行相应的操作。
为什么App进程做服务端呢?
仔细想想,Activity的生命周期回调是谁调用的啊。肯定不是app本身控制,而远程服务通过监听到一系列的操作发起周期回调,AMS持有App的proxy,这个代理的协议是IApplicationThread,于是AMS监控系统需要onResume,则通过proxy发起IApplicationThread的onResume,也就是通知服务去执行onResume。所以这里作为Binder理解IPC,服务端就是客户端App而不是AMS,AMS作为请求端,持有App进程的代理。
public static void main(String[] args) {
//....
//创建Looper和MessageQueue对象,用于处理主线程的消息
Looper.prepareMainLooper();
//创建ActivityThread对象
ActivityThread thread = new ActivityThread();
//建立Binder通道(创建新线程)
thread.attach(false);
Looper.loop(); //消息循环运行
throw new RuntimeException("Main thread loop unexpectedly exited");
}
private void attach(boolean system){
...
final IActivityManager mgr = ActivityManager.getService();
try {
//将ApplicationThread这个Binder交给了ActivityManagerService
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
if (dalvikUsed > ((3*dalvikMax)/4)) {
if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
+ " total=" + (runtime.totalMemory()/1024)
+ " used=" + (dalvikUsed/1024));
mSomeActivitiesChanged = false;
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
...
}
主线程(ActivityThread)的初始化:
- 开启消息循环。调用Looper.prepareLoop() Looper.loop(),开启主线程的消息循环,以便于ApplicationThread调用ActivityThread中的生命周期方法。
- 通知ActivityManagerService。调用ActivityThread.attach()方法,attach()方法在调用了attachApplication()将ApplicationThread这个Binder交给了ActivityManagerService,意味着ActivityManagerService可以通过ApplicationThread控制我们的应用,建立了服务器端对客户端的通信渠道。
- 添加GCWatcher。在attach()方法中,添加了监听dialvik内存使用情况得监听者GcWatcher,当内存使用超过总容量的3/4,则打印Log进行记录,并且调用ActivityManagerService的releaseSomeActivities()进行内存释放操作,以防止内存溢出导致应用崩溃。
attach()方法在调用了attachApplication()之后,经过一系列操作,最后调用了ApplicationThread的bindApplication()方法,bindApplication中通过消息机制,sendMessage到ActivityThread,handleMessage调用了ActivityThread的handleBindApplication()。通过反射创建了Application对象,然后onCreate创建activity。
private void handleBindApplication(AppBindData data) {
//创建appContext
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
//通过反射创建Application
app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
try {
//调用Application的onCreate方法
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
}
}
}
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
总结:ActivityThread通过ApplicationThread和AMS进行进程间通讯,AMS接受 ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到ActivityThread中去执行,即切换到主线程中去执行。
Handler 线程间通信
从上面我们得知Activity的生命周期都是依靠主线程的Looper.loop,主线程Handler收到不同Message时则采用相应措施。接下来介绍Handler。
Handler作用:
进行子线程与主线程之间的通信。子线程可以通过Handler来通知主线程进行UI更新。
根据Looper.loop()源码可知里面是一个死循环在遍历消息队列取消息,queue.next()阻塞方法,从队列中获取消息。
public static void loop() {
final Looper me = myLooper();
......
for (;;) {
//获取消息队列中的消息
Message msg = queue.next(); // might block
....
//然后分发消息到Handler的处理中
msg.target.dispatchMessage(msg);
...
//释放消息
msg.recycleUnchecked();
}
}
Android在子线程更新UI的三种方式
new Handler(mContext.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// 在这里执行你要想的操作 比如直接在这里更新ui或者调用回调在 在回调中更新ui
}
});
常见常用的post()类方法汇总:
- post(Runnable)
- postAtTime(Runnable,long) System.currentTimeMillis() + 100000 在设定的目标时间post
- postDelayed(Runnable long) 延迟多少时间再post
((Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
// 在这里执行你要想的操作 比如直接在这里更新ui或者调用回调在 在回调中更新ui
}
});
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case ACTIVENUMBER:
MaintainProtos.ActiveNumber activeNumber = (MaintainProtos.ActiveNumber) msg.obj;
break;
}
}
};
Message msg = Message.obtain();
msg.what = ACTIVENUMBER;
msg.obj = activeNumber;
mHandler.sendMessage(msg);
常见常用的send类方法汇总:
- sendEmptyMessage(int)
- sendMessage(Message)
- sendMessageAtTime(Message,long)
- sendMessageDelayed(Message,long)
Handler内部如何获取到当前线程的Looper?
ThreadLocal。ThreadLocal可以在不同的线程中互不干扰的存储并提供数据,通过ThreadLocal可以轻松获取每个线程的Looper。当然需要注意的是①线 程是默认没有Looper的,如果需要使用Handler,就必须为线程创建Looper。我们经常提到的主线 程,也叫UI线程,它就是ActivityThread,②ActivityThread被创建时就会初始化Looper,这也是在主 线程中默认可以使用Handler的原因。
系统为什么不允许在子线程中访问UI?
这是因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态,那么为什么 系统不对UI控件的访问加上锁机制呢?缺点有两个: ①首先加上锁机制会让UI访问的逻辑变得复杂 ②锁机制会降低UI访问的效率,因为锁机制会阻塞某些线程的执行。 所以最简单且高效的方法就是采用单线程模型来处理UI操作。
Looper.loop为什么不会阻塞主线程?
Activity的生命周期就是依靠Looper.loop(),Looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper.loop() 的控制之下。所以不存在主线程会被Looper.loop方法阻塞。
Handler优化:
实现静态内部类:实际项目中Handler很少采用上面匿名类的实现方式,因为会造成内存泄漏,大部分采用静态内部类、建一个单类或者在onDestroy方法中removeCallbacksAndMessages。
使用HandlerThread:Loop主线程已经有了,不需要我们自己创建,但是子线程默认是没有开启消息循环的。需要用到Looper.prepare()和Looper.loop(),当然也可以用到我们上面的实现方式传回主线程,但是这样做会增加主线程的工作量。
HandlerThread:本质上就是一个普通Thread,只不过内部建立了Looper。
public class MainActivity extends AppCompatActivity {
private HandlerThread myHandlerThread ;
private Handler handler ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1、创建一个线程,线程名字:handler-thread
myHandlerThread = new HandlerThread( "handler-thread") ;
//2、开启一个线程
myHandlerThread.start();
//3、在这个线程中创建一个handler对象
handler = new Handler( myHandlerThread.getLooper() ){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//这个方法是运行在 handler-thread 线程中的 ,可以执行耗时操作
Log.d( "handler " , "消息: " + msg.what + " 线程: " + Thread.currentThread().getName() ) ;
}
};
//在主线程给handler发送消息
handler.sendEmptyMessage( 1 ) ;
//在子线程给handler发送数据
new Thread(new Runnable() {
@Override
public void run() {
handler.sendEmptyMessage( 2 ) ;
}
}).start() ;
}
@Override
protected void onDestroy() {
super.onDestroy();
//4、释放资源
myHandlerThread.quit() ;
}
}
因为最后执行了quit()操作,所以内存泄漏的问题也得到解决。
最后
以上就是阔达皮卡丘为你收集整理的Android—ActivityThread与HandlerActivityThread的全部内容,希望文章能够帮你解决Android—ActivityThread与HandlerActivityThread所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复