Android ActivityThread(主线程或UI线程)简介
1. ActivityThread功能
它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IApplicationThread接口,AMS为Client、ActivityThread.ApplicationThread为Server)负责调度和执行activities、broadcasts和其它操作。
在Android系统中,在默认情况下,一个应用程序内的各个组件(如Activity、BroadcastReceiver、Service)都会在同一个进程(Process)里执行,且由此进程的【主线程】负责执行。
在Android系统中,如果有特别指定(通过android:process),也可以让特定组件在不同的进程中运行。无论组件在哪一个进程中运行,默认情况下,他们都由此进程的【主线程】负责执行。
【主线程】既要处理Activity组件的UI事件,又要处理Service后台服务工作,通常会忙不过来。为了解决此问题,主线程可以创建多个子线程来处理后台服务工作,而本身专心处理UI画面的事件。
【主线程】的主要责任:
• 快速处理UI事件。而且只有它才处理UI事件, 其它线程还不能存取UI画面上的对象(如TextView等),此时, 主线程就叫做UI线程。基本上,Android希望UI线程能根据用户的要求做出快速响应,如果UI线程花太多时间处理后台的工作,当UI事件发生时,让用户等待时间超过5秒而未处理,Android系统就会给用户显示ANR提示信息。
只有UI线程才能执行View派生类的onDraw()函数。
• 快速处理Broadcast消息。【主线程】除了处理UI事件之外,还要处理Broadcast消息。所以在BroadcastReceiver的onReceive()函数中,不宜占用太长的时间,否则导致【主线程】无法处理其它的Broadcast消息或UI事件。如果占用时间超过10秒, Android系统就会给用户显示ANR提示信息。
注意事项:
• 尽量避免让【主线程】执行耗时的操作,让它能快速处理UI事件和Broadcast消息。
• BroadcastReceiver的子类都是无状态的,即每次启动时,才会创建其对象,然后调用它的onReceive()函数,当执行完onReceive()函数时,就立即删除此对象。由于每次调用其函数时,会重新创建一个新的对象,所以对象里的属性值,是无法让各函数所共享。
1.1 Thread与SurfaceView
View组件由UI线程(主线程)所执行。如果需要迅速更新UI画面或UI画图需要较长时间,则需要使用SurfaceView。它可由后台线程(background thread)来执行,而View只能由UI(主)线程执行。SurfaceView内有高效的rendering机制,可以让后台线程快速刷新Surface的内容。
View ---> UI(主)线程
SurfaceView ---> 后台线程
2. Android应用程序主线程stack
在一个只有Activity派生类的应用程序中,它包含如下线程:
main线程stack如下:
- at android.os.MessageQueue.nativePollOnce(Native Method)
- at android.os.MessageQueue.next(MessageQueue.java:118)
- at android.os.Looper.loop(Looper.java:118)
- at android.app.ActivityThread.main(ActivityThread.java:4424) // Java main入口函数
- at java.lang.reflect.Method.invokeNative(Native Method)
- at java.lang.reflect.Method.invoke(Method.java:511)
- at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
- at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
- at dalvik.system.NativeStart.main(Native Method)
JDWP线程stack如下:
- at org.apache.harmony.dalvik.ddmc.DdmVmInternal.getStackTraceById(Native Method)
- at android.ddm.DdmHandleThread.handleSTKL(DdmHandleThread.java:131)
- at android.ddm.DdmHandleThread.handleChunk(DdmHandleThread.java:77)
- at org.apache.harmony.dalvik.ddmc.DdmServer.dispatch(DdmServer.java:171)
- at dalvik.system.NativeStart.run(Native Method)
3. IApplicationThread关系图
4. ActivityThread类
ActivityThread类即代表Application主线程。
4.1 类中关键信息
- /**
- * This manages the execution of the main thread in an
- * application process, scheduling and executing activities,
- * broadcasts, and other operations on it as the activity
- * manager requests.
- *
- * {@hide}
- */
- public final class ActivityThread {
- static ContextImpl mSystemContext = null;
- static IPackageManager sPackageManager;
- // 创建ApplicationThread实例,以接收AMS指令并执行
- final ApplicationThread mAppThread = new ApplicationThread();
- final Looper mLooper = Looper.myLooper();
- final H mH = new H();
- final HashMap<IBinder, ActivityClientRecord> mActivities
- = new HashMap<IBinder, ActivityClientRecord>();
- // List of new activities (via ActivityRecord.nextIdle) that should
- // be reported when next we idle.
- ActivityClientRecord mNewActivities = null;
- // Number of activities that are currently visible on-screen.
- int mNumVisibleActivities = 0;
- final HashMap<IBinder, Service> mServices
- = new HashMap<IBinder, Service>();
- Application mInitialApplication;
- final ArrayList<Application> mAllApplications
- = new ArrayList<Application>();
- static final ThreadLocal<ActivityThread> sThreadLocal = new ThreadLocal<ActivityThread>();
- Instrumentation mInstrumentation;
- static Handler sMainThreadHandler; // set once in main()
- static final class ActivityClientRecord {
- IBinder token;
- int ident;
- Intent intent;
- Bundle state;
- Activity activity;
- Window window;
- Activity parent;
- String embeddedID;
- Activity.NonConfigurationInstances lastNonConfigurationInstances;
- boolean paused;
- boolean stopped;
- boolean hideForNow;
- Configuration newConfig;
- Configuration createdConfig;
- ActivityClientRecord nextIdle;
- String profileFile;
- ParcelFileDescriptor profileFd;
- boolean autoStopProfiler;
- ActivityInfo activityInfo;
- CompatibilityInfo compatInfo;
- LoadedApk packageInfo; //包信息,通过调用ActivityThread.getPapckageInfo而获得
- List<ResultInfo> pendingResults;
- List<Intent> pendingIntents;
- boolean startsNotResumed;
- boolean isForward;
- int pendingConfigChanges;
- boolean onlyLocalRequest;
- View mPendingRemoveWindow;
- WindowManager mPendingRemoveWindowManager;
- ...
- }
- private class ApplicationThread extends ApplicationThreadNative {
- private void updatePendingConfiguration(Configuration config) {
- synchronized (mPackages) {
- if (mPendingConfiguration == null ||
- mPendingConfiguration.isOtherSeqNewer(config)) {
- mPendingConfiguration = config;
- }
- }
- }
- public final void schedulePauseActivity(IBinder token, boolean finished,
- boolean userLeaving, int configChanges) {
- queueOrSendMessage(
- finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
- token,
- (userLeaving ? 1 : 0),
- configChanges);
- }
- // we use token to identify this activity without having to send the
- // activity itself back to the activity manager. (matters more with ipc)
- public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
- ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
- Bundle state, List<ResultInfo> pendingResults,
- List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
- String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
- ActivityClientRecord r = new ActivityClientRecord();
- r.token = token;
- r.ident = ident;
- r.intent = intent;
- r.activityInfo = info;
- r.compatInfo = compatInfo;
- r.state = state;
- r.pendingResults = pendingResults;
- r.pendingIntents = pendingNewIntents;
- r.startsNotResumed = notResumed;
- r.isForward = isForward;
- r.profileFile = profileName;
- r.profileFd = profileFd;
- r.autoStopProfiler = autoStopProfiler;
- updatePendingConfiguration(curConfig);
- queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
- }
- ...
- }
- private class H extends Handler {
- public void handleMessage(Message msg) {
- if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
- switch (msg.what) {
- case LAUNCH_ACTIVITY: {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
- ActivityClientRecord r = (ActivityClientRecord)msg.obj;
- r.packageInfo = getPackageInfoNoCheck(
- r.activityInfo.applicationInfo, r.compatInfo);
- handleLaunchActivity(r, null);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- } break;
- ...
- }
- if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
- }
- ...
- }
- public static ActivityThread currentActivityThread() {
- return sThreadLocal.get();
- }
- public static void main(String[] args) {
- SamplingProfilerIntegration.start();
- // CloseGuard defaults to true and can be quite spammy. We
- // disable it here, but selectively enable it later (via
- // StrictMode) on debug builds, but using DropBox, not logs.
- CloseGuard.setEnabled(false);
- Environment.initForCurrentUser();
- // Set the reporter for event logging in libcore
- EventLogger.setReporter(new EventLoggingReporter());
- Process.setArgV0("<pre-initialized>");
- Looper.prepareMainLooper();
- // 创建ActivityThread实例
- ActivityThread thread = new ActivityThread();
- thread.attach(false);
- if (sMainThreadHandler == null) {
- sMainThreadHandler = thread.getHandler();
- }
- AsyncTask.init();
- if (false) {
- Looper.myLooper().setMessageLogging(new
- LogPrinter(Log.DEBUG, "ActivityThread"));
- }
- Looper.loop();
- throw new RuntimeException("Main thread loop unexpectedly exited");
- }
- }
4.2 家族图谱
4.3 ActivityThread内部类
4.4 ActivityThread工作流程
Android ActivityThread(主线程或UI线程)简介的更多相关文章
- [Android学习笔记]子线程更新UI线程方法之Handler
关于此笔记 不讨论: 1.不讨论Handler实现细节 2.不讨论android线程派发细节 讨论: 子线程如何简单的使用Handler更新UI 问题: android开发时,如何在子线程更新UI? ...
- 新建线程与UI线程间的通信
现在用一个实例来演示一下自己的新建线程与UI线程间的通信. UI界面包含3个控件: 一个输入框,用来输入数字: 一个显示框,用来显示从2开始,到输入数字之间的所有质数: 一个按钮,点击后获取输入框输入 ...
- OkHttp3几个简单的例子和在子线程更新UI线程的方法
okHttp用于android的http请求.据说很厉害,我们来一起尝尝鲜.但是使用okHttp也会有一些小坑,后面会讲到如何掉进坑里并爬出来. 首先需要了解一点,这里说的UI线程和主线程是一回事儿. ...
- C# 委托 / 跨线程访问UI / 线程间操作无效: 从不是创建控件“Form1”的线程访问它
C# 委托 / 跨线程访问UI / 线程间操作无效: 从不是创建控件“Form1”的线程访问它 网上的代码都比较复杂,还是这个简单 见代码, 简易解决办法: 主窗体代码 using System; ...
- 主线程与UI线程简介
---------------siwuxie095 Java 程序的主线程 当 Java 程序启动时,一个线程立刻运行,该线程通常叫做程 ...
- C#用副线程改主线程(UI线程)的控件属性的方法(包括Winform和WPF)
C#用副线程去试图修改主线程的UI控件会报出异常,解决方案是使用副线程注册事件通知主线程自己去修改UI控件 在winform中,方法如下 private void button1_Click(obje ...
- Android开之在非UI线程中更新UI
当在非UI线程中更新UI(程序界面)时会出现例如以下图所看到的的异常: 那怎样才干在非UI线程中更细UI呢? 方法有非常多种.在这里主要介绍三种: 第一种:调用主线程mHandler的post(Run ...
- C#中后台线程和UI线程的交互
在C#中,从Main()方法开始一个默认的线程,一般称之为主线程,如果在这个进行一些非常耗CPU的计算,那么UI界面就会被挂起而处于假死状态,也就是说无法和用户进行交互了,特别是要用类似进度条来实时显 ...
- WPF线程获取UI线程
WPF中只能是UI线程才可以改变UI控件相关,当采用多线程工作时,可用以下代码获取 UI线程进行操作: App.Current.Dispatcher.Invoke((Action)delegate() ...
随机推荐
- 浅谈thinkphp中将字符串转换成json数组的方法
这是一部分代码: $client = M("Client");$data = $client->where('user_id ='.$user_id)->select( ...
- yii中sphinx,Ajax搜索分页
效果图: 控制器: <?phpnamespace backend\controllers; use Yii;use yii\web\Controller;use yii\data\Paginat ...
- linux挂接U盘
挂接U盘fdisk -lDisk /dev/sdd: 131 MB, 131072000 bytes/dev/sdd1 * 1 889 127983+ b Win95 FAT32#mkdir -p / ...
- html随笔
<!DOCTYPE HTML> <html> <head> <meta charset = "utf-8"> <script ...
- java 文件及流读取
在Java语言的IO编程中,读取文件是分两个步骤:1.将文件中的数据转换为流,2.读取流内部的数据.其中第一个步骤由系统完成,只需要创建对应的流对象即可,对象创建完成以后步骤1就完成了,第二个步骤使用 ...
- CSS Reset / Normalize 如何进行样式重置
CSS Reset 过于激进,所有样式全部消除没有必要. 关键是保持各种浏览器的兼容,包括Bootstrap的CSS Reset也是走的这个路线. 线面这个就是后面一种思路的成果: http://ne ...
- WCF入门教程:WCF基础知识问与答(转)
学习WCF已有近两年的时间,其间又翻译了Juval的大作<Programming WCF Services>,我仍然觉得WCF还有更多的内容值得探索与挖掘.学得越多,反而越发觉得自己所知太 ...
- 【转】Delphi利用系统环境变量获取常用系统目录
Delphi code //譬如 %WINDIR% 是表示系统目录的系统变量, 可以这样获取: var s: string; begin s := GetEnvironmentVariable('WI ...
- WM_SETFOCUS和WM_KILLFOCUS、WM_GETDLGCODE、CM_ENTER...
procedure WMSetFocus (var Message: TWMSetFocus); message WM_SETFOCUS; //获得焦点 procedure WMKillFocus ( ...
- 图像处理工具包ImagXpress教程:Accusoft不同组件间的图像数据传递
图像处理工具包ImagXpress的开发厂商Accusoft Pegasus旗下有多种图像处理相关的控件,但是这些图像处理控件之间的如何加传递图像数据呢?在ImagXpress 11版本之前,是需要将 ...