高效地加载图片(五) 将图片展示在UI中

这篇文章将前几篇使用的方法进行了整合,让我们能够在后台线程中加载以及缓存图片并在ViewPager和GridView中展示出来,并在这些过程中处理并发以及参数的设置.

将图片加载到ViewPager中

使用滑动视图来对图片详情进行导航是一种不错的方式.我们可以使用ViewPager和PagerAdapter来实现.但是,使用FragmentStatePagerAdapter可能会更好,它能够自动地保存ViewPager中Fragment的状态并控制它的创建和销毁,能够有效地利用内存.

注意:如果你仅仅需要加载少量的图片,并且能够确认这些图片不会造成内存溢出,则使用普通的PagerAdapter或者FragmenetPagerAdapter可能会更合适.

以下是使用ViewPager实现的图片展示:

view plaincopy to clipboardprint?

  1. public class ImageDetailActivity extends FragmentActivity {

  2. public static final String EXTRA_IMAGE = "extra_image";
  3. private ImagePagerAdapter mAdapter;

  4. private ViewPager mPager;
  5. // 静态的图片资源数组

  6. public final static Integer[] imageResIds = new Integer[] {

  7. R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,

  8. R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,

  9. R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};
  10. @Override

  11. public void onCreate(Bundle savedInstanceState) {

  12. super.onCreate(savedInstanceState);

  13. setContentView(R.layout.image_detail_pager); // 布局中仅仅包含一个ViewPager
  14. mAdapter = new ImagePagerAdapter(getSupportFragmentManager(), imageResIds.length);

  15. mPager = (ViewPager) findViewById(R.id.pager);

  16. mPager.setAdapter(mAdapter);

  17. }
  18. public static class ImagePagerAdapter extends FragmentStatePagerAdapter {

  19. private final int mSize;
  20. public ImagePagerAdapter(FragmentManager fm, int size) {

  21. super(fm);

  22. mSize = size;

  23. }
  24. @Override

  25. public int getCount() {

  26. return mSize;

  27. }
  28. @Override

  29. public Fragment getItem(int position) {

  30. return ImageDetailFragment.newInstance(position);

  31. }

  32. }

  33. }

public class ImageDetailActivity extends FragmentActivity {
public static final String EXTRA_IMAGE = "extra_image";

private ImagePagerAdapter mAdapter;
private ViewPager mPager;

// 静态的图片资源数组
public final static Integer[] imageResIds = new Integer[] {
R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,
R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,
R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image_detail_pager); // 布局中仅仅包含一个ViewPager

mAdapter = new ImagePagerAdapter(getSupportFragmentManager(), imageResIds.length);
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
}

public static class ImagePagerAdapter extends FragmentStatePagerAdapter {
private final int mSize;

public ImagePagerAdapter(FragmentManager fm, int size) {
super(fm);
mSize = size;
}

@Override
public int getCount() {
return mSize;
}

@Override
public Fragment getItem(int position) {
return ImageDetailFragment.newInstance(position);
}
}
}

以下是一个包含了ImageView的Fragment,用于展示图片.这部分代码看起来是一个十分理想的实现,但是你能够看出它的缺点吗?该怎么改进它?

view plaincopy to clipboardprint?

  1. public class ImageDetailFragment extends Fragment {

  2. private static final String IMAGE_DATA_EXTRA = "resId";

  3. private int mImageNum;

  4. private ImageView mImageView;
  5. static ImageDetailFragment newInstance(int imageNum) {

  6. final ImageDetailFragment f = new ImageDetailFragment();

  7. final Bundle args = new Bundle();

  8. args.putInt(IMAGE_DATA_EXTRA, imageNum);

  9. f.setArguments(args);

  10. return f;

  11. }
  12. // Empty constructor, required as per Fragment docs

  13. public ImageDetailFragment() {}
  14. @Override

  15. public void onCreate(Bundle savedInstanceState) {

  16. super.onCreate(savedInstanceState);

  17. mImageNum = getArguments() != null ? getArguments().getInt(IMAGE_DATA_EXTRA) : -1;

  18. }
  19. @Override

  20. public View onCreateView(LayoutInflater inflater, ViewGroup container,

  21. Bundle savedInstanceState) {

  22. // image_detail_fragment.xml contains just an ImageView

  23. final View v = inflater.inflate(R.layout.image_detail_fragment, container, false);

  24. mImageView = (ImageView) v.findViewById(R.id.imageView);

  25. return v;

  26. }
  27. @Override

  28. public void onActivityCreated(Bundle savedInstanceState) {

  29. super.onActivityCreated(savedInstanceState);

  30. final int resId = ImageDetailActivity.imageResIds[mImageNum];

  31. mImageView.setImageResource(resId); // 将图片加载到ImageView中

  32. }

  33. }

public class ImageDetailFragment extends Fragment {
private static final String IMAGE_DATA_EXTRA = "resId";
private int mImageNum;
private ImageView mImageView;

static ImageDetailFragment newInstance(int imageNum) {
final ImageDetailFragment f = new ImageDetailFragment();
final Bundle args = new Bundle();
args.putInt(IMAGE_DATA_EXTRA, imageNum);
f.setArguments(args);
return f;
}

// Empty constructor, required as per Fragment docs
public ImageDetailFragment() {}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mImageNum = getArguments() != null ? getArguments().getInt(IMAGE_DATA_EXTRA) : -1;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// image_detail_fragment.xml contains just an ImageView
final View v = inflater.inflate(R.layout.image_detail_fragment, container, false);
mImageView = (ImageView) v.findViewById(R.id.imageView);
return v;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final int resId = ImageDetailActivity.imageResIds[mImageNum];
mImageView.setImageResource(resId); // 将图片加载到ImageView中
}
}

从以上代码中,你可能发现了:图片是直接从资源文件中读取并展示到UI上的,这可能会造成应用挂起或者被强制关闭.此处使用AsyncTask在后台线程中加载图片会更好:

view plaincopy to clipboardprint?

  1. public class ImageDetailActivity extends FragmentActivity {

  2. ...
  3. public void loadBitmap(int resId, ImageView imageView) {

  4. mImageView.setImageResource(R.drawable.image_placeholder);

  5. BitmapWorkerTask task = new BitmapWorkerTask(mImageView);

  6. task.execute(resId);

  7. }
  8. ... // include BitmapWorkerTask class

  9. }
  10. public class ImageDetailFragment extends Fragment {

  11. ...
  12. @Override

  13. public void onActivityCreated(Bundle savedInstanceState) {

  14. super.onActivityCreated(savedInstanceState);

  15. if (ImageDetailActivity.class.isInstance(getActivity())) {

  16. final int resId = ImageDetailActivity.imageResIds[mImageNum];

  17. // 在后台线程中加载图片,而不是在Activity中直接读取图片

  18. ((ImageDetailActivity) getActivity()).loadBitmap(resId, mImageView);

  19. }

  20. }

  21. }

public class ImageDetailActivity extends FragmentActivity {
...

public void loadBitmap(int resId, ImageView imageView) {
mImageView.setImageResource(R.drawable.image_placeholder);
BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
task.execute(resId);
}

... // include BitmapWorkerTask class
}

public class ImageDetailFragment extends Fragment {
...

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (ImageDetailActivity.class.isInstance(getActivity())) {
final int resId = ImageDetailActivity.imageResIds[mImageNum];
// 在后台线程中加载图片,而不是在Activity中直接读取图片
((ImageDetailActivity) getActivity()).loadBitmap(resId, mImageView);
}
}
}

这样,我们可以在BitmapWorkerTask中实现任何附加的操作(如改变尺寸或者从网络读取图片资源)而不会映像UI线程的响应速度.就算使用后台线程加载图片的效率比直接加载图片低,我们也可以将使用的图片添加到缓存中以便复用.以下是添加缓存的方式:

view plaincopy to clipboardprint?

  1. public class ImageDetailActivity extends FragmentActivity {

  2. ...

  3. private LruCache<String, Bitmap> mMemoryCache;
  4. @Override

  5. public void onCreate(Bundle savedInstanceState) {

  6. ...

  7. // initialize LruCache as per Use a Memory Cache section

  8. }
  9. public void loadBitmap(int resId, ImageView imageView) {

  10. final String imageKey = String.valueOf(resId);
  11. final Bitmap bitmap = mMemoryCache.get(imageKey);

  12. if (bitmap != null) {

  13. mImageView.setImageBitmap(bitmap);

  14. } else {

  15. mImageView.setImageResource(R.drawable.image_placeholder);

  16. BitmapWorkerTask task = new BitmapWorkerTask(mImageView);

  17. task.execute(resId);

  18. }

  19. }
  20. ... // include updated BitmapWorkerTask from Use a Memory Cache section

  21. }

public class ImageDetailActivity extends FragmentActivity {
...
private LruCache<String, Bitmap> mMemoryCache;

@Override
public void onCreate(Bundle savedInstanceState) {
...
// initialize LruCache as per Use a Memory Cache section
}

public void loadBitmap(int resId, ImageView imageView) {
final String imageKey = String.valueOf(resId);

final Bitmap bitmap = mMemoryCache.get(imageKey);
if (bitmap != null) {
mImageView.setImageBitmap(bitmap);
} else {
mImageView.setImageResource(R.drawable.image_placeholder);
BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
task.execute(resId);
}
}

... // include updated BitmapWorkerTask from Use a Memory Cache section
}

将以上组合起来使用,就可以实现高效率的ViewPager展示,这样可以耗费最少的时间和资源完成更多的任务.

将图片展示在GridView中的实现

网格结构的视图有利于展示多张图片,这种结果可以通过GridView来实现.而GridView可用通过用户的滑动操作及时地将图片显示出来.要实现这种效果,我们必须保证UI线程不被阻塞,内存的使用也要处于控制之中,而且图片的并发加载也要处理好(基于GridView的子View的循环使用).

开始之前,这里有一个使用GridView和Fragment(包含ImageView)的实现:

view plaincopy to clipboardprint?

  1. public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {

  2. private ImageAdapter mAdapter;
  3. // A static dataset to back the GridView adapter

  4. public final static Integer[] imageResIds = new Integer[] {

  5. R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,

  6. R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,

  7. R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};
  8. // Empty constructor as per Fragment docs

  9. public ImageGridFragment() {}
  10. @Override

  11. public void onCreate(Bundle savedInstanceState) {

  12. super.onCreate(savedInstanceState);

  13. mAdapter = new ImageAdapter(getActivity());

  14. }
  15. @Override

  16. public View onCreateView(

  17. LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

  18. final View v = inflater.inflate(R.layout.image_grid_fragment, container, false);

  19. final GridView mGridView = (GridView) v.findViewById(R.id.gridView);

  20. mGridView.setAdapter(mAdapter);

  21. mGridView.setOnItemClickListener(this);

  22. return v;

  23. }
  24. @Override

  25. public void onItemClick(AdapterView<?> parent, View v, int position, long id) {

  26. final Intent i = new Intent(getActivity(), ImageDetailActivity.class);

  27. i.putExtra(ImageDetailActivity.EXTRA_IMAGE, position);

  28. startActivity(i);

  29. }
  30. private class ImageAdapter extends BaseAdapter {

  31. private final Context mContext;
  32. public ImageAdapter(Context context) {

  33. super();

  34. mContext = context;

  35. }
  36. @Override

  37. public int getCount() {

  38. return imageResIds.length;

  39. }
  40. @Override

  41. public Object getItem(int position) {

  42. return imageResIds[position];

  43. }
  44. @Override

  45. public long getItemId(int position) {

  46. return position;

  47. }
  48. @Override

  49. public View getView(int position, View convertView, ViewGroup container) {

  50. ImageView imageView;

  51. if (convertView == null) { // if it‘s not recycled, initialize some attributes

  52. imageView = new ImageView(mContext);

  53. imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);

  54. imageView.setLayoutParams(new GridView.LayoutParams(

  55. LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

  56. } else {

  57. imageView = (ImageView) convertView;

  58. }

  59. imageView.setImageResource(imageResIds[position]); // Load image into ImageView

  60. return imageView;

  61. }

  62. }

  63. }

public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
private ImageAdapter mAdapter;

// A static dataset to back the GridView adapter
public final static Integer[] imageResIds = new Integer[] {
R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,
R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,
R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};

// Empty constructor as per Fragment docs
public ImageGridFragment() {}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new ImageAdapter(getActivity());
}

@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.image_grid_fragment, container, false);
final GridView mGridView = (GridView) v.findViewById(R.id.gridView);
mGridView.setAdapter(mAdapter);
mGridView.setOnItemClickListener(this);
return v;
}

@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
final Intent i = new Intent(getActivity(), ImageDetailActivity.class);
i.putExtra(ImageDetailActivity.EXTRA_IMAGE, position);
startActivity(i);
}

private class ImageAdapter extends BaseAdapter {
private final Context mContext;

public ImageAdapter(Context context) {
super();
mContext = context;
}

@Override
public int getCount() {
return imageResIds.length;
}

@Override
public Object getItem(int position) {
return imageResIds[position];
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup container) {
ImageView imageView;
if (convertView == null) { // if it‘s not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(imageResIds[position]); // Load image into ImageView
return imageView;
}
}
}

此处同样在UI线程中读取了图片.这种方式在图片较少并且尺寸规律时并无不妥(基于系统资源的加载和缓存方式),但是如果需要任何其他的附加处理,我们的UI线程就可能被阻塞.

同样,前述的异步加载图片并且缓存的方式也适用于这里.同时,我们也必须谨慎地处理并发操作,因为在GridView中,子View是可以被复用的.具体处理方式,可以参考Processing
Bitmaps Off the UI Thread
.如下是此处的处理:

view plaincopy to clipboardprint?

  1. public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {

  2. ...
  3. private class ImageAdapter extends BaseAdapter {

  4. ...
  5. @Override

  6. public View getView(int position, View convertView, ViewGroup container) {

  7. ...

  8. loadBitmap(imageResIds[position], imageView)

  9. return imageView;

  10. }

  11. }
  12. public void loadBitmap(int resId, ImageView imageView) {

  13. if (cancelPotentialWork(resId, imageView)) {

  14. final BitmapWorkerTask task = new BitmapWorkerTask(imageView);

  15. final AsyncDrawable asyncDrawable =

  16. new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);

  17. imageView.setImageDrawable(asyncDrawable);

  18. task.execute(resId);

  19. }

  20. }
  21. static class AsyncDrawable extends BitmapDrawable {

  22. private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
  23. public AsyncDrawable(Resources res, Bitmap bitmap,

  24. BitmapWorkerTask bitmapWorkerTask) {

  25. super(res, bitmap);

  26. bitmapWorkerTaskReference =

  27. new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);

  28. }
  29. public BitmapWorkerTask getBitmapWorkerTask() {

  30. return bitmapWorkerTaskReference.get();

  31. }

  32. }
  33. public static boolean cancelPotentialWork(int data, ImageView imageView) {

  34. final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
  35. if (bitmapWorkerTask != null) {

  36. final int bitmapData = bitmapWorkerTask.data;

  37. if (bitmapData != data) {

  38. // Cancel previous task

  39. bitmapWorkerTask.cancel(true);

  40. } else {

  41. // The same work is already in progress

  42. return false;

  43. }

  44. }

  45. // No task associated with the ImageView, or an existing task was cancelled

  46. return true;

  47. }
  48. private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {

  49. if (imageView != null) {

  50. final Drawable drawable = imageView.getDrawable();

  51. if (drawable instanceof AsyncDrawable) {

  52. final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;

  53. return asyncDrawable.getBitmapWorkerTask();

  54. }

  55. }

  56. return null;

  57. }
  58. ... // include updated BitmapWorkerTask class

public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
...

private class ImageAdapter extends BaseAdapter {
...

@Override
public View getView(int position, View convertView, ViewGroup container) {
...
loadBitmap(imageResIds[position], imageView)
return 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);
}
}

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();
}
}

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;
}

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;
}

... // include updated BitmapWorkerTask class

注意:此处的处理同样适用于ListView.

在此处的处理中,我们实现了对图片的灵活加载以及处理,并且保证了UI线程的流畅性.在后台线程中我们能够加载网络图片或者对大图片进行处理.

时间: 2024-10-10 12:21:37

高效地加载图片(五) 将图片展示在UI中的相关文章

高效地加载图片(三) 缓存图片

如果只需要加载一张图片,那么直接加载就可以.但是,如果要在类似ListView,GridView或者ViewPager的控件中加载大量的图片时,问题就会变得复杂.在使用这类控件时,在短时间内可能会显示在屏幕上的图片数量是不固定的. 这类控件会通过子View的复用来保持较低的内存占用.而Garbage Collector也会在View被复用时释放对应的Bitmap,保证这些没用用到的Bitmap不会长期存在于内存中.但是为了保证控件的流畅滑动,在一个View再次滑动出现在屏幕上时,我们需要避免图片

高效地加载图片(四) 管理缓存

除了缓存图片意外,还有一些其他的方式来促进GC的效率和图片的复用.不同的Android系统版本有不同的处理策略.BitmapFun中就包含了这个类,能够使我们高效地构建我们的项目. 为了开始以下教程,我们需要先介绍一下Android系统对Bitmap管理的进化史. 在Android2.2(API level 8)以及更低的版本中,当垃圾被回收时,应用的线程会被停止,这会造成一定程度的延时.在Android 2.3中,加入了并发回收机制,这意味着当Bitmap不再被使用的时候,内存会被很快地回收.

asp.net MVC发布iis无法加载css,js和图片

今天真够郁闷的,遇到了在本地能运行的项目到了iis服务器那里就不行了,无法加载css,js和图片,这里说清楚一下先,关于asp.net 的MVC中这样的情况其实不少,但是之前遇到的是在visual studio运行的时候就已经不能加载css和js文件,那种情况一般都是路径的问题,改下页面代码就行,网上教程不少,而这个其实是一个CMS的开源系统.Orchard,国庆实在无聊,就想玩下这个asp.net MVC框架的CMS,而且是微软推荐的开源CMS,提到了就来说说这个吧,和国内的其他CMS对比起来

使用MFC CImage类和GDI+ Image加载并绘制PNG图片

一.使用MFC CImage类加载PNG图片        为了测试CImage绘制PNG图片的效果,我们用截图软件截得一张360的界面,然后使用PhotoShop等工具在图片的周边加上了透明的区域,然后保存成PNG图片文件.CImage首先从文件中加载,即 CImage* m_pImgBk; ...... m_pImgBk = new CImage; m_pImgBk->Load( _T("res\\bk.png")); if ( m_pImgBk->IsNull() )

分针网—每日分享: 根据屏幕大小,加载不同大小的图片

引言 今天要介绍的东西,很简单,但是对于前端响应式的时候是个很重要的知识: 我们在用bootstrap这类前端框架时, 虽然页面局部通过media query实现了,页面始终无滚动条,响应式页面. 但是,bootstrap里面的img-responsive类只是通过设置图片100%, 并没有真正的实现在手机上和电脑端加载不同大小的图片. 代码其实很简单 <!DOCTYPE html> <html lang="en"> <head> <meta 

imagepool前端图片加载管理器(JavaScript图片连接池)

前言 imagepool是一款管理图片加载的JS工具,通过imagepool可以控制图片并发加载个数. 对于图片加载,最原始的方式就是直接写个img标签,比如:<img src="图片url" />. 经过不断优化,出现了图片延迟加载方案,这回图片的URL不直接写在src属性中,而是写在某个属性中,比如:<img src="" data-src="图片url" />.这样浏览器就不会自动加载图片,等到一个恰当的时机需要加载

js判断图片加载完成后获取图片实际宽高

通常,我们会用jq的.width()/.height()方法获取图片的宽度/高度或者用js的.offsetwidth/.offsetheight方法来获取图片的宽度/高度,但这些方法在我们通过样式设置了图片的宽高后获取的就不是图片的实际宽高,这显然在有些时候不是我们想要的结果,那么有没有一种方法来获取这样的实际宽高呢?答案是有的.下面的代码就能解决这样的问题: <img src="01.jpg" id="test" width="250px"

Android利用Volley异步加载数据(JSON和图片)完整示例

Android利用Volley异步加载数据(JSON和图片)完整示例 MainActivity.java package cc.testvolley; import org.json.JSONObject; import android.app.Activity; import android.app.ProgressDialog; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v

js解决img标签加载失败显示默认图片

问题: 为所有显示楼盘的页面添加一个加载失败的默认图片. 基本思路: img标签中有个onerror属性,专门用来处理加载失败的事件.所以可以用jquery添加onerror属性,在onerror中加载默认图片. $(function(){ //注册加载失败事件,再次加载时先重新设置url,在清空原先的注册加载失败事件 $("img").attr("onerror","this.src='img/error.jpg;this.onerror=null;'&

Android开发 - ImageView加载Base64编码的图片

在我们开发应用的过程中,并不是所有情况下都请求图片的URL或者加载本地图片,有时我们需要加载Base64编码的图片.这种情况出现在服务端需要动态生成的图片,比如: 二维码 图形验证码 ... 这些应用场景有个共同点就是,这些图片都是由服务器动态生成,并不需要生成后保存成文件再返回给客户端. Android中ImageView加载Base64图片其实非常简单,并不需要引入第三方库,方法如下: import android.util.Base64; # 代码片段 String base64 = "d