Android 线程优化知识点学习

目录
  • 前言
  • 一、线程调度原理解析
    • 线程调度的原理
    • 线程调度模型
    • Android 的线程调度
    • 线程调度小结
  • 二、Android 异步方式汇总
    • Thread
    • HandlerThread
    • IntentService
    • AsyncTask
    • 线程池
    • RxJava
  • 三、Android线程优化实战
    • 线程使用准则
    • 线程池优化实战
  • 四、定位线程创建者
    • 如何确定线程创建者
    • Epic实战
  • 五、优雅实现线程收敛
    • 线程收敛常规方案
    • 基础库如何使用线程
    • 基础库优雅使用线程

前言

在实际项目开发中会频繁的用到线程,线程使用起来是很简单,但是滥用线程会带来性能问题, 比如启动一个线程至少 占用16kb的内存、线程过多会导致cpu的频繁切换而cpu切换成本是很高的、消耗大量用户电量等问题, 所以应该让app的线程数保持在合理水平,这是性能优化中很重要的一部分。本文对线程优化方面的知识做了一个全面总结,主要内容如下:

一、线程调度原理解析

线程调度的原理

在任意时刻,CPU 只能执行一条机器指令,每个线程只有获得了 CPU 的使用权之后才能执行指令,也就是说 在任意时刻,只有一个线程占用 CPU,处于运行状态。而我们平常所说的 多线程并发运行,实际上说的是多个线程轮流获取 CPU 的使用权,然后分别执行各自的任务。其实在可运行池当中有多个处于就绪状态的线程在等待 CPU,而 JVM 负责线程调度,按照特定机制为多个线程分配 CPU 使用权。

上面的描述提到了三个主要信息:

  • 在任意时刻,只有一个线程占用 CPU,处于运行状态
  • 多线程并发运行,实际上说的是多个线程轮流获取 CPU 的使用权
  • JVM 负责线程调度,按照特定机制为多个线程分配 CPU 使用权

线程调度模型

线程调度模型可以分为两类,分别是 分时调度模型 和 抢占式调度模型。

  • 分时调度模型:让所有线程轮流获取 CPU 的使用权,而且均分每个线程占用 CPU 的时间片,这种方式非常公平
  • 抢占式调度模型:JVM 使用的是抢占式调度模型,让优先级高的线程优先获取到 CPU 的使用权,如果在可运行池当中的线程优先级都一样,那就随机选取一个

Android 的线程调度

Android 的线程调度从两个因素决定,一个是 nice 值(即线程优先级),一个是 cgroup(即线程调度策略)。

对于 nice 值来说,它首先是在 Process 中定义的,值越小,进程优先级越高,默认值是 THREAD_PRIORITY_DEFAULT = 0,主线程的优先级也是这个值。修改 nice 值只需要在对应的线程下设置即可:

public class MyRunnable implements Runnable {<!-- -->
	@Override
	public void run() {<!-- -->
		Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT)
	}
}
// 附上 setThreadPriority() 文档说明
/**
 * Set the priority of the calling thread, based on Linux priorities.  See
 * {@link #setThreadPriority(int, int)} for more information.
 *
 * @param priority A Linux priority level, from -20 for highest scheduling
 * priority to 19 for lowest scheduling priority.
 *
 * @throws IllegalArgumentException Throws IllegalArgumentException if
 * &lt;var&gt;tid&lt;/var&gt; does not exist.
 * @throws SecurityException Throws SecurityException if your process does
 * not have permission to modify the given thread, or to use the given
 * priority.
 *
 * @see #setThreadPriority(int, int)
 */
public static final native void setThreadPriority(int priority)
        throws IllegalArgumentException, SecurityException;

nice 值它还有其他的优先级可选:

public class Process {
    /**
     * Standard priority of application threads.
     * Use with {@link #setThreadPriority(int)} and
     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
     * {@link java.lang.Thread} class.
     */
	public static final int THREAD_PRIORITY_DEFAULT = 0;
    /**
     * Lowest available thread priority.  Only for those who really, really
     * don't want to run if anything else is happening.
     * Use with {@link #setThreadPriority(int)} and
     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
     * {@link java.lang.Thread} class.
     */
    public static final int THREAD_PRIORITY_LOWEST = 19;
    /**
     * Standard priority background threads.  This gives your thread a slightly
     * lower than normal priority, so that it will have less chance of impacting
     * the responsiveness of the user interface.
     * Use with {@link #setThreadPriority(int)} and
     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
     * {@link java.lang.Thread} class.
     */
    public static final int THREAD_PRIORITY_BACKGROUND = 10;
    /**
     * Standard priority of threads that are currently running a user interface
     * that the user is interacting with.  Applications can not normally
     * change to this priority; the system will automatically adjust your
     * application threads as the user moves through the UI.
     * Use with {@link #setThreadPriority(int)} and
     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
     * {@link java.lang.Thread} class.
     */
    public static final int THREAD_PRIORITY_FOREGROUND = -2;
    /**
     * Standard priority of system display threads, involved in updating
     * the user interface.  Applications can not
     * normally change to this priority.
     * Use with {@link #setThreadPriority(int)} and
     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
     * {@link java.lang.Thread} class.
     */
    public static final int THREAD_PRIORITY_DISPLAY = -4;
    /**
     * Standard priority of the most important display threads, for compositing
     * the screen and retrieving input events.  Applications can not normally
     * change to this priority.
     * Use with {@link #setThreadPriority(int)} and
     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
     * {@link java.lang.Thread} class.
     */
    public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8;
    /**
     * Standard priority of video threads.  Applications can not normally
     * change to this priority.
     * Use with {@link #setThreadPriority(int)} and
     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
     * {@link java.lang.Thread} class.
     */
    public static final int THREAD_PRIORITY_VIDEO = -10;
    /**
     * Standard priority of audio threads.  Applications can not normally
     * change to this priority.
     * Use with {@link #setThreadPriority(int)} and
     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
     * {@link java.lang.Thread} class.
     */
    public static final int THREAD_PRIORITY_AUDIO = -16;
    /**
     * Standard priority of the most important audio threads.
     * Applications can not normally change to this priority.
     * Use with {@link #setThreadPriority(int)} and
     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
     * {@link java.lang.Thread} class.
     */
    public static final int THREAD_PRIORITY_URGENT_AUDIO = -19;
    /**
     * Minimum increment to make a priority more favorable.
     */
    public static final int THREAD_PRIORITY_MORE_FAVORABLE = -1;
    /**
     * Minimum increment to make a priority less favorable.
     */
    public static final int THREAD_PRIORITY_LESS_FAVORABLE = +1;
}

在实践过程当中,如果只有 nice 值是不足够的。比如有一个 app 它有1个前台线程,而且它还有10个后台线程,虽然后台线程的优先级比较低,但是数量比较多,这10个后台线程对 CPU 的消耗量是可以影响到前台线程的性能的。所以 Android 需要一种机制来处理这种情况,也就是 cgroup。

Android 借鉴了 Linux 的 cgroup 来执行 更严格的前台和后台调度策略,后台优先级的线程会被隐式的移动到后台 group,而其他 group 的线程如果处于工作状态,那么后台这些线程它们将会被限制,只有很小的几率能够利用 CPU。

这种分离的调度策略既允许了后台线程来执行一些任务,同时又不会对用户可见的前台线程造成很大的影响,让前台线程有更多的 CPU。

或许你会有疑问:哪些线程会被移到后台 group?

  • 第一种就是那些 手动设置了优先级比较低的线程
  • 第二种就是 不在前台运行的那些应用程序的线程

线程调度小结

  • 线程过多会导致 CPU 频繁切换,降低线程运行效率。 在前面讲解启动优化的时候有强调要充足的利用线程比如异步启动任务,但是线程也不能无限制的使用
  • 正确认识任务重要性决定哪种优先级。 一般情况下线程工作量和优先级是成反比,比如线程的工作量越大,所做的工作没那么重要,那这个线程的优先级应该越低
  • 线程的优先级具有继承性。 比如在 A 线程创建了 B 线程,在我们没有指定线程优先级的情况下,B 线程的优先级是和 A 一样的。所以我们在 UI 线程中创建线程,线程的优先级是和 UI 线程一样的,这就会导致 UI 线程抢占 CPU 时间片的概率会变少

二、Android 异步方式汇总

Thread

使用 Thread 创建线程是最简单、常见的异步方式,但在实际项目中,它也就只有这个优点了,并不推荐直接使用 Thread 创建线程,主要有以下几点原因:

  • 不易复用,频繁创建及销毁开销大
  • 复杂场景不易使用

HandlerThread

是 Android 提供的一个自带消息循环的线程,它内部使用 串行的方式执行任务,比较 适合长时间运行,不断从队列中获取任务的场景。

IntentService

继承了 Android Service 组件,内部创建了 HandlerThread,相比 Service 是在主线程执行,IntentService 是 在子线程异步执行不占用主线程,而且 优先级比较高,不易被系统 kill。

AsyncTask

AsyncTask 是 Android 提供的工具类,内部的实现是使用了线程池,它比较大的好处是无需自己处理线程切换,但需要注意 AsyncTask 不同版本执行方式不一致的问题。

线程池

java 提供了线程池,在实际项目中比较推荐使用线程池的方式实现异步任务,它主要有以下优点:

  • 易复用,减少线程频繁创建、销毁的时间
  • 功能强大:定时、任务队列、并发数控制等,java 提供了 Executors 工具类可以很方便的创建一个线程池,也可以自己定制线程池

RxJava

RxJava 由强大的 Scheduler 集合提供,内部实际也是使用的线程池,它封装的非常完善,可以根据任务类型的不同指定使用不同的线程池,比如 IO 密集型的任务可以指定 Schedulers.IO,CPU 密集型任务可以指定 Schedulers.Computation

Single.just(xxx)
	.subscribeOn(Schedulers.IO) // 指定工作线程类型为 IO 密集型
	.observeOn(AndroidSchedulers.mainThread()) // 指定下游接收所在线程
	.subscribe();

三、Android线程优化实战

线程使用准则

  • 严禁使用直接new Thread()的方式
  • 提供基础线程池供各个业务线使用: 避免各个业务线各自维护一套线程池,导致线程数过多
  • 根据任务类型选择合适的异步方式: 比如优先级低且长时间执行可以使用Handler Thread,再比如:有一个任务需要定时执行,使用线程池更适合
  • 创建线程必须命名: 方便定位线程归属于哪一个业务方,在线程运行期可以使用Thread.currentThread().setName修改名字
  • 关键异步任务监控: 异步不等于不耗时,如果一个任务在主线程需要耗费500ms,那么它在异步任务中至少需要500ms,因为异步任务中优先级较低,耗费时间很可能会高于500ms,所以这里可以使用AOP的方式来做监控,并且结合所在的业务场景,根据监控结果来适时的做一些相对应的调整
  • 重视优先级设置: 使用Process.setThreadPriority();设置,并且可以设置多次

线程池优化实战

接下来针对线程池的使用来做一个简单的实践,还是打开我们之前的项目,这里说一下每次实践的代码都是基于第一篇启动优化的那个案例上写的。

首先新建一个包async,然后在包中创建一个类ThreadPoolUtils,这里我们创建可重用且固定线程数的线程池,核心数为5,并且对外暴露一个get方法,然后我们可以在任何地方都能获取到这个全局的线程池:

public class ThreadPoolUtils {
    //创建定长线程池,核心数为5
    private static ExecutorService mService = Executors.newFixedThreadPool(5, new ThreadFactory() {
        @Override
        public Thread newThread(Runnable runnable) {
            Thread thread = new Thread(runnable,"ThreadPoolUtils");//设置线程名
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //设置线程优先级
            return thread;
        }
    });
    //获取全局的线程池
    public static ExecutorService getService(){
        return mService;
    }
}

然后使用的时候就可以在你需要的地方直接调用了,并且你在使用的时候还可以修改线程的优先级以及线程名称:

        //使用全局统一的线程池
        ThreadPoolUtils.getService().execute(new Runnable() {
            @Override
            public void run() {
                Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); //修改线程优先级
                String oldName = Thread.currentThread().getName();
                Thread.currentThread().setName("Jarchie"); //修改线程名称
                Log.i("MainActivity","");
                Thread.currentThread().setName(oldName); //将原有名称改回去
            }
        });

四、定位线程创建者

如何确定线程创建者

当你的项目做的越来越大的时候一般情况下线程都会变的非常多,最好是能够对整体的线程数进行收敛,那么问题来了,如何知道某个线程是在哪里创建的呢?不仅仅是你自己的项目源码,你依赖的第三方库、aar中都有线程的创建,如果单靠人眼review代码的方式,工作量很大而且你还不一定能找的全。

并且你这次优化完了线程数,你还要考虑其他人新加的线程是否合理,所以就需要能够建立一套很好的监控预防手段。然后针对这些情况来做一个解决方案的总结分析,主要思想就是以下两点:

  • 创建线程的位置获取堆栈
  • 所有的异步方式,都会走到new Thread

解决方案:

  • 特别适合Hook手段
  • 找Hook点:构造函数或者特定方法
  • Thread的构造函数

可以在构造函数中加上自己的逻辑,获取当前的调用栈信息,拿到调用栈信息之后,就可以分析看出某个线程是否使用的是统一的线程池,也可以知道某个线程具体属于哪个业务方。

Epic实战

Epic简介

  • Epic是一个虚拟机层面、以Java Method为粒度的运行时Hook框架
  • 支持Android4.0-10.0(我的手机上程序出现了闪退,后来查找原因发现这个库开源版本一些高版本手机好像不支持)

Epic使用

  • implementation 'me.weishu:epic:0.6.0'
  • 继承XC_MethodHook,实现相应逻辑
  • 注入Hook:DexposedBridge.findAndHookMethod

代码中使用

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        //Hook Thread类的构造函数,两个参数:需要Hook的类,MethodHook的回调
        DexposedBridge.hookAllConstructors(Thread.class, new XC_MethodHook() {
            //afterHookedMethod是Hook此方法之后给我们的回调
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param); //Hook完成之后会回调到这里
                //实现自己的逻辑,param.thisObject可以拿到线程对象
                Thread thread = (Thread) param.thisObject;
                //Log.getStackTraceString打印当前的调用栈信息
                Log.i(thread.getName() + "stack", Log.getStackTraceString(new Throwable()));
            }
        });
    }

如果你的手机支持的话,这个时候运行程序应该就可以看到线程打印出来的堆栈信息了

五、优雅实现线程收敛

线程收敛常规方案

  • 根据线程创建堆栈考量合理性,使用统一线程库
  • 各业务线需要移除自己的线程库使用统一的线程库

基础库如何使用线程

  • 直接依赖线程库
  • 缺点:线程库更新可能会导致基础库也跟着更新

基础库优雅使用线程

  • 基础库内部暴露API:setExecutor
  • 初始化的时候注入统一的线程库

举个栗子:

比如这里有一个日志工具类,我们将它作为应用的日志基础库,假设它内部有一些异步操作,原始的情况下是它自己内部实现的,然后现在在它内部对外暴露一个API,如果外部注入了一个ExecutorService,那么我们就使用外部注入的这个,如果外部没有注入,那就使用它默认的,代码如下所示:

public class LogUtils {
    private static ExecutorService mExecutorService;
    public static void setExecutor(ExecutorService executorService){
        mExecutorService = executorService;
    }
    public static final String TAG = "Jarchie";
    public static void i(String msg){
        if(Utils.isMainProcess(BaseApp.getApplication())){
            Log.i(TAG,msg);
        }
        // 异步操作
        if(mExecutorService != null){
            mExecutorService.execute(() -> {
                ...
            });
        }else {
            //使用原有的
            ...
        }
    }
}

统一线程库

  • 区分任务类型:IO密集型、CPU密集型
  • IO密集型任务不消耗CPU,核心池可以很大(网络请求、IO读写等)
  • CPU密集型任务:核心池大小和CPU核心数相关(如果并发数超过核心数会导致CPU频繁切换,降低执行效率)

举个栗子:根据上面的说明,可以做如下的设置:

    //获取CPU的核心数
    private int CPUCOUNT = Runtime.getRuntime().availableProcessors();
    //cpu线程池,核心数大小需要和cpu核心数相关联,这里简单的将它们保持一致了
    private ThreadPoolExecutor cpuExecutor = new ThreadPoolExecutor(CPUCOUNT, CPUCOUNT,
            30, TimeUnit.SECONDS, new LinkedBlockingDeque<>(), sThreadFactory);
    //IO线程池,核心数64,这个数量可以针对自身项目再确定
    private ThreadPoolExecutor iOExecutor = new ThreadPoolExecutor(64, 64,
            30, TimeUnit.SECONDS, new LinkedBlockingDeque<>(), sThreadFactory);
    //这里面使用了一个count作为标记
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        public Thread newThread(Runnable runnable) {
            return new Thread(runnable, "ThreadPoolUtils #" + mCount.getAndIncrement());
        }
    };

然后在你实际项目中需要区分具体的任务类型,针对性的选择相应的线程池进行使用。 以上就是对于Android线程优化方面的总结了,今天的内容还好不算多,觉得有用的朋友可以看看。

以上就是Android 线程优化知识点学习的详细内容,更多关于Android 线程优化的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android中实现多线程操作的几种方式

    目录 前言 最基础的方式 继承Thread类并实现run()方法 匿名内部类 实现Runnable接口 callable+FutureTask 线程池 手动创建线程池 使用Executors创建线程池 Android中特有的实现多线程 使用HandlerThread 使用IntentService JobIntentService/JobScheduler WorkManager WorkManager 使用协程 AsyncTask 结语 前言 多线程一直是一个老大难的问题,首先因为它难以理解,

  • Android如何调整线程调用栈大小

    在常规的Android开发过程中,随着业务逻辑越来越复杂,调用栈可能会越来越深,难免会遇到调用栈越界的情况,这种情况下,就需要调整线程栈的大小. 当然,主要还是增大线程栈大小,尤其是存在jni调用的情况下,C++层的栈开销有时候是非常恐怖的,比如说递归调用. 这就需要分三种情况,主线程,自定义线程池,AsyncTask. 主线程的线程栈是没有办法进行修改的,这个没办法处理. 针对线程池的情况,需要在创建线程的时候,调用构造函数 public Thread(@RecentlyNullable Th

  • android实现线程间通信的四种常见方式

    1,通过Handler机制 主线程中定义Handler,子线程发消息,通知Handler完成UI更新,Handler对象必须定义在主线程中,如果是多个类直接互相调用,就不是很方便,需要传递content对象或通过接口调用. 另外Handler机制与Activity生命周期不一致的原因,容易导致内存泄漏,不推荐使用. private void one() { handler=new Handler(){ @Override public void handleMessage(Message msg

  • Android中切换到主线程执行的方法

    方法一: view.post(Runnable runnable) 使用 view 对象,调用 post 方法即可在主线程中执行里边的代码,postDelayed 是延时执行,也可以达到相同的效果.例如: textView.post(new Runnable() { @Override public void run() { textView.setText("更新textView"); } }); 方法二:runOnUiThread(Runnable runnable) 在 Acit

  • Android开发经验谈:并发编程(线程与线程池)(推荐)

    一.线程 在Android开发中,你不可能都在主线程中开发,毕竟要联网,下载数据,保存数据等操作,当然这就离不开线程. (当然你可以在Android4.0以前的手机里在主线程请求网络,我最早开发的时候,用的手机比较古老...) 在Android中你可以随意创建线程,于是就会造成线程不可控,内存泄漏,创建线程消耗资源,线程太多了消耗资源等问题. 具体线程怎么创建我就不在文章里描述了,毕竟这主要将并发编程.... 大家知道线程不可控就好了...于是就需要对线程进行控制,防止一系列问题出现,这就用到了

  • android studio项目:绑定服务和线程实现计时器

    实验目的: 熟悉和掌握Android线程的使用 实验要求: 1.完成一个秒表,具备启停功能 2.通过绑定服务实现功能,通过Thread+handler更新界面 这章节没花什么时间去学,其他事情又很多,所以只是简单实现了一下,在生命周期那里还是有些没处理的地方,因此 主要思路是:在服务中启动一个线程实现计数的功能,并且每隔10ms调用一下更新界面的函数,这需要用到Thread+handler,当然还需要一些控制启停的公有函数供activity调用,同过绑定的服务的方式,activity中可以获得服

  • Android 线程优化知识点学习

    目录 前言 一.线程调度原理解析 线程调度的原理 线程调度模型 Android 的线程调度 线程调度小结 二.Android 异步方式汇总 Thread HandlerThread IntentService AsyncTask 线程池 RxJava 三.Android线程优化实战 线程使用准则 线程池优化实战 四.定位线程创建者 如何确定线程创建者 Epic实战 五.优雅实现线程收敛 线程收敛常规方案 基础库如何使用线程 基础库优雅使用线程 前言 在实际项目开发中会频繁的用到线程,线程使用起来

  • Android 内存优化知识点梳理总结

    目录 RAM 和 ROM 常见内存问题 内存溢出 内存泄漏 常见内存泄漏场景 静态变量或单例持有对象 非静态内部类的实例生命周期比外部类更长导致的内存泄漏 Handler 导致的内存泄漏 postDelayed 导致的内存泄漏 View 的生命周期大于 Activity 时导致的内存泄漏 集合中的对象未释放导致内存泄漏 WebView 导致的内存泄漏 内存抖动 解决方案 其他优化点 App 内存过低时主动清理 前言: Android 操作系统给每个进程都会分配指定额度的内存空间,App 使用内存

  • Android性能优化之plt hook与native线程监控详解

    目录 背景 native 线程创建 PLT PLT Hook xhook bhook plt hook总结 背景 我们在android超级优化-线程监控与线程统一可以知道,我们能够通过asm插桩的方式,进行了线程的监控与线程的统一,通过一系列的黑科技,我们能够将项目中的线程控制在一个非常可观的水平,但是这个只局限在java层线程的控制,如果我们项目中存在着native库,或者存在着很多其他so库,那么native层的线程我们就没办法通过ASM或者其他字节码手段去监控了,但是并不是就没有办法,还有

  • Android性能优化之线程监控与线程统一详解

    目录 背景 常规解决方案 线程监控 当前线程统计 线程信息具体化 线程统一 Thread创建 注意 总结 背景 在我们日常开发中,多线程管理一直是非常头疼的问题之一,尤其在历史性长,结构复杂的app中,线程数会达到好几百个甚至更多,然而过多的线程不仅仅带来了内存上的消耗同时也降低了cpu调度的效率,过多的cpu调度带来的消耗的坏处甚至超过了多线程带来的好处. 在我们日常开发中,通常会遇到以下几个问题 某个场景会创造过多的线程,最终导致oom 线程池过多问题,比如三方库有一套线程池,自己项目也有一

  • Android性能优化死锁监控知识点详解

    目录 前言 死锁检测 线程Block状态 获取当前线程所请求的锁 通过锁获取当前持有的线程 线程启动 nativePeer 与 native Thread tid 与java Thread tid dlsym与调用 系统限制 死锁检测所有代码 总结 前言 “死锁”,这个从接触程序开发的时候就会经常听到的词,它其实也可以被称为一种“艺术”,即互斥资源访问循环的艺术,在Android中,如果主线程产生死锁,那么通常会以ANR结束app的生命周期,如果是两个子线程的死锁,那么就会白白浪费cpu的调度资

  • android线程消息机制之Handler详解

    android线程消息机制主要由Handler,Looper,Message和MessageQuene四个部分组成.平常在开发中,我们常用来在子线程中通知主线程来更新,其实整个安卓生命周期的驱动都是通过Handler(ActivityThread.H)来实现的. 首先我们先介绍这四个类的作用: Handler:消息的发送者.负责将Message消息发送到MessageQueue中.以及通过Runnable,Callback或者handleMessage()来实现消息的回调处理 Looper:是消

  • Android性能优化系列篇UI优化

    目录 前言 一.UI优化 1.1 系统做的优化 1.1.1 硬件加速 1.2 优化方案 1.2.1 java代码布局 1.2.2 View重用 1.2.3 异步创建view 1.2.4 xml布局优化 1.2.5 异步布局框架Litho 1.2.6 屏幕适配 1.2.7 Flutter 1.2.8 Jetpack Compose 1.3 工具篇 1.3.1 Choreographer 1.3.2 LayoutInspector/Android Device Monitor 1.3.3 Systr

  • Android编程之SurfaceView学习示例详解

    本文实例讲述了Android编程之SurfaceView学习示例.分享给大家供大家参考,具体如下: SurfaceView是View的子类,使用的方式与任何View所派生的类都是完全相同的,可以像其他View那样应用动画,并把它们放到布局中. SurfaceView封装的Surface支持使用本章前面所描述的所有标准Canvas方法进行绘图,同时也支持完全的OpenGL ES库. 使用OpenGL,你可以再Surface上绘制任何支持的2D或者3D对象,与在2D画布上模拟相同的效果相比,这种方法

  • Android线程管理之ActivityThread

    ActivityThread功能 它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IApplicationThread接口,AMS为Client.ActivityThread.ApplicationThread为Server)负责调度和执行activities.broadcasts和其它操作. 在Android系统中,在默认情况下,一个应用程序内的各个组件(如Activity.BroadcastReceiver.Service)都会在同一个进程(

  • Android布局优化之ViewStub控件

    ViewStub是Android布局优化中一个很不错的标签/控件,直接继承自View.虽然Android开发人员基本上都听说过,但是真正用的可能不多. ViewStub可以理解成一个非常轻量级的View,与其他的控件一样,有着自己的属性及特定的方法.当ViewStub使用在布局文件中时,当程序inflate布局文件时,ViewStub本身也会被解析,且占据内存控件,但是与其他控件相比,主要区别体现在以下几点: 1.当布局文件inflate时,ViewStub控件虽然也占据内存,但是相相比于其他控

随机推荐