接触Android时间不久,第一感觉就是对多屏幕的处理比较复杂。第二感觉就是layout和dp的处理大致上能比较简单地解决这些问题,第三感觉就是坑爹。
dp是什么呢? 密度无关像素?看完了screens_support最佳实践也没看出有啥意义的东西。
如果是layout和布局上图片资源这些东西,我基本也不用关心屏幕适应性问题了。鬼才管他100dp等于多少pixels。我又不是在手机上做photoshop。基本上可以把这个理解为屏幕尺寸。看起来Google试图把开发者和屏幕实际像素这些问题屏蔽开。
但我很快就遇到了一些现实问题:
我需要把一组任意尺寸的图片进行处理并放置到一个横向的线性布局中的ListView中。ListView占有weight 1, 他的右边是一个ImageView 占有weight 2。显示ListView中选中的图像的左边部分。(搞笑的是Google的人居然weight这种东西都能搞反, ListView实际上要写成2,imageview要写成weight=1)
我们需要处理的图片确实尺寸上没法限制,虽然在服务器端已经图片进行了预切割和尺寸放缩,但目的是在尽量不影响内容的情况下,尽量减少图片的尺寸,但为了保证在各种设备上都能有较好的表现,服务器的预处理并不会直接将图片处理为当前设备最完美的状态。另一方面,图片可能来源于照相机,800万摄像产生的照片也不会小。所以,我们需要在手机端也对图片读取时进行预处理。
一、复制图片到SDCARD
1. 我们在sdcard中建立一个子目录,然后拷贝一些图片到这个目录中。其中还有一张比较大的图片。其中还有一张3648x2746的图片。假定我们的这些图片都放置在这个子目录中。(系统的图标这些东西还是放在那些drawable中。)这些是动态处理的,假定是从互联网下载的。
将计算机文件拷贝到虚拟机的方法:
启动虚拟机,进入终端,然后执行adb push 见下图
adb push download sdcard意思是将当前目录的download目录下的所有东西复制到sdcrad根目录。当然也可以在sdcard中建立一个目录。在shell中运行 adb shell, cd sdcard, mkdir sourceDir......
二、对现有程序的处理
本来没打算写这一节。主要是因为现有的程序直接读取的ID,还没有考虑读取动态图片的问题。如果要读取动态图片,那么就要更改现在写的一些方法。除了以前的setImage(int id)这样方法以外,还要增加一个方法setImage(String path)。
问题马上就显现了,原来很顺滑的ListView现在卡得很。(ListView中的Item是一个带有图片的自定义控件)。所以先搞定这个问题再说。
解决ListView读取图片速度较慢的问题:
看Resource.类的源码.尼玛居然没有一点注释,不过并不复杂,loadDrawable的方法就是getResource().getDrawable(int id)所调用的。loadDrawable首先判断是否缓存中有这个图片,如果有就返回缓存的,没有就直接加载文件,并写入缓存。看起来他并没有做读取图片的优化。大概在resource的1968行可以看到(android2.3.3)sPreloadedDrawables ,sPreloadedColorDrawables这两个是预处理的缓存,mDrawableCache,mColorDrawableCache这两个是非预处理的缓存.
实际的应用中,这些图片基本上是读取的服务端传到本地的。最初的测试程序并没有考虑这个问题,在循环中重复加载这些图片时系统使用了缓存。所以显得比较快。很显然,时间消耗在了读取文件的过程了。
解决方案:
1. 增加内存缓冲
2. 多线程加载
01.package com.zh.mob.util;
02.
03.import java.lang.ref.SoftReference;
04.import java.util.concurrent.ConcurrentHashMap;
05.
06.import android.graphics.drawable.BitmapDrawable;
07.import android.graphics.drawable.Drawable;
08.import android.os.Handler;
09.import android.os.Message;
10.
11.public class AsynImageLoader {
12. private static ConcurrentHashMap> imageCache = new ConcurrentHashMap>();
13.
14.
15. public static void loadDrawable(final String path,
16. final AsyncLoadableImageView view) {
17. if (imageCache.containsKey(path)) {
18. SoftReference softReference = imageCache.get(path);
19. Drawable drawable = softReference.get();
20. if (drawable != null) {
21. view.setAsyncImage(drawable, path);
22. return;
23. }
24. }
25. final Handler handler = new Handler() {
26. @Override
27. public void handleMessage(Message message) {
28. view.setAsyncImage((Drawable) message.obj, path);
29. }
30. };
31. new Thread() {
32. @Override
33. public void run() {
34. Drawable drawable = new BitmapDrawable(path);
35. imageCache.put(path, new SoftReference(drawable));
36. Message message = handler.obtainMessage(0, drawable);
37. handler.sendMessage(message);
38. }
39. }.start();
40. }
41.
42. public inte***ce AsyncLoadableImageView {
43.
44. void setAsyncImage(Drawable drawable, String path);
45.
46. }
47.}
复制代码注意到AsyncLoadableImageView个接口,实现该接口的类就可以获得多线程加载的能力了。
使用方法:
部分隐藏 回复可见
dp是什么呢? 密度无关像素?看完了screens_support最佳实践也没看出有啥意义的东西。
如果是layout和布局上图片资源这些东西,我基本也不用关心屏幕适应性问题了。鬼才管他100dp等于多少pixels。我又不是在手机上做photoshop。基本上可以把这个理解为屏幕尺寸。看起来Google试图把开发者和屏幕实际像素这些问题屏蔽开。
但我很快就遇到了一些现实问题:
我需要把一组任意尺寸的图片进行处理并放置到一个横向的线性布局中的ListView中。ListView占有weight 1, 他的右边是一个ImageView 占有weight 2。显示ListView中选中的图像的左边部分。(搞笑的是Google的人居然weight这种东西都能搞反, ListView实际上要写成2,imageview要写成weight=1)
我们需要处理的图片确实尺寸上没法限制,虽然在服务器端已经图片进行了预切割和尺寸放缩,但目的是在尽量不影响内容的情况下,尽量减少图片的尺寸,但为了保证在各种设备上都能有较好的表现,服务器的预处理并不会直接将图片处理为当前设备最完美的状态。另一方面,图片可能来源于照相机,800万摄像产生的照片也不会小。所以,我们需要在手机端也对图片读取时进行预处理。
一、复制图片到SDCARD
1. 我们在sdcard中建立一个子目录,然后拷贝一些图片到这个目录中。其中还有一张比较大的图片。其中还有一张3648x2746的图片。假定我们的这些图片都放置在这个子目录中。(系统的图标这些东西还是放在那些drawable中。)这些是动态处理的,假定是从互联网下载的。
将计算机文件拷贝到虚拟机的方法:
启动虚拟机,进入终端,然后执行adb push 见下图
adb push download sdcard意思是将当前目录的download目录下的所有东西复制到sdcrad根目录。当然也可以在sdcard中建立一个目录。在shell中运行 adb shell, cd sdcard, mkdir sourceDir......
二、对现有程序的处理
本来没打算写这一节。主要是因为现有的程序直接读取的ID,还没有考虑读取动态图片的问题。如果要读取动态图片,那么就要更改现在写的一些方法。除了以前的setImage(int id)这样方法以外,还要增加一个方法setImage(String path)。
问题马上就显现了,原来很顺滑的ListView现在卡得很。(ListView中的Item是一个带有图片的自定义控件)。所以先搞定这个问题再说。
解决ListView读取图片速度较慢的问题:
看Resource.类的源码.尼玛居然没有一点注释,不过并不复杂,loadDrawable的方法就是getResource().getDrawable(int id)所调用的。loadDrawable首先判断是否缓存中有这个图片,如果有就返回缓存的,没有就直接加载文件,并写入缓存。看起来他并没有做读取图片的优化。大概在resource的1968行可以看到(android2.3.3)sPreloadedDrawables ,sPreloadedColorDrawables这两个是预处理的缓存,mDrawableCache,mColorDrawableCache这两个是非预处理的缓存.
实际的应用中,这些图片基本上是读取的服务端传到本地的。最初的测试程序并没有考虑这个问题,在循环中重复加载这些图片时系统使用了缓存。所以显得比较快。很显然,时间消耗在了读取文件的过程了。
解决方案:
1. 增加内存缓冲
2. 多线程加载
01.package com.zh.mob.util;
02.
03.import java.lang.ref.SoftReference;
04.import java.util.concurrent.ConcurrentHashMap;
05.
06.import android.graphics.drawable.BitmapDrawable;
07.import android.graphics.drawable.Drawable;
08.import android.os.Handler;
09.import android.os.Message;
10.
11.public class AsynImageLoader {
12. private static ConcurrentHashMap
13.
14.
15. public static void loadDrawable(final String path,
16. final AsyncLoadableImageView view) {
17. if (imageCache.containsKey(path)) {
18. SoftReference
19. Drawable drawable = softReference.get();
20. if (drawable != null) {
21. view.setAsyncImage(drawable, path);
22. return;
23. }
24. }
25. final Handler handler = new Handler() {
26. @Override
27. public void handleMessage(Message message) {
28. view.setAsyncImage((Drawable) message.obj, path);
29. }
30. };
31. new Thread() {
32. @Override
33. public void run() {
34. Drawable drawable = new BitmapDrawable(path);
35. imageCache.put(path, new SoftReference
36. Message message = handler.obtainMessage(0, drawable);
37. handler.sendMessage(message);
38. }
39. }.start();
40. }
41.
42. public inte***ce AsyncLoadableImageView {
43.
44. void setAsyncImage(Drawable drawable, String path);
45.
46. }
47.}
复制代码注意到AsyncLoadableImageView个接口,实现该接口的类就可以获得多线程加载的能力了。
使用方法:
部分隐藏 回复可见