- 浏览: 561474 次
- 来自: -
博客专栏
-
libgdx 游戏开发
浏览量:12247
文章分类
- 全部博客 (171)
- OS (1)
- JavaScript (13)
- Struts (2)
- Regular Expression (1)
- Java (14)
- HTML (4)
- XML (1)
- Non-Relational Database (2)
- Miscellaneous (7)
- Lotus Notes (8)
- Algorithm (3)
- Web Analytics (6)
- Web (8)
- Perl (3)
- PHP (3)
- C & C++ (1)
- Shell (7)
- Google (1)
- Android (31)
- iPhone (1)
- SQL (1)
- HTML5 (3)
- jQuery (6)
- CSS (6)
- PostgreSQL (1)
- Design Patterns (1)
- Excel (1)
- Magento (4)
- jMeter (3)
- SEO (1)
- libgdx (5)
- Software (4)
- App (1)
- Game (1)
- Gradle (1)
- Linux (16)
- Ubuntu (4)
- Docker (2)
- Spring (2)
- Other (3)
- Directory Server (1)
- CentOS (1)
- Python (1)
- VCS (3)
- Database (1)
- Open Source (1)
最新评论
-
ls0609:
赞一个,支持下博主。
[原创] Android ListView 在右上角添加三角形图标和文字 -
love297:
不让别人商用,自己先商用起来了。
手机游戏开发展示 -
a851206:
你的有些类是哪里来的?我想研究一下你的程序,可是有些类没有代码 ...
[原创] Google Custom Search & Yahoo Boss Search | Web Search API 使用 -
ypppk:
BitmapFactory.Options options = ...
[原创] 连载 1 - 深入讨论 Android 关于高效显示图片的问题 - 如何高效的加载大位图 -
笑遍世界:
我也遇到了,弄清了其中原因,可参考我的博客:http://sm ...
[原创] 使用 jMeter 登录 Wordpress
[原创] 连载 2 - 深入讨论 Android 关于高效显示图片的问题 - 如何在非 UI 线程处理位图
- 博客分类:
- Android
更加详细的说明,可以参阅如下官网地址:http://developer.android.com/training/building-graphics.html
快速导航
1. 如何高效的加载大位图。(如何解码大位图,避免超过每个应用允许使用的最大内存)http://yhz61010.iteye.com/blog/1848337
2. 如何在非 UI 线程处理位图。(如何使用 AsyncTask 在后台线程处理位图及处理并发问题)http://yhz61010.iteye.com/blog/1848811
3. 如何对位图进行缓存。(如何通过创建内存缓存和磁盘缓存来流畅的显示多张位图)http://yhz61010.iteye.com/blog/1849645
4. 如何管理位图内存。(如何针对不同的 Android 版本管理位图内存)http://yhz61010.iteye.com/blog/1850232
5. 如何在 UI 中显示位图。(如何通过 ViewPager 和 GridView 显示多张图片)http://yhz61010.iteye.com/blog/1852927
如何在非 UI 线程处理位图?
前一篇文章http://yhz61010.iteye.com/blog/1848337提到的 BitmapFactory.decode* 方法,不应该在主 UI 线程被调用(除非位图来源是内存),因为加载位置的时间不可预知的,而且还依赖于很多其它因素(例如,磁盘或网络的读取时间,图片大小,CPU 功率等)。无论上述任何一个因素导致 UI 线程被阻塞,那么系统会将此程序标记成无响应状态,此时用户有权关闭该程序。
本文将引导你如何使用 AsyncTask 在后台线程处理位图,并且将为你演示如何处理并发问题。
使用 AsyncTask
AsyncTask 类让我们可以使用简单的方法就可以在后台线程执行一些任务,并在处理完成后将结果反馈到 UI 线程。使用该类,需要创建一个它的子类,并覆写一些方法即可。下面为大家演示如何使用 AsyncTask 和 decodeSampledBitmapFromResource() 为 ImageView 设置一张大图片:
其中,指向 ImageView 的 WeakReference 引用是为了确保 AsyncTask 允许对 ImageView 和任何指向它的引用进行垃圾回收。由于无法保证将后台任务执行完成时,ImageView 依然可用(例如,用户可能会在后台任务执行时离开了当前页面或者对页面进行了其它操作导致无法找到 ImageView),所以我们必须在 onPostExecute() 方法中,检查引用的可用性。
只需向下面这样简单的创建一个任务,并执行该任务,就可以实现异步加载位图:
并发处理
某些共通视图组件,例如 ListView 和 GridView,若像上面那样将它们和 AsyncTask 连用时,就会遇到新的问题。为了高效的利用内存,当用户在上述组件中进行滚动时,这些组件会重用其中的子视图。如果每个子视图触发一个 AsyncTask,那么我们无法保证在任务执行完成时,触发该任务的子视图没有被其它子视图使用。此处,我们也无法保证任务执行完成的顺序和调用的顺序的一致性。
Multithreading for Performance 这篇文章(可能需要代理才能访问:http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html)深入的讨论了如何解决并发问题,并且提供了一种解决方法,就是在使用 ImageView 的地方,保存一个指向最近被使用的 AsyncTask 引用,当这个任务完成时,可以检查 AsyncTask。使用如之类似的方法,我们可以将前面使用过的 AsyncTask 进行扩展来达到我们的目前:
在执行 BitmapWorkerTask 之前,我们可以先创建一个 AsyncDrawable 然后将它绑定到所需的 ImageView 上:
上述方法中的 cancelPotentialWork 方法用于检查是否有其它正在运行的任务关联到当前的 ImageView 上。如果有其它正在运行的任务关联到当前的 ImageView 上,那么就可以调用 cancel() 方法来尝试取消先前的任务。在某些情况下,新任务的中的 data 和已经存在的任务的 data 相同,此时就不需要做任何处理。下面是 cancelPotentialWork 方法的具体实现:
该示例中使用到的 getBitmapWorkerTask() 方法,会接收一个与任务相关联的 ImageView:
最后一步是更新 BitmapWorkerTask 中的 onPostExecute() 方法,在该方法中检查任务是否需要已经被取消,并且还要检查当前任务是否与关联的 ImageView 相匹配:
综上所述,经过修改后的代码实现,可以适用于 ListView 和 GridView 组件,以及任何其它会重复使用它们子视图的组件。具体做法也很简单,只需要在原来为 ImageView 设值的地方调用 loadBitmap 方法即可。例如,在实现 GridView 时,在返回的 adapter 中的 getView() 方法中调用上述方法即可。
快速导航
1. 如何高效的加载大位图。(如何解码大位图,避免超过每个应用允许使用的最大内存)http://yhz61010.iteye.com/blog/1848337
2. 如何在非 UI 线程处理位图。(如何使用 AsyncTask 在后台线程处理位图及处理并发问题)http://yhz61010.iteye.com/blog/1848811
3. 如何对位图进行缓存。(如何通过创建内存缓存和磁盘缓存来流畅的显示多张位图)http://yhz61010.iteye.com/blog/1849645
4. 如何管理位图内存。(如何针对不同的 Android 版本管理位图内存)http://yhz61010.iteye.com/blog/1850232
5. 如何在 UI 中显示位图。(如何通过 ViewPager 和 GridView 显示多张图片)http://yhz61010.iteye.com/blog/1852927
如何在非 UI 线程处理位图?
前一篇文章http://yhz61010.iteye.com/blog/1848337提到的 BitmapFactory.decode* 方法,不应该在主 UI 线程被调用(除非位图来源是内存),因为加载位置的时间不可预知的,而且还依赖于很多其它因素(例如,磁盘或网络的读取时间,图片大小,CPU 功率等)。无论上述任何一个因素导致 UI 线程被阻塞,那么系统会将此程序标记成无响应状态,此时用户有权关闭该程序。
本文将引导你如何使用 AsyncTask 在后台线程处理位图,并且将为你演示如何处理并发问题。
使用 AsyncTask
AsyncTask 类让我们可以使用简单的方法就可以在后台线程执行一些任务,并在处理完成后将结果反馈到 UI 线程。使用该类,需要创建一个它的子类,并覆写一些方法即可。下面为大家演示如何使用 AsyncTask 和 decodeSampledBitmapFromResource() 为 ImageView 设置一张大图片:
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { private final WeakReference<ImageView> imageViewReference; private int data = 0; public BitmapWorkerTask(ImageView imageView) { // Use a WeakReference to ensure the ImageView can be garbage collected imageViewReference = new WeakReference<ImageView>(imageView); } // Decode image in background. @Override protected Bitmap doInBackground(Integer... params) { data = params[0]; return decodeSampledBitmapFromResource(getResources(), data, 100, 100)); } // Once complete, see if ImageView is still around and set bitmap. @Override protected void onPostExecute(Bitmap bitmap) { if (imageViewReference != null && bitmap != null) { final ImageView imageView = imageViewReference.get(); if (imageView != null) { imageView.setImageBitmap(bitmap); } } } }
其中,指向 ImageView 的 WeakReference 引用是为了确保 AsyncTask 允许对 ImageView 和任何指向它的引用进行垃圾回收。由于无法保证将后台任务执行完成时,ImageView 依然可用(例如,用户可能会在后台任务执行时离开了当前页面或者对页面进行了其它操作导致无法找到 ImageView),所以我们必须在 onPostExecute() 方法中,检查引用的可用性。
只需向下面这样简单的创建一个任务,并执行该任务,就可以实现异步加载位图:
public void loadBitmap(int resId, ImageView imageView) { BitmapWorkerTask task = new BitmapWorkerTask(imageView); task.execute(resId); }
并发处理
某些共通视图组件,例如 ListView 和 GridView,若像上面那样将它们和 AsyncTask 连用时,就会遇到新的问题。为了高效的利用内存,当用户在上述组件中进行滚动时,这些组件会重用其中的子视图。如果每个子视图触发一个 AsyncTask,那么我们无法保证在任务执行完成时,触发该任务的子视图没有被其它子视图使用。此处,我们也无法保证任务执行完成的顺序和调用的顺序的一致性。
Multithreading for Performance 这篇文章(可能需要代理才能访问:http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html)深入的讨论了如何解决并发问题,并且提供了一种解决方法,就是在使用 ImageView 的地方,保存一个指向最近被使用的 AsyncTask 引用,当这个任务完成时,可以检查 AsyncTask。使用如之类似的方法,我们可以将前面使用过的 AsyncTask 进行扩展来达到我们的目前:
static class AsyncDrawable extends BitmapDrawable { private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { super(res, bitmap); bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(bitmapWorkerTask); } public BitmapWorkerTask getBitmapWorkerTask() { return bitmapWorkerTaskReference.get(); } }
在执行 BitmapWorkerTask 之前,我们可以先创建一个 AsyncDrawable 然后将它绑定到所需的 ImageView 上:
public void loadBitmap(int resId, ImageView imageView) { if (cancelPotentialWork(resId, imageView)) { final BitmapWorkerTask task = new BitmapWorkerTask(imageView); final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), mPlaceHolderBitmap, task); imageView.setImageDrawable(asyncDrawable); task.execute(resId); } }
上述方法中的 cancelPotentialWork 方法用于检查是否有其它正在运行的任务关联到当前的 ImageView 上。如果有其它正在运行的任务关联到当前的 ImageView 上,那么就可以调用 cancel() 方法来尝试取消先前的任务。在某些情况下,新任务的中的 data 和已经存在的任务的 data 相同,此时就不需要做任何处理。下面是 cancelPotentialWork 方法的具体实现:
public static boolean cancelPotentialWork(int data, ImageView imageView) { final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); if (bitmapWorkerTask != null) { final int bitmapData = bitmapWorkerTask.data; if (bitmapData != data) { // Cancel previous task bitmapWorkerTask.cancel(true); } else { // The same work is already in progress return false; } } // No task associated with the ImageView, or an existing task was cancelled return true; }
该示例中使用到的 getBitmapWorkerTask() 方法,会接收一个与任务相关联的 ImageView:
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { if (imageView != null) { final Drawable drawable = imageView.getDrawable(); if (drawable instanceof AsyncDrawable) { final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; return asyncDrawable.getBitmapWorkerTask(); } } return null; }
最后一步是更新 BitmapWorkerTask 中的 onPostExecute() 方法,在该方法中检查任务是否需要已经被取消,并且还要检查当前任务是否与关联的 ImageView 相匹配:
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { ... @Override protected void onPostExecute(Bitmap bitmap) { if (isCancelled()) { bitmap = null; } if (imageViewReference != null && bitmap != null) { final ImageView imageView = imageViewReference.get(); final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); if (this == bitmapWorkerTask && imageView != null) { imageView.setImageBitmap(bitmap); } } } }
综上所述,经过修改后的代码实现,可以适用于 ListView 和 GridView 组件,以及任何其它会重复使用它们子视图的组件。具体做法也很简单,只需要在原来为 ImageView 设值的地方调用 loadBitmap 方法即可。例如,在实现 GridView 时,在返回的 adapter 中的 getView() 方法中调用上述方法即可。
发表评论
-
[转] DialogFragment Fragment already added
2017-10-25 11:16 2749原文地址:http://blog.csdn.net/u0129 ... -
Android Studio .gitignore
2017-10-16 15:44 909参考文献: https://github.com/github ... -
[转] How to detect incoming calls in an Android
2017-10-13 14:14 1234原文地址:https://stackoverflow.com/ ... -
[转] Android 检测电源按钮是否被按下
2017-10-11 12:55 1061原文地址:https://stackoverflow.com/ ... -
[原创] Android Activity onNewIntent() 详解
2017-08-16 13:46 4807阅读难度:中 阅读前提: 1. 需要了解 Android 的生 ... -
[转] Android Webview: “Uncaught TypeError: Cannot read property 'getItem' of null
2017-08-14 15:09 2360原文地址:https://stackoverflow.com/ ... -
[原创] 使用 Vitamio 播放视频作为 Splash 时出现失真情况的解决方案
2017-08-02 09:10 1228目前在做关于视频及流媒体播放项目时,有这样一个需求,应用启动时 ... -
[转] Android: Expand/collapse animation
2017-07-31 14:57 1590原文地址:https://stackoverflow.com/ ... -
[原创] Android ListView 在右上角添加三角形图标和文字
2017-07-26 17:24 2790最终显示效果如下图,在右上角添加三角形图标并在图标内显示文字: ... -
[转] Detect home button press in android
2017-07-20 17:49 1189原文地址:https://stackoverflow.com/ ... -
[原创] 开启 Android TextView Marquee
2017-07-18 15:47 1829亲测可能。直接上代码。 测试机器:XiaoMi 2S Andr ... -
[原创] 小米手机无法真机调试
2017-07-06 09:10 6508系统环境: 小米 2S MIUI 版本:8.0.1.0(LXA ... -
了解数据绑定 - Data Binding Library
2017-06-22 15:31 984原文地址: -
How to play gif with Fresco
2017-06-22 14:00 674原文地址:https://stackoverflow.com/ ... -
设置 Toolbar(ActionBar) 上的按钮颜色
2017-06-22 08:11 2092原文地址: https://stackoverflow.com ... -
Display back button on action bar and back event
2017-06-22 08:00 768原文地址: https://stackoverflow.com ... -
Gradle 修改 Maven 仓库地址
2017-06-02 15:51 1696修改 Gradle Maven 仓库地址为阿里云镜像 修改根 ... -
[转] How to clear cookies and cache of webview on Android when not in webview?
2017-04-26 09:28 2211原文地址:http://stackoverflow.com/a ... -
[转] Android 在程序中如何动态的修改程序图标
2017-03-02 17:05 956http://stackoverflow.com/a/4150 ... -
[转] Android Libraries
2017-01-16 10:28 576原文地址: https://dzone.com/article ...
相关推荐
4. 处理线程问题:库会自动处理线程切换,确保在UI线程中显示Dialog,避免出现异常。 5. 监听用户操作:为Dialog的按钮或其他交互元素设置监听器,处理用户的点击事件。 在压缩包中的`AndroidDialogDemo-master`...
在Qt框架中,多线程技术是实现高效并发处理的关键,尤其在数据处理和用户界面(UI)更新方面。这个实例“qt多线程实例-数据处理和UI界面显示”很可能是为了展示如何在不阻塞UI的情况下进行繁重的数据处理任务。 在...
线程在Android中扮演着处理后台任务的重要角色,它可以避免因为长时间运行操作而阻塞主线程,确保UI的流畅性。 首先,我们需要理解Android的线程模型。主线程,也被称为UI线程,负责处理所有的用户交互,如触摸事件...
本篇文章将深入探讨如何通过委托在子线程中更新UI界面。 1. **多线程基础知识** - 线程:线程是程序中的执行流,每个进程至少有一个线程。 - 主线程:应用程序启动时创建的第一个线程,负责处理UI交互和事件。 -...
开发者应遵循“密度独立像素”(DP,Density-independent Pixel)的原则,确保图片在各种屏幕尺寸下显示一致。通常,需要为每个密度提供相应尺寸的图片,避免因拉伸导致的模糊。 在UI设计中,图标的设计是一大重点...
在Android应用开发中,UI线程(也称为主线程)负责处理用户界面的交互,而后台线程则用于执行耗时操作,如网络请求、数据库操作等,以避免阻塞UI,保证用户界面的流畅性。当后台线程完成耗时操作后,通常需要将结果...
不过,由于线程安全问题,直接在非UI线程上修改UI组件可能会导致异常,因此我们需要使用`Control.Invoke`或`Control.BeginInvoke`方法来安全地在UI线程上执行更新UI的操作。 接下来,我们讨论UI更新。在Windows ...
在Windows Presentation Foundation(WPF)开发中,UI(用户界面)通常由主线程管理,而后台线程用于执行耗时的任务。然而,由于GUI组件不是线程安全的,直接在后台线程修改UI元素可能会导致应用程序崩溃或出现不可...
在Android开发中,将网络上的图片加载到ImageView控件上是一项常见的需求,特别是在构建社交应用、电商应用或者新闻阅读类应用时。这个过程涉及到多个关键知识点,包括网络请求、图片缓存策略、线程管理以及UI更新等...
在Android开发中,大位图(Bitmap)的处理是一个重要的技术点,特别是在处理高分辨率图像或者需要显示大量图片的应用中。由于Android系统对内存管理的限制,直接加载大位图可能导致应用崩溃,这就是著名的"Out of ...
在Android开发中,由于UI操作必须在主线程(也称为UI线程)中进行,因此在后台线程处理任务并更新界面时需要遵循特定的机制。以下是对标题和描述中涉及知识点的详细解释: 1. **线程模型**: Android系统采用单...
在深入探讨Android中的多线程处理之前,我们需要先理解Android的基本进程和线程模型。 **Android进程:** 当一个Android应用首次启动时,系统会为该应用创建一个Linux进程。此进程中包含了应用的主要线程——主线程...
通过学习这个实例,开发者可以掌握如何在多线程环境中正确处理UI更新,避免出现线程安全问题,提高应用程序的响应性和用户体验。 总结来说,C# WinForm应用中的跨线程修改UI是通过异步编程和UI线程同步机制来实现的...
在Android开发中,线程处理UI的理解是至关重要的,因为它涉及到应用程序的性能和用户体验。"线程处理UI的理解Demo"这个主题旨在通过实例演示如何在Android环境中正确地管理线程,特别是与用户界面(UI)交互时。在这...
Android系统默认的主线程(Main Thread)负责处理UI交互,如果在这个线程中执行耗时操作,会阻塞UI更新,导致应用无响应(ANR)。因此,了解如何在Android中正确地在后台线程处理任务并动态更新UI是开发者必备的技能...
在Android应用开发中,线程管理和UI更新是至关重要的部分,因为Android系统为每个应用程序分配一个主线程,也称为UI线程。主线程主要负责处理用户界面的交互,包括绘制和更新视图。然而,执行耗时的操作(如网络请求...
在Qt编程中,UI(用户界面)的更新通常在主线程中进行,因为GUI(图形用户界面)组件的渲染和事件处理是与主线程紧密关联的。然而,当执行耗时的操作,如网络请求、大数据处理或长时间计算时,如果在主线程中执行,...
这个主题“安卓开发-演化理解 Android 异步加载图片”涵盖了如何在Android平台上高效地处理图片加载,避免UI线程阻塞,提高应用性能。下面我们将详细探讨这一领域的多个知识点。 1. UI线程与工作线程: Android...
在Android开发中,异步...通过分析这个压缩包中的源码,开发者可以深入了解Android图片异步加载的各个层面,提高自己在处理图片加载问题上的能力。无论是使用开源库还是自定义解决方案,都能从中获得宝贵的实践经验。
在C#编程中,开发Windows桌面应用程序时,我们经常遇到多线程操作,尤其是在WinForms应用中。当后台线程需要更新用户界面(UI)时,由于.NET Framework的安全机制,直接操作UI控件会引发“Cross-thread operation ...