Android 非UI线程不能更新UI
1. 什么是UI线程?
App通过Zygote fork创建一个App进程,通过ActivityThread的main()函数创建ActivityThread实例及UI线程Looper对象。
程序都有一个main()函数,也就是主函数,Android中的主函数在ActivityThread这个类中,主函数是一个静态方法。
源码:
public class ActivityThread { ... public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); // Install selective syscall interception AndroidOs.install(); // 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(); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line. // It will be in the format "seq=114" long startSeq = 0; if (args != null) { for (int i = args.length - 1; i >= 0; --i) { if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) { startSeq = Long.parseLong( args[i].substring(PROC_START_SEQ_IDENT.length())); } } } ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } .... }
上面代码和创建一个工作线程及创建工作线程的Looper代码是一样的。
UI线程就是通过AMS Zygeto fork创建进程时创建的线程主线程就是UI线程。
2. 主线程是如何工作的?
就是Handler原理,典型的生产者消费者模式;
3. 假设,把UI线程设计成线程安全的?
1. 什么是线程不安全?
可变资源(内存)线程间共享。
2. 如果多线程更新TextView,线程安全就是设计成这样:
图上可知就是加锁,加锁是比较耗时的,但是,UI更新又是一个高频更新。
3. 为什么不设计成线程安全?
1. UI具有可变性,甚至是高频可变性;
2. UI对响应时间敏感性的要求UI操作必须高效;
3. UI组件必须批量绘制来保住效率;
4. 非UI线程就一定不能更新UI吗?
1. 工作线程间接更新UI,比如:网络请求:
正常通知UI线程更新UI:
工作线程(I/O线程)间接更新UI:
2. 工作线程直接更新UI,比如:SurfaceView就是子线程更新渲染的:
视频画面渲染显示就是使用SurfaceView。
地图使用的是GLSurfaceView,是SurfaceView子类,GLSurfaceView是OpenGL渲染。