- 浏览: 447176 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (267)
- java (8)
- 求职&面试 (1)
- linux (33)
- windows (1)
- C++ (5)
- android (12)
- QT (1)
- 经验 (1)
- memory-leaks (1)
- Streaming&V/A (1)
- network&security (5)
- SCM (13)
- mysql (10)
- browsers (4)
- Windows APIs (2)
- opensource (1)
- pm (1)
- GDI (1)
- database (14)
- MFC (1)
- web&fronts (17)
- Tomcat (4)
- OLE (1)
- 观后感 (1)
- Production (2)
- UML (3)
- Javascript (7)
- Cloud Computing&SAAS (5)
- SoftwareEngineering (1)
- Computer&Maintenance (1)
- Web (8)
- Desgin (1)
- J2ee (10)
- mysql cluster (0)
- LB&HA (2)
- webserver (11)
- php (5)
- cas&authtication (0)
- Languages (1)
- IDEs (3)
- architecture (2)
- iOS (8)
- spring (3)
- webservices (1)
- security (1)
- MVCFrameworks (2)
- bservices (0)
- build-tools (2)
- unittest (1)
- spring-security (0)
- sphinx (2)
- hibernate (1)
- mybatis (2)
- search (0)
- nginx (2)
- design&production (2)
- DFS (0)
- algorithm (0)
- distributed&network (0)
- blogs (0)
- os&admin (0)
- fastcgi (0)
- kv-db (0)
- operation&maintenance (1)
- productions (9)
- 养生 (1)
- appserver (1)
- HTTP (2)
- test (1)
- erlang (2)
- browser (0)
- 非技术 (2)
- mobiles (2)
- cloud computing (2)
- Business (2)
- maven (1)
- python (5)
- 人生 (0)
- Cryptography (3)
- CV (0)
- cms (2)
- jqm (2)
- html (2)
- flex (1)
- redmine (1)
- iptables (1)
- groovy (1)
- scala (1)
- grails (1)
- ftp (3)
- vsftpd (2)
- lua (0)
- chroot (3)
- jailkit (3)
- UED (0)
- myeclipse (2)
- ide (2)
- eclipse (2)
最新评论
-
Nick712:
http://blog.csdn.net/victory08/ ...
处理SVN出现:Cleanup failed to process the following paths: xxx -
xs6262460:
Spring AOP根据JdbcTemplate方法名动态设置数据源 -
xhpscdx:
我的解决办法是把D:\ACRS\Projects\TAIS 下 ...
处理SVN出现:Cleanup failed to process the following paths: xxx -
hnraysir:
总结得相当不错,支持下。
使用CodeIgniter 创建 RESTful 服务 REST API【原创译文】 -
云上太阳:
这个必须评论下,间接的救过俺的命啊
解决tomcat启动报错,加强错误日志的显示:
在学习"Android异步加载图像小结 "这篇文章时, 发现有些地方没写清楚,我就根据我的理解,把这篇文章的代码重写整理了一遍,下面就是我的整理。
下面测试使用的layout文件:
简单来说就是 LinearLayout 布局,其下放了5个ImageView。
<?xml version="1.0 " encoding="utf-8 "?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android " android:orientation="vertical " android:layout_width="fill_parent " android:layout_height="fill_parent "> <TextView android:text="图片区域开始 " android:id="@+id/textView2 " android:layout_width="wrap_content " android:layout_height="wrap_content "></TextView> <ImageView android:id="@+id/imageView1 " android:layout_height="wrap_content " android:src="@drawable/icon " android:layout_width="wrap_content "></ImageView> <ImageView android:id="@+id/imageView2 " android:layout_height="wrap_content " android:src="@drawable/icon " android:layout_width="wrap_content "></ImageView> <ImageView android:id="@+id/imageView3 " android:layout_height="wrap_content " android:src="@drawable/icon " android:layout_width="wrap_content "></ImageView> <ImageView android:id="@+id/imageView4 " android:layout_height="wrap_content " android:src="@drawable/icon " android:layout_width="wrap_content "></ImageView> <ImageView android:id="@+id/imageView5 " android:layout_height="wrap_content " android:src="@drawable/icon " android:layout_width="wrap_content "></ImageView> <TextView android:text="图片区域结束 " android:id="@+id/textView1 " android:layout_width="wrap_content " android:layout_height="wrap_content "></TextView> </LinearLayout>
我们将演示的逻辑是异步从服务器上下载5张不同图片,依次放入这5个ImageView。上下2个TextView 是为了方便我们看是否阻塞了UI的显示。
当然 AndroidManifest.xml 文件中要配置好网络访问权限。
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Handler+Runnable模式
我们先看一个并不是异步线程加载的例子,使用 Handler+Runnable模式。
这里为何不是新开线程的原因请参看这篇文章:Android Runnable 运行在那个线程 这里的代码其实是在UI 主线程中下载图片的,而不是新开线程。
我们运行下面代码时,会发现他其实是阻塞了整个界面的显示,需要所有图片都加载完成后,才能显示界面。
package ghj1976.AndroidTest; import java.io.IOException; import java.net.URL; import android.app.Activity; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.util.Log; import android.widget.ImageView; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); loadImage("http://www.baidu.com/img/baidu_logo.gif ", R.id.imageView1); loadImage(http://www.chinatelecom.com.cn/images/logo_new.gif ", R.id.imageView2); loadImage("http://cache.soso.com/30d/img/web/logo.gif , R.id.imageView3); loadImage("http://csdnimg.cn/www/images/csdnindex_logo.gif ", R.id.imageView4); loadImage("http://images.cnblogs.com/logo_small.gif ", R.id.imageView5); } private Handler handler = new Handler(); private void loadImage(final String url, final int id) { handler.post(new Runnable() { public void run() { Drawable drawable = null ; try { drawable = Drawable.createFromStream( new URL(url).openStream(), "image.gif "); } catch (IOException e) { Log.d("test ", e.getMessage()); } if (drawable == null ) { Log.d("test ", "null drawable "); } else { Log.d("test ", "not null drawable "); } // 为了测试缓存而模拟的网络延时
SystemClock.sleep(2000);
((ImageView) MainActivity.this
.findViewById(id))
.setImageDrawable(drawable);
}
});
}
}
Handler+Thread+Message模式
这种模式使用了线程,所以可以看到异步加载的效果。
核心代码:
package ghj1976.AndroidTest; import java.io.IOException; import java.net.URL; import android.app.Activity; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.util.Log; import android.widget.ImageView; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); loadImage2("http://www.baidu.com/img/baidu_logo.gif ", R.id.imageView1); loadImage2("http://www.chinatelecom.com.cn/images/logo_new.gif ", R.id.imageView2); loadImage2("http://cache.soso.com/30d/img/web/logo.gif ", R.id.imageView3); loadImage2("http://csdnimg.cn/www/images/csdnindex_logo.gif ", R.id.imageView4); loadImage2("http://images.cnblogs.com/logo_small.gif ", R.id.imageView5); } final Handler handler2 = new Handler() { @Override public void handleMessage(Message msg) { ((ImageView) MainActivity.this .findViewById(msg.arg1)) .setImageDrawable((Drawable) msg.obj); } }; // 采用handler+Thread模式实现多线程异步加载 private void loadImage2(final String url, final int id) { Thread thread = new Thread() { @Override public void run() { Drawable drawable = null ; try { drawable = Drawable.createFromStream( new URL(url).openStream(), "image.png "); } catch (IOException e) { Log.d("test ", e.getMessage()); } // 模拟网络延时 SystemClock.sleep(2000); Message message = handler2.obtainMessage(); message.arg1 = id; message.obj = drawable; handler2.sendMessage(message); } }; thread.start(); thread = null ; } }
这时候我们可以看到实现了异步加载, 界面打开时,五个ImageView都是没有图的,然后在各自线程下载完后才把图自动更新上去。
Handler+ExecutorService(线程池)+MessageQueue模式
能开线程的个数毕竟是有限的,我们总不能开很多线程,对于手机更是如此。
这个例子是使用线程池。Android拥有与Java相同的ExecutorService实现,我们就来用它。
线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。
线程池的信息可以参看这篇文章:Java&Android的线程池-ExecutorService 下面的演示例子是创建一个可重用固定线程数的线程池。
核心代码
package ghj1976.AndroidTest; import java.io.IOException; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.app.Activity; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.util.Log; import android.widget.ImageView; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); loadImage3("http://www.baidu.com/img/baidu_logo.gif ", R.id.imageView1); loadImage3("http://www.chinatelecom.com.cn/images/logo_new.gif ", R.id.imageView2); loadImage3("http://cache.soso.com/30d/img/web/logo.gif ", R.id.imageView3); loadImage3("http://csdnimg.cn/www/images/csdnindex_logo.gif ", R.id.imageView4); loadImage3("http://images.cnblogs.com/logo_small.gif ", R.id.imageView5); } private Handler handler = new Handler(); private ExecutorService executorService = Executors.newFixedThreadPool(5); // 引入线程池来管理多线程 private void loadImage3(final String url, final int id) { executorService.submit(new Runnable() { public void run() { try { final Drawable drawable = Drawable.createFromStream( new URL(url).openStream(), "image.png "); // 模拟网络延时 SystemClock.sleep(2000); handler.post(new Runnable() { public void run() { ((ImageView) MainActivity.this .findViewById(id)) .setImageDrawable(drawable); } }); } catch (Exception e) { throw new RuntimeException(e); } } }); } }
这里我们象第一步一样使用了 handler.post(new Runnable() { 更新前段显示当然是在UI主线程,我们还有 executorService.submit(new Runnable() { 来确保下载是在线程池的线程中。
Handler+ExecutorService(线程池)+MessageQueue+缓存模式
下面比起前一个做了几个改造:
- 把整个代码封装在一个类中
- 为了避免出现同时多次下载同一幅图的问题,使用了本地缓存
封装的类:
package ghj1976.AndroidTest; import java.lang.ref.SoftReference; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.SystemClock; public class AsyncImageLoader3 { // 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动) public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>(); private ExecutorService executorService = Executors.newFixedThreadPool(5); // 固定五个线程来执行任务 private final Handler handler = new Handler(); /** * * @param imageUrl * 图像url地址 * @param callback * 回调接口 * @return 返回内存中缓存的图像,第一次加载返回null */ public Drawable loadDrawable(final String imageUrl, final ImageCallback callback) { // 如果缓存过就从缓存中取出数据 if (imageCache.containsKey(imageUrl)) { SoftReference<Drawable> softReference = imageCache.get(imageUrl); if (softReference.get() != null ) { return softReference.get(); } } // 缓存中没有图像,则从网络上取出数据,并将取出的数据缓存到内存中 executorService.submit(new Runnable() { public void run() { try { final Drawable drawable = loadImageFromUrl(imageUrl); imageCache.put(imageUrl, new SoftReference<Drawable>( drawable)); handler.post(new Runnable() { public void run() { callback.imageLoaded(drawable); } }); } catch (Exception e) { throw new RuntimeException(e); } } }); return null ; } // 从网络上取数据方法 protected Drawable loadImageFromUrl(String imageUrl) { try { // 测试时,模拟网络延时,实际时这行代码不能有 SystemClock.sleep(2000); return Drawable.createFromStream(new URL(imageUrl).openStream(), "image.png "); } catch (Exception e) { throw new RuntimeException(e); } } // 对外界开放的回调接口 public interface ImageCallback { // 注意 此方法是用来设置目标对象的图像资源 public void imageLoaded(Drawable imageDrawable); } }
说明:
final参数是指当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。参看:Java关键字final、static使用总结
这里使用SoftReference 是为了解决内存不足的错误(OutOfMemoryError)的,更详细的可以参看:内存优化的两个类:SoftReference 和 WeakReference
前段调用:
package ghj1976.AndroidTest; import android.app.Activity; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.widget.ImageView; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); loadImage4("http://www.baidu.com/img/baidu_logo.gif ", R.id.imageView1); loadImage4("http://www.chinatelecom.com.cn/images/logo_new.gif ", R.id.imageView2); loadImage4("http://cache.soso.com/30d/img/web/logo.gif ", R.id.imageView3); loadImage4("http://csdnimg.cn/www/images/csdnindex_logo.gif ", R.id.imageView4); loadImage4("http://images.cnblogs.com/logo_small.gif ", R.id.imageView5); } private AsyncImageLoader3 asyncImageLoader3 = new AsyncImageLoader3(); // 引入线程池,并引入内存缓存功能,并对外部调用封装了接口,简化调用过程 private void loadImage4(final String url, final int id) { // 如果缓存过就会从缓存中取出图像,ImageCallback接口中方法也不会被执行 Drawable cacheImage = asyncImageLoader3.loadDrawable(url, new AsyncImageLoader3.ImageCallback() { // 请参见实现:如果第一次加载url时下面方法会执行 public void imageLoaded(Drawable imageDrawable) { ((ImageView) findViewById(id)) .setImageDrawable(imageDrawable); } }); if (cacheImage != null ) { ((ImageView) findViewById(id)).setImageDrawable(cacheImage); } } }
参考资料:
Android异步加载图像小结
http://blog.csdn.net/sgl870927/archive/2011/03/29/6285535.aspx
发表评论
-
android中实现消息推送
2013-04-18 11:45 1802android中实现消息推送 ... -
android 9patch (讲的很不错,相当全面:转)
2012-12-21 14:29 975android 9patch (讲的很不错,相当全面 ... -
ios, anroid统一推送
2012-12-17 15:01 0Location: Home / HomeLang ... -
Android Service待机/睡眠时运行
2012-12-06 23:38 0Android Service待机/睡眠时运行 ... -
android中实现消息推送
2012-12-05 23:30 0android中实现消息推 ... -
androidpn的学习研究(五)【转】androidpn-client 常见BUG解决方法
2012-12-05 22:57 0androidpn的学习研究(五)【转】andro ... -
解决androidpn服务器端掉线不会重连的问题
2012-12-05 22:50 6023解决androidpn服务器端掉线不会重连的问题 wi ... -
HttpClient的超时用法小记
2012-11-25 00:02 0HttpClient的超时用法小记 Ht ... -
Android的网络请求中GZip的使用
2012-11-04 00:28 0Android的网络请求中GZip的使用 刚才去 ... -
HttpClient实现对GZip压缩的Response进行解压
2012-11-03 23:48 0HttpClient实现对GZip压缩的Respo ... -
为android的HttpClient添加请求超时时间
2012-11-03 23:36 0在以前做一个android的移动项目的时候, ... -
Android Activity和Intent机制学习笔记
2012-10-10 16:22 973Android Activity和Intent机 ... -
Android推送通知指南
2012-10-07 15:55 981Android推送通知指南 ... -
Google Android chat using Jetty Cometd java client
2012-09-03 10:46 0Google Android chat usin ... -
Android Push Notification实现信息推送使用
2012-09-03 10:35 0Android Push Notification实 ... -
深入剖析Android消息机制
2012-08-30 23:44 843深入剖析Android消息机制 在Android ... -
AsyncTask的用法
2012-08-30 23:45 768在开发A ... -
Debugging the hello-jni project with Visual Studio
2012-07-20 14:03 1365Debugging the hello-jni proj ... -
解決在 Android 中使用 Bitmap 造成 Out of memory 的方法
2012-07-14 23:40 1521因为Android本身的限制,在2.x版 ... -
利用Necessitas 在Qt上实现Android应用开发
2012-06-19 10:59 1115Necessitas是一个 用于Android平台的qt开 发 ...
相关推荐
这个"Android演化理解 Android 异步加载图片.zip"源码资源提供了对Android平台图片加载机制演进的理解和实现方法。以下是这个主题涵盖的一些关键知识点: 1. UI线程与工作线程:Android系统的主线程(UI线程)负责...
Android演化理解 Android 异步加载图片.zip项目安卓应用源码下载Android演化理解 Android 异步加载图片.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
演化理解 Android 异步加载图片.zip安卓程序源码资源下载演化理解 Android 异步加载图片.zip安卓程序源码资源下载 1.适合学生做毕业设计用 2.适合程序员学习研究用 3.适合新手自学研究使用
演化理解 Android 异步加载图片.zip项目安卓应用源码下载演化理解 Android 异步加载图片.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
在深入理解Android异步加载图片的过程中,还需要掌握Bitmap类的使用和内存管理。Bitmap对象占用了大量的内存,不当使用可能导致内存泄漏或内存抖动。因此,需要合理地配置Bitmap的配置参数,如Bitmap.Config,以及...
这个"Android演化理解 Android 异步加载图片"的压缩包文件提供了关于如何在Android平台处理图片加载的源码参考,这对于开发者来说是极其宝贵的资源。 首先,我们要了解为什么需要异步加载图片。在移动设备上,内存...
Android安卓项目源码-演化理解 Android 异步加载图片.zip
本资源"Android参考源码-演化理解 Android 异步加载图片.zip"提供了一套用于学习和参考的源代码,帮助开发者深入理解Android平台下图片异步加载的实现原理。下面,我们将详细探讨这一主题。 首先,我们要了解为什么...
"演化理解 Android 异步加载图片.zip"这个资源包,显然提供了一些关于如何在Android应用中实现高效图片异步加载的源码示例。以下是对这个主题的详细讲解: 首先,我们需要理解为什么需要异步加载图片。在Android...
本资料包"安卓图片加载缓存相关-演化理解Android异步加载图片.rar"主要探讨了Android平台上图片异步加载和缓存的策略。 首先,我们来看"Android异步加载图片"这个主题。在Android系统中,由于UI线程不能进行耗时...
总的来说,这个项目为Android开发者提供了一个实践平台,通过学习和分析源码,可以加深对Android异步加载图片机制的理解,提升实际开发技能。同时,它也是完成毕业设计的一个优秀案例,对于即将毕业的学生来说,能够...
本资料包"安卓Android源码——演化理解 Android 异步加载图片.zip"深入探讨了Android平台下图片异步加载的原理与实践,旨在帮助开发者更高效地处理这一问题。 首先,我们来了解一下Android图片异步加载的基本概念。...
总结起来,这个源码包提供了Android异步加载图片的多种实现方式,涵盖了从早期的Universal Image Loader到现代的Glide、Fresco,以及Kotlin协程的使用。通过深入研究这些源码,开发者不仅可以掌握异步加载图片的最佳...
下面将详细探讨Android异步加载图片的原理、方法和最佳实践。 1. **异步加载图片的重要性**: - 用户体验:避免因图片加载导致的UI卡顿,提高应用响应速度。 - 资源优化:减少内存占用,防止OOM(OutOfMemory)...
在Android应用开发中,...综上所述,Android异步加载图片是一个涉及多方面技术的综合课题,包括异步编程模型、图片库选择、缓存策略、资源管理等。理解和掌握这些知识点,对于开发流畅、高效的Android应用至关重要。
这个"Android演化理解Android异步加载图片"的项目,是针对Android源码的学习和毕业设计的一个实例,旨在帮助开发者深入理解如何在Android平台上有效地处理图片加载,以避免UI阻塞,提高应用性能。 首先,我们需要...
免责声明:资料部分来源于合法的互联网渠道收集和整理,部分自己学习积累成果,供大家学习参考与交流。收取的费用仅用于收集和整理资料耗费时间的酬劳。 本人尊重原创作者或出版方,资料版权归原作者或出版方所有,...