iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Android编程学习之异步加载图片的方法
  • 117
分享到

Android编程学习之异步加载图片的方法

异步加载方法学习图片异步Android 2022-06-06 09:06:33 117人浏览 泡泡鱼
摘要

本文实例讲述了Android编程学习之异步加载图片的方法。分享给大家供大家参考,具体如下: 最近在android开发中碰到比较棘手的问题,就是加载图片内存溢出。我开发的是一个新

本文实例讲述了Android编程学习之异步加载图片的方法。分享给大家供大家参考,具体如下:

最近在android开发中碰到比较棘手的问题,就是加载图片内存溢出。我开发的是一个新闻应用,应用中用到大量的图片,一个界面中可能会有上百张图片。开发android应用的朋友可能或多或少碰到加载图片内存溢出问题,一般情况下,加载一张大图就会导致内存溢出,同样,加载多张图片内存溢出的概率也很高。

列一下网络上查到的一般做法:

1.使用BitmapFactory.Options对图片进行压缩
2.优化加载图片的adapter中的getView方法,使之尽可能少占用内存
3.使用异步加载图片的方式,使图片在页面加载后慢慢载入进来。

1、2步骤是必须做足的工作,但是对于大量图片的列表仍然无法解决内存溢出的问题,采用异步加载图片的方式才能有效解决图片加载内存溢出问题。

测试的效果图如下:

在这里我把主要的代码贴出来,给大家分享一下。

1、首先是MainActivity和activity_main.xml布局文件的代码。

(1)、MainActivity的代码如下:


package net.loonggg.test; 
import java.util.List; 
import net.loonggg.adapter.MyAdapter; 
import net.loonggg.bean.Menu; 
import net.loonggg.util.HttpUtil; 
import net.loonggg.util.Utils; 
import android.app.Activity; 
import android.app.ProgressDialog; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.view.Window; 
import android.widget.ListView; 
public class MainActivity extends Activity { 
 private ListView lv; 
 private MyAdapter adapter; 
 private ProgressDialog pd; 
 @Override 
 protected void onCreate(Bundle savedInstanceState) { 
  requestWindowFeature(Window.FEATURE_NO_TITLE); 
  super.onCreate(savedInstanceState); 
  setContentView(R.layout.activity_main); 
  lv = (ListView) findViewById(R.id.lv); 
  pd = new ProgressDialog(this); 
  pd.setTitle("加载菜单"); 
  pd.setMessage("正在加载"); 
  adapter = new MyAdapter(this); 
  new MyTask().execute("1"); 
 } 
 public class MyTask extends AsyncTask<String, Void, List<Menu>> { 
  @Override 
  protected void onPreExecute() { 
   super.onPreExecute(); 
   pd.show(); 
  } 
  @Override 
  protected void onPostExecute(List<Menu> result) { 
   super.onPostExecute(result); 
   adapter.setData(result); 
   lv.setAdapter(adapter); 
   pd.dismiss(); 
  } 
  @Override 
  protected List<Menu> doInBackground(String... params) { 
   String menuListStr = getListDishesInfo(params[0]); 
   return Utils.getInstance().parseMenusJSON(menuListStr); 
  } 
 } 
 private String getListDishesInfo(String sortId) { 
  // url 
  String url = HttpUtil.BASE_URL + "servlet/MenuInfoServlet?sortId=" 
    + sortId + "&flag=1"; 
  // 查询返回结果 
  return HttpUtil.queryStringForPost(url); 
 } 
} 

(2)、activity_main.xml的布局文件如下:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 xmlns:tools="http://schemas.android.com/tools" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="#ffffff" 
 android:orientation="vertical" > 
 <ListView 
  android:id="@+id/lv" 
  android:layout_width="fill_parent" 
  android:layout_height="wrap_content" > 
 </ListView> 
</LinearLayout> 

2、这是自定义的ListView的adapter的代码:


package net.loonggg.adapter; 
import java.util.List; 
import net.loonggg.bean.Menu; 
import net.loonggg.test.R; 
import net.loonggg.util.ImageLoader; 
import android.app.Activity; 
import android.content.Context; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.BaseAdapter; 
import android.widget.ImageView; 
import android.widget.TextView; 
public class MyAdapter extends BaseAdapter { 
 private List<Menu> list; 
 private Context context; 
 private Activity activity; 
 private ImageLoader imageLoader; 
 private ViewHolder viewHolder; 
 public MyAdapter(Context context) { 
  this.context = context; 
  this.activity = (Activity) context; 
  imageLoader = new ImageLoader(context); 
 } 
 public void setData(List<Menu> list) { 
  this.list = list; 
 } 
 @Override 
 public int getCount() { 
  return list.size(); 
 } 
 @Override 
 public Object getItem(int position) { 
  return list.get(position); 
 } 
 @Override 
 public long getItemId(int position) { 
  return position; 
 } 
 @Override 
 public View getView(int position, View convertView, ViewGroup parent) { 
  if (convertView == null) { 
   convertView = LayoutInflater.from(context).inflate( 
     R.layout.listview_item, null); 
   viewHolder = new ViewHolder(); 
   viewHolder.tv = (TextView) convertView.findViewById(R.id.item_tv); 
   viewHolder.iv = (ImageView) convertView.findViewById(R.id.item_iv); 
   convertView.setTag(viewHolder); 
  } else { 
   viewHolder = (ViewHolder) convertView.getTag(); 
  } 
  viewHolder.tv.setText(list.get(position).getDishes()); 
  imageLoader.DisplayImage(list.get(position).getPicPath(), activity, 
    viewHolder.iv); 
  return convertView; 
 } 
 private class ViewHolder { 
  private ImageView iv; 
  private TextView tv; 
 } 
} 

3、这是最重要的一部分代码,这就是异步加载图片的一个类,这里我就不解释了,代码中附有注释。代码如下:


package net.loonggg.util; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.util.Collections; 
import java.util.Map; 
import java.util.Stack; 
import java.util.WeakHashMap; 
import net.loonggg.test.R; 
import android.app.Activity; 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.widget.ImageView; 
 
public class ImageLoader { 
 // 手机中的缓存 
 private MemoryCache memoryCache = new MemoryCache(); 
 // sd卡缓存 
 private FileCache fileCache; 
 private PicturesLoader pictureLoaderThread = new PicturesLoader(); 
 private PicturesQueue picturesQueue = new PicturesQueue(); 
 private Map<ImageView, String> imageViews = Collections 
   .synchronizedMap(new WeakHashMap<ImageView, String>()); 
 public ImageLoader(Context context) { 
  // 设置线程的优先级 
  pictureLoaderThread.setPriority(Thread.NORM_PRIORITY - 1); 
  fileCache = new FileCache(context); 
 } 
 // 在找不到图片时,默认的图片 
 final int stub_id = R.drawable.stub; 
 public void DisplayImage(String url, Activity activity, ImageView imageView) { 
  imageViews.put(imageView, url); 
  Bitmap bitmap = memoryCache.get(url); 
  if (bitmap != null) 
   imageView.setImageBitmap(bitmap); 
  else {// 如果手机内存缓存中没有图片,则调用任务队列,并先设置默认图片 
   queuePhoto(url, activity, imageView); 
   imageView.setImageResource(stub_id); 
  } 
 } 
 private void queuePhoto(String url, Activity activity, ImageView imageView) { 
  // 这ImageView可能之前被用于其它图像。所以可能会有一些旧的任务队列。我们需要清理掉它们。 
  picturesQueue.Clean(imageView); 
  PictureToLoad p = new PictureToLoad(url, imageView); 
  synchronized (picturesQueue.picturesToLoad) { 
   picturesQueue.picturesToLoad.push(p); 
   picturesQueue.picturesToLoad.notifyAll(); 
  } 
  // 如果这个线程还没有启动,则启动线程 
  if (pictureLoaderThread.getState() == Thread.State.NEW) 
   pictureLoaderThread.start(); 
 } 
  
 private Bitmap getBitmap(String url) { 
  File f = fileCache.getFile(url); 
  // 从SD卡缓存中获取 
  Bitmap b = decodeFile(f); 
  if (b != null) 
   return b; 
  // 否则从网络中获取 
  try { 
   Bitmap bitmap = null; 
   URL imageUrl = new URL(url); 
   HttpURLConnection conn = (HttpURLConnection) imageUrl 
     .openConnection(); 
   conn.setConnectTimeout(30000); 
   conn.setReadTimeout(30000); 
   InputStream is = conn.getInputStream(); 
   OutputStream os = new FileOutputStream(f); 
   // 将图片写到sd卡目录中去 
   ImageUtil.CopyStream(is, os); 
   os.close(); 
   bitmap = decodeFile(f); 
   return bitmap; 
  } catch (Exception ex) { 
   ex.printStackTrace(); 
   return null; 
  } 
 } 
 // 解码图像和缩放以减少内存的消耗 
 private Bitmap decodeFile(File f) { 
  try { 
   // 解码图像尺寸 
   BitmapFactory.Options o = new BitmapFactory.Options(); 
   o.inJustDecodeBounds = true; 
   BitmapFactory.decodeStream(new FileInputStream(f), null, o); 
   // 找到正确的缩放值。这应该是2的幂。 
   final int REQUIRED_SIZE = 70; 
   int width_tmp = o.outWidth, height_tmp = o.outHeight; 
   int scale = 1; 
   while (true) { 
    if (width_tmp / 2 < REQUIRED_SIZE 
      || height_tmp / 2 < REQUIRED_SIZE) 
     break; 
    width_tmp /= 2; 
    height_tmp /= 2; 
    scale *= 2; 
   } 
   // 设置恰当的inSampleSize可以使BitmapFactory分配更少的空间 
   // 用正确恰当的inSampleSize进行decode 
   BitmapFactory.Options o2 = new BitmapFactory.Options(); 
   o2.inSampleSize = scale; 
   return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); 
  } catch (FileNotFoundException e) { 
  } 
  return null; 
 } 
  
 private class PictureToLoad { 
  public String url; 
  public ImageView imageView; 
  public PictureToLoad(String u, ImageView i) { 
   url = u; 
   imageView = i; 
  } 
 } 
 public void stopThread() { 
  pictureLoaderThread.interrupt(); 
 } 
 // 存储下载的照片列表 
 class PicturesQueue { 
  private Stack<PictureToLoad> picturesToLoad = new Stack<PictureToLoad>(); 
  // 删除这个ImageView的所有实例 
  public void Clean(ImageView image) { 
   for (int j = 0; j < picturesToLoad.size();) { 
    if (picturesToLoad.get(j).imageView == image) 
     picturesToLoad.remove(j); 
    else 
     ++j; 
   } 
  } 
 } 
 // 图片加载线程 
 class PicturesLoader extends Thread { 
  public void run() { 
   try { 
    while (true) { 
     // 线程等待直到有图片加载在队列中 
     if (picturesQueue.picturesToLoad.size() == 0) 
      synchronized (picturesQueue.picturesToLoad) { 
       picturesQueue.picturesToLoad.wait(); 
      } 
     if (picturesQueue.picturesToLoad.size() != 0) { 
      PictureToLoad photoToLoad; 
      synchronized (picturesQueue.picturesToLoad) { 
       photoToLoad = picturesQueue.picturesToLoad.pop(); 
      } 
      Bitmap bmp = getBitmap(photoToLoad.url); 
      // 写到手机内存中 
      memoryCache.put(photoToLoad.url, bmp); 
      String tag = imageViews.get(photoToLoad.imageView); 
      if (tag != null && tag.equals(photoToLoad.url)) { 
       BitmapDisplayer bd = new BitmapDisplayer(bmp, 
         photoToLoad.imageView); 
       Activity activity = (Activity) photoToLoad.imageView 
         .getContext(); 
       activity.runOnUiThread(bd); 
      } 
     } 
     if (Thread.interrupted()) 
      break; 
    } 
   } catch (InterruptedException e) { 
    // 在这里允许线程退出 
   } 
  } 
 } 
 // 在UI线程中显示Bitmap图像 
 class BitmapDisplayer implements Runnable { 
  Bitmap bitmap; 
  ImageView imageView; 
  public BitmapDisplayer(Bitmap bitmap, ImageView imageView) { 
   this.bitmap = bitmap; 
   this.imageView = imageView; 
  } 
  public void run() { 
   if (bitmap != null) 
    imageView.setImageBitmap(bitmap); 
   else 
    imageView.setImageResource(stub_id); 
  } 
 } 
 public void clearCache() { 
  memoryCache.clear(); 
  fileCache.clear(); 
 } 
} 

4、紧接着是几个实体类,一个是缓存到SD卡中的实体类,还有一个是缓存到手机内存中的实体类。代码如下:

(1)、缓存到sd卡的实体类:


package net.loonggg.util; 
import java.io.File; 
import android.content.Context; 
public class FileCache { 
 private File cacheDir; 
 public FileCache(Context context) { 
  // 找到保存缓存的图片目录 
  if (android.os.Environment.getExternalStorageState().equals( 
    android.os.Environment.MEDIA_MOUNTED)) 
   cacheDir = new File( 
     android.os.Environment.getExternalStorageDirectory(), 
     "newnews"); 
  else 
   cacheDir = context.getCacheDir(); 
  if (!cacheDir.exists()) 
   cacheDir.mkdirs(); 
 } 
 public File getFile(String url) { 
  String filename = String.valueOf(url.hashCode()); 
  File f = new File(cacheDir, filename); 
  return f; 
 } 
 public void clear() { 
  File[] files = cacheDir.listFiles(); 
  for (File f : files) 
   f.delete(); 
 } 
} 

(2)、缓存到手机内存的实体类:


package net.loonggg.util; 
import java.lang.ref.SoftReference; 
import java.util.HashMap; 
import android.graphics.Bitmap; 
public class MemoryCache { 
 private HashMap<String, SoftReference<Bitmap>> cache=new HashMap<String, SoftReference<Bitmap>>(); 
 public Bitmap get(String id){ 
  if(!cache.containsKey(id)) 
   return null; 
  SoftReference<Bitmap> ref=cache.get(id); 
  return ref.get(); 
 } 
 public void put(String id, Bitmap bitmap){ 
  cache.put(id, new SoftReference<Bitmap>(bitmap)); 
 } 
 public void clear() { 
  cache.clear(); 
 } 
} 

5、这个是输入输出流转换的类,及方法:


package net.loonggg.util; 
import java.io.InputStream; 
import java.io.OutputStream; 
public class ImageUtil { 
 public static void CopyStream(InputStream is, OutputStream os) { 
  final int buffer_size = 1024; 
  try { 
   byte[] bytes = new byte[buffer_size]; 
   for (;;) { 
    int count = is.read(bytes, 0, buffer_size); 
    if (count == -1) 
     break; 
    os.write(bytes, 0, count); 
   } 
  } catch (Exception ex) { 
  } 
 } 
} 

到这里基本就完成了。

希望本文所述对大家Android程序设计有所帮助。

您可能感兴趣的文章:Android异步加载数据和图片的保存思路详解深入理解Android中的Handler异步通信机制Android 中使用 AsyncTask 异步读取网络图片Android ListView异步加载图片方法详解Android实现图片异步加载并缓存到本地Android实现图片异步加载及本地缓存Android实现图片缓存与异步加载Android中异步类AsyncTask用法总结android异步加载图片并缓存到本地实现方法全面总结Android中线程的异步处理方式


--结束END--

本文标题: Android编程学习之异步加载图片的方法

本文链接: https://www.lsjlt.com/news/26449.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android实现异步加载图片
    麦洛开通博客以来,有一段时间没有更新博文了.主要是麦洛这段时间因项目开发实在太忙了.今天周六还在公司加班,苦逼程序猿都是这样生活的.今天在做项目的时候,有一个实现异步加载图片的功能,虽然比较简单但还是记录一下吧.因为麦洛之前实现异步加载图片...
    99+
    2023-05-31
    android 异步加载 roi
  • Android ListView实现ImageLoader图片加载的方法
    本文实例讲述了Android ListView实现ImageLoader图片加载的方法。分享给大家供大家参考,具体如下:最近一直忙着做项目,今天也是忙里偷闲,想写篇博客来巩固下之前在应用中所用的知识。之前我们可能会也会肯定遇到了图片的异步加...
    99+
    2023-05-30
    android listview imageloader
  • 学习Golang异步编程的技巧
    学习Golang异步编程的技巧 随着互联网技术的不断发展,对于高效并发处理的需求也日益增加。在编程领域,异步编程是一种常见的解决方案,可以有效提高程序的性能和响应速度。Go语言作为一门...
    99+
    2024-02-29
    技巧 golang 异步编程 go语言
  • Android Fresco图片加载优化的方案
    目录优化背景数据记录优化方案注意事项优化背景 一般情况下,Fresco图片加载需使用SimpleDraweeView,这个控件并不能自动根据自身的尺寸按需加载图片,即一个 N×N ...
    99+
    2024-04-02
  • 详解Android GLide图片加载常用几种方法
    目录缓存浅析GLide图片加载方法图片加载周期图片格式(Bitmap,Gif)缓存集成网络框架权限占位符淡入效果变换启动页/广告页banner固定宽高圆角圆形总结缓存浅析 为啥要做缓...
    99+
    2022-11-16
    Android GLide图片加载 Android GLide
  • Android 图片加载库之Coil的详解与使用
    一、介绍         在Android,资源的呈现主要有三大形式:文字、图片、视频。图片有分为本地资源和网络资源。 网络资源需要通过下载然后绑定到ImageView中。         在前期我们使用的图片加载框架如:picasso、...
    99+
    2023-10-02
    android kotlin Coil
  • Android官推kotlin-first图片加载库Coil的使用方法
    这篇文章给大家分享的是有关Android官推kotlin-first图片加载库Coil的使用方法的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Coil 是一个非常年轻的图片加载库,在 2020 年 10 月 22...
    99+
    2023-06-14
  • Android学习之菜单的使用方法
    本文实例为大家分享了Android学习之菜单使用的具体代码,供大家参考,具体内容如下 Android中菜单包含上下文菜单和选项菜单两种类型。 使用统一的菜单类来管理菜单: Menu、...
    99+
    2024-04-02
  • 异步加载CSS的方法有哪些
    这篇文章主要介绍“异步加载CSS的方法有哪些”,在日常操作中,相信很多人在异步加载CSS的方法有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”异步加载CSS的方法有哪些”...
    99+
    2024-04-02
  • Android给图片添加水印的方法
    这篇文章主要介绍Android给图片添加水印的方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1. 前言PS:最近在项目执行过程中有这样一个需求,要求拍完照的图片必须达到以上的效果。需求分析:使用用预览布局Surf...
    99+
    2023-06-15
  • 微信小程序加载本地图片的方法
    微信小程序加载本地图片的方法:1、在微信开发工具中打开项目。2、新建一个文件夹并将图片放到这个目录下。3、用style样式的方式或image标签的相对路径去访问图片,实现加载本地图片。具体操作步骤:首先,打开微信开发工具,再打开项目。如下图...
    99+
    2024-04-02
  • GO语言学习笔记,如何加载编程算法?
    随着计算机科学的发展,编程算法变得越来越重要。算法是解决计算机问题的方法,而GO语言则是一种强大的编程语言,它可以帮助开发人员编写高效的算法。在本文中,我们将探讨如何加载编程算法,以及如何使用GO语言编写高效的算法。 GO语言是一种高效的...
    99+
    2023-08-18
    学习笔记 编程算法 load
  • Android编程获取图片数据的方法详解
    本文实例讲述了Android编程获取图片数据的方法。分享给大家供大家参考,具体如下:网络的访问在我们日常生活中太重要了,如果没有网络我们的生活将会是什么样子呢?Android手机和浏览器也是一样的,也可以通过网络通讯获取数据,如调用webs...
    99+
    2023-05-30
    android 图片 roi
  • ​​​​​​​Python入门学习之函数式编程的方法
    本篇内容介绍了“Python入门学习之函数式编程的方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!前言在 Python 中,函数是「头等公...
    99+
    2023-06-30
  • 从零开始学习ASP异步编程,轻松实现Linux编程算法
    ASP异步编程是一种高效的编程方式,它可以让程序在等待某些操作完成的同时,继续执行其他任务。本文将从零开始介绍ASP异步编程的基础知识,并演示如何在Linux平台上实现编程算法。 一、异步编程基础 在传统的同步编程中,程序必须等待某个操作完...
    99+
    2023-11-03
    异步编程 linux 编程算法
  • Android学习之Span的使用方法详解
    目录Span集合段落类Span其他Span展示效果小试牛刀小结Span集合 段落类Span BulletSpan 为段落开头增加项目符号并支持大小、颜色、弧度 span.append...
    99+
    2024-04-02
  • PHP 多线程和异步编程的学习资源推荐?
    php 多线程和异步编程的学习资源和实战应用,可提升应用程序性能和响应能力。资源包括:1. php 官方文档;2. thinkphp 异步编程教程;3. swoole 框架教程。实战案例...
    99+
    2024-05-12
    php 并发 thinkphp swoole
  • html5异步加载路由组件的方法
    这篇文章主要介绍“html5异步加载路由组件的方法”,在日常操作中,相信很多人在html5异步加载路由组件的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”html5异步加...
    99+
    2024-04-02
  • 从Java异步编程到JavaScript对象:一次跨越式的学习之旅
    在当今的软件开发领域中,异步编程是一项必不可少的技能。无论是Java还是JavaScript,都有各自的异步编程方式。本文将带领读者完成一次从Java异步编程到JavaScript对象的跨越式学习之旅。 一、Java异步编程 Java是一...
    99+
    2023-06-15
    异步编程 javascript 对象
  • 异步的含义以及JavaScript异步编程的方法
    本篇内容主要讲解“异步的含义以及JavaScript异步编程的方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“异步的含义以及JavaScript异步编程的方法...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作