• 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渲染。

  • 相关阅读:
    java 版下载地址
    java文档
    中文打包之后无法显示
    通过Unity3d创建二维码(利用zxing2.2)
    通过NavMeshObstacle解决NavMesh防卡
    EditorGUILayout.EnumPopup 枚举弹出选择菜单
    价格表
    热更新脚本C#light,ulua,Scorpio性能比较
    Ngui 五种点击事件实现方式及在3d场景中点透的情况
    linux每日命令(38):iostat命令
  • 原文地址:https://www.cnblogs.com/naray/p/13035205.html
Copyright © 2020-2023  润新知