- 浏览: 550488 次
- 来自: -
博客专栏
-
libgdx 游戏开发
浏览量:11947
文章分类
- 全部博客 (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 2607原文地址:http://blog.csdn.net/u0129 ... -
Android Studio .gitignore
2017-10-16 15:44 834参考文献: https://github.com/github ... -
[转] How to detect incoming calls in an Android
2017-10-13 14:14 1167原文地址:https://stackoverflow.com/ ... -
[转] Android 检测电源按钮是否被按下
2017-10-11 12:55 955原文地址:https://stackoverflow.com/ ... -
[原创] Android Activity onNewIntent() 详解
2017-08-16 13:46 4719阅读难度:中 阅读前提: 1. 需要了解 Android 的生 ... -
[转] Android Webview: “Uncaught TypeError: Cannot read property 'getItem' of null
2017-08-14 15:09 2244原文地址:https://stackoverflow.com/ ... -
[原创] 使用 Vitamio 播放视频作为 Splash 时出现失真情况的解决方案
2017-08-02 09:10 1180目前在做关于视频及流媒体播放项目时,有这样一个需求,应用启动时 ... -
[转] Android: Expand/collapse animation
2017-07-31 14:57 1537原文地址:https://stackoverflow.com/ ... -
[原创] Android ListView 在右上角添加三角形图标和文字
2017-07-26 17:24 2676最终显示效果如下图,在右上角添加三角形图标并在图标内显示文字: ... -
[转] Detect home button press in android
2017-07-20 17:49 1145原文地址:https://stackoverflow.com/ ... -
[原创] 开启 Android TextView Marquee
2017-07-18 15:47 1779亲测可能。直接上代码。 测试机器:XiaoMi 2S Andr ... -
[原创] 小米手机无法真机调试
2017-07-06 09:10 6451系统环境: 小米 2S MIUI 版本:8.0.1.0(LXA ... -
了解数据绑定 - Data Binding Library
2017-06-22 15:31 897原文地址: -
How to play gif with Fresco
2017-06-22 14:00 629原文地址:https://stackoverflow.com/ ... -
设置 Toolbar(ActionBar) 上的按钮颜色
2017-06-22 08:11 2036原文地址: https://stackoverflow.com ... -
Display back button on action bar and back event
2017-06-22 08:00 714原文地址: https://stackoverflow.com ... -
Gradle 修改 Maven 仓库地址
2017-06-02 15:51 1624修改 Gradle Maven 仓库地址为阿里云镜像 修改根 ... -
[转] How to clear cookies and cache of webview on Android when not in webview?
2017-04-26 09:28 2165原文地址:http://stackoverflow.com/a ... -
[转] Android 在程序中如何动态的修改程序图标
2017-03-02 17:05 883http://stackoverflow.com/a/4150 ... -
[转] Android Libraries
2017-01-16 10:28 538原文地址: https://dzone.com/article ...
相关推荐
Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面。
Xamarin.Android 非UI线程更新UI
qt多线程实例-数据处理和UI界面显示
dialog库,可以在任意类内调用,子线程或ui线程内均可显示
ndroid异步处理一:使用Thread+Handler实现非UI线程更新UI界面
1.2项目概述本文档适用于“中兴Android系统界面软件设计与开发”项目(以下简称“AndroidUI项目”)的开发过程 1.3文档概述本文档依据国家标准《G
Android-awesome-android-ui.zip,一份精选的android ui/ux库列表,安卓系统是谷歌在2008年设计和制造的。操作系统主要写在爪哇,C和C 的核心组件。它是在linux内核之上构建的,具有安全性优势。
•Android---UI篇---Tab Layout(选项卡布局) ...•Android---UI篇---ListView之ArrayAdapter(列表)---2 • •Android---UI篇---ListView之SimpleCursorAdapter(列表)---3 • •Android---UI篇---Menu(菜单)
1、查看网络上的图片 2、主线程阻塞-ANR 3、刷新UI-Handler 4、在本地缓存图片-例如微信的图片 5、获取开源代码 6、显示一个新闻客户端 7、使用GET方式提交表单数据 8、使用POST方式提交表单
010_android 之UI线程阻塞及其优化视频教材,讲解的比较详细,有兴趣的可以学习下哦。
在C#中,由于使用线程和调用UI的线程属于两个不同的线程,如果在线程中直接设置UI元素的属性,此时就会出现跨线程错误。 下面介绍两种解决方案 第一种:使用控件自带的Invoke或者BeginInvoke方法。 Task....
用于为Office和Office 365构建体验的Android UI框架。
Android ,非MainActivity类中的子线程和UI线程通讯,并且获取子线程传递的信息,更新UI界面。需要使用okHttp类库
Android 线程 更新UI 操作UI
1.2 项目概述本文档适用于“中兴Android系统界面软件设计与开发”项目(以下简称“AndroidUI项目”)的开发过程 1.3 文档概述本文档依据国家标准
WinForm后台线程与UI线程通讯 实现进度条变化
android UI界面开发图片,数量巨大,而且经典,觉得值得收藏 android UI界面开发图片,数量巨大,而且经典,觉得值得收藏
用MFC實現 UI线程,在UI線程中 工作 大量計算,并 用Static 顯示进度。同时把 进度 返回 主线程,让主线程 用进度条 显示进度,达到 工作的时候 主线程 可以自由拖动。
android UI线程和后台线程交互,包括多线程之AsyncTask等例子展示。。。。。。。。。。。
1.2项目概述本文档适用于“中兴Android系统界面软件设计与开发”项目(以下简称“AndroidUI项目”)的开发过程 1.3文档概述本文档依据国家标准《G