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线程。

Android 非UI线程不能更新UI

2. 主线程是如何工作的?

  就是Handler原理,典型的生产者消费者模式;

 

 Android 非UI线程不能更新UI

 

 

3. 假设,把UI线程设计成线程安全的?

  1. 什么是线程不安全?

  可变资源(内存)线程间共享。

  2. 如果多线程更新TextView,线程安全就是设计成这样:

Android 非UI线程不能更新UI

 

 

  图上可知就是加锁,加锁是比较耗时的,但是,UI更新又是一个高频更新。

  3. 为什么不设计成线程安全?

    1. UI具有可变性,甚至是高频可变性;

    2. UI对响应时间敏感性的要求UI操作必须高效;

    3. UI组件必须批量绘制来保住效率;

4. 非UI线程就一定不能更新UI吗?

  1. 工作线程间接更新UI,比如:网络请求:

  正常通知UI线程更新UI:

Android 非UI线程不能更新UI

 

 

  工作线程(I/O线程)间接更新UI:

 Android 非UI线程不能更新UI

 

 

  2. 工作线程直接更新UI,比如:SurfaceView就是子线程更新渲染的:

 

Android 非UI线程不能更新UI

 

 

  视频画面渲染显示就是使用SurfaceView。

  地图使用的是GLSurfaceView,是SurfaceView子类,GLSurfaceView是OpenGL渲染。

 

Android 非UI线程不能更新UI

上一篇:Android 绘图时实现双缓冲


下一篇:苹果 M1 Mac 安装系统后创建用户失败的解决方法