IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android高级面试题之SDK源码分析:通过线程提升性能,你所不知道的Android原生开发的现状 -> 正文阅读

[移动开发]Android高级面试题之SDK源码分析:通过线程提升性能,你所不知道的Android原生开发的现状

public class MyAsyncTask extends AsyncTask<Void, Void, String> {

@Override protected String doInBackground(Void… params) {…}

@Override protected void onPostExecute(String result) {…}

}

}

此代码段的缺陷在于,代码会将线程处理对象?MyAsyncTask?声明为某个 Activity 的非静态内部类(或 Kotlin 中的内部类)。此声明会创建对封装?Activity?实例的隐式引用。因此,在线程处理工作完成之前,该对象一直包含对相应 Activity 的引用,导致所引用 Activity 的销毁出现延迟。 这种延迟进而会给内存带来更多压力。

此问题的直接解决方法是将过载的类实例定义为静态类,或在其自己的文件中定义,从而移除隐式引用。

另一个解决方法是将?AsyncTask?对象声明为静态嵌套类(或在 Kotlin 中移除内部限定符)。这样做可以消除隐式引用问题,因为静态嵌套类与内部类有所不同:内部类的实例要求对外部类的实例进行实例化,并且可直接访问封装实例的方法和字段。相反,静态嵌套类不需要引用封装类的实例,因此它不包含对外部类成员的引用。

public class MainActivity extends Activity {

// …

static public class MyAsyncTask extends AsyncTask<Void, Void, String> {

@Override protected String doInBackground(Void… params) {…}

@Override protected void onPostExecute(String result) {…}

}

}

线程和应用 Activity 生命周期


应用生命周期会影响线程处理在应用中的工作方式。您可能需要确定线程在 Activity 销毁后应不应该保留。您还应注意线程优先级与 Activity 是在前台运行还是在后台运行之间的关系。

保留线程

线程会在生成这些线程的 Activity 的生命周期过后继续保留。无论是否发生 Activity 创建或销毁事件,线程都会继续不间断地执行。在某些情况下,这种持久性是可取的。

假设某个 Activity 生成了一组线程处理工作块,然后在工作线程能执行工作块之前被销毁。应用应如何处理正在执行的工作块?

如果工作块将要更新不再存在的界面,则该工作不必再继续。例如,如果该工作是从数据库加载用户信息,然后更新视图,则不再需要该线程。

相比之下,工作数据包可能具有某种不完全与界面相关的优势。在这种情况下,您应该保留该线程。例如,数据包可能正在等待下载图片,将其缓存到磁盘并更新关联的?View?对象。虽然该对象已不存在,但是下载和缓存该图片可能仍然有用,以防用户返回到已销毁的 Activity。

为所有线程处理对象手动管理生命周期响应可能极其复杂。如果管理不当,应用可能会遇到内存争用和性能问题。您可以结合使用?ViewModel?和?LiveData加载数据并在数据发生更改时收到通知,而不用关心生命周期。ViewModel?对象是此问题的一种解决方案。ViewModel 会在配置更改后保持不变,便于您保留视图数据。要详细了解 ViewModel 和 LiveData,请分别参阅?ViewModel 指南和?LiveData 指南。如果您还想详细了解应用架构,请参阅应用架构指南

线程优先级

应用线程的优先级一定程度上取决于应用处于生命周期的哪个阶段。在应用中创建和管理线程时,请务必设置线程的优先级,以便正确的线程适时获得正确的优先级。如果设置得过高,您的线程可能会干扰界面线程和 RenderThread,导致应用掉帧。如果设置得过低,可能会导致异步任务(例如图片加载)达不到所需的速度。

每次创建线程时,都应调用?setThreadPriority()。系统的线程调度程序会优先考虑优先级较高的线程,在这些优先级与最终将所有工作都完成的需求之间做出权衡。一般来说,前台组约占设备总执行时间的 95%,而后台组约占 5%。

系统还会使用?Process?类为每个线程分配系统自己的优先级值。

默认情况下,系统会将线程的优先级设置为与生成它的线程具有相同的优先级和组成员资格。但是,您的应用可以使用?setThreadPriority()?明确调整线程优先级。

Process?类提供了一组可供您的应用设置线程优先级的常量,以帮助简化优先级值的分配。例如,THREAD_PRIORITY_DEFAULT?代表线程的默认值。如果线程执行的工作不太紧急,应用应将线程的优先级设为?THREAD_PRIORITY_BACKGROUND

应用可以使用?THREAD_PRIORITY_LESS_FAVORABLE?和?THREAD_PRIORITY_MORE_FAVORABLE?常量作为增量器来设置相对优先级。如需线程优先级的列表,请参阅?Process类中的?THREAD_PRIORITY?常量。

如需详细了解如何管理线程,请参阅有关?Thread?和?Process类的参考文档。

线程处理的辅助类


框架提供了相同的 Java 类和基元来方便线程处理,例如?ThreadRunnable和?Executors类。为了帮助减轻与开发适用于 Android 的线程处理应用相关的认知负荷,框架提供了一组可协助开发的辅助程序,例如?AsyncTaskLoader?和?AsyncTask。每个辅助类都有一组特定的性能细微差别,专用于解决一小部分特定的线程处理问题。将错误的类用在错误的场合可能会导致性能问题。

AsyncTask 类

对于需要快速将工作从主线程移动到工作线程的应用来说,AsyncTask?类是一个简单实用的基元。例如,输入事件可能会触发使用加载的位图更新界面的需求。AsyncTask对象可以将位图加载和解码分流到备用线程;处理完成后,AsyncTask对象可以设法回到主线程上接收工作以更新界面。

在使用?AsyncTask?时,请注意以下几个性能方面的要点。首先,默认情况下,应用会将其创建的所有?AsyncTask对象推送到单个线程中。因此,它们按顺序执行,而且与主线程一样,特别长的工作数据包可能会阻塞队列。鉴于这个原因,我们建议您仅使用?AsyncTask?处理持续时间短于 5ms 的工作项。

对于隐式引用问题,AsyncTask?对象也是最常见的诱因。AsyncTask?对象也会带来与显式引用相关的风险,但这些风险有时更容易解决。例如,AsyncTask?可能需要引用某个界面对象,以便?AsyncTask?在主线程上执行其回调后正确更新该界面对象。在这种情况下,您可以使用WeakReference存储对所需界面对象的引用,并在?AsyncTask?在主线程上运行后访问该对象。注意,保留对一个对象的?WeakReference?不会使该对象变为线程安全;WeakReference?仅提供一种处理显式引用和垃圾回收问题的方法。

HandlerThread 类

虽然?AsyncTask?很有用,但对您的线程处理问题来说,它可能并不一定是正确的解决方案。相反,您可能需要采用更传统的方法在更长时间运行的线程上执行工作块,并且能够手动管理该工作流。

想一想从您的?Camera?对象获取预览帧时遇到的常见问题。当您注册 Camera 预览帧时,您会在?onPreviewFrame()?回调中收到这些帧,该回调在调用了它的事件线程上被调用。如果该回调是在界面线程上调用的,则处理大型像素矩阵的任务会干扰渲染和事件处理工作。AsyncTask?也存在同样的问题,它也是按顺序执行作业,并且容易出现阻塞。

这种情况适合采用处理程序线程:处理程序线程实际上是一个长时间运行的线程,会从队列中抓取工作并对其进行操作。在此示例中,当您的应用将?Camera.open()?命令委托给处理程序线程上的工作块时,关联的?onPreviewFrame()?回调会进入处理程序线程,而不是界面或?[AsyncTask]( )?线程。因此,如果要对像素执行长时间运行的工作,这可能是更好的解决方案。

当您的应用使用?HandlerThread?创建线程时,别忘了根据线程正在执行的工作类型设置其优先级。请记住,CPU 只能并行处理少量线程。设置优先级有助于系统了解当所有其他线程都在争取关注时调度此工作的正确方法。

ThreadPoolExecutor 类

某些类型的工作可以简化为高度并行的分布式任务。例如,为 800 万像素图片的每个 8x8 块计算滤镜就是这样的一个任务。鉴于这会创建大量的工作数据包,AsyncTask?和?HandlerThread?类并不合适。具有单线程处理特性的?AsyncTask?会将所有线程池化的工作转化为一个线性系统。另一方面,使用?HandlerThread?类需要程序员在一组线程之间手动实现负载平衡。

Android开发除了flutter还有什么是必须掌握的吗?

相信大多数从事Android开发的朋友们越来越发现,找工作越来越难了,面试的要求越来越高了

除了基础扎实的java知识,数据结构算法,设计模式还要求会底层源码,NDK技术,性能调优,还有会些小程序和跨平台,比如说flutter,以思维脑图的方式展示在下图;

点击文档前往获取面试资料与视频教程;【阿里P7级别Android架构师技术脑图+全套视频】

5%8F%91%E4%B8%8D%E4%BC%9A%E8%BF%99%E4%BA%9B%EF%BC%9F%E5%A6%82%E4%BD%95%E9%9D%A2%E8%AF%95%E6%8B%BF%E9%AB%98%E8%96%AA%EF%BC%81.md)**

[外链图片转存中…(img-6e8bDlDM-1645101980522)]

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-19 01:17:18  更:2022-02-19 01:18:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 14:47:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码