Android_异步加载2

Android 异步加载解决方案 NULL 博文链接:https://jgeng.iteye.com/blog/1630650 立即下载


         接着这篇博客写:http://blog.youkuaiyun.com/two_water/article/details/51477206

        异步加载1这篇博客在最后暴露出了一个问题,就是只在ListView的最后一个Item的ImageView刷新图片,解决问题的方案也提出来了,需要让url和对应的ImageView进行下配对!

ImageLoader的代码把showImageByThread方法里面的判断是否有缓存图片的代码注释了,改到在Adapter那里进行判断,判断是否有缓存图片,如果有显示缓存的图片,如果没有就先显示默认加载的图片,然后再去加载网络图片,并添加缓存!

package com.liangdianshui.asynchronouslyload;

import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

/**
 * Created by 两点水 on 2016/5/12.
 */
public class MyAdapter extends BaseAdapter {

	private Context context;
	private List<DataBean> list;
	private ViewHolder mHolder;
	private ImageLoader mImaeLoader;

	public MyAdapter(Context context, List<DataBean> list) {
		this.context = context;
		this.list = list;
		mImaeLoader = new ImageLoader();  //因为创建了缓存空间,所以放在构造方法,只创建一次
	}

	@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.item_layout, null);
			mHolder = new ViewHolder();
			mHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
			mHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
			mHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
			convertView.setTag(mHolder);
		} else {
			mHolder = (ViewHolder) convertView.getTag();
		}
//		mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//默认加载的图片
		String url = list.get(position).getDataIconUrl();
		mHolder.ivIcon.setTag(url);//为防止listview显示的图片错乱,重复,闪烁
//		new ImageLoader().showImageByThread(mHolder.ivIcon, url);
		Bitmap bitmapFromCache = mImaeLoader.getBitmapFromCache(url);
		if (bitmapFromCache != null) {
			mHolder.ivIcon.setImageBitmap(bitmapFromCache);
		}else{
			mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);
			mImaeLoader.showImageByThread(mHolder.ivIcon, url);
		}
		mHolder.tvTitle.setText(list.get(position).getDataTitle());
		mHolder.tvContent.setText(list.get(position).getDataContent());
		return convertView;
	}

	class ViewHolder {
		private TextView tvTitle;
		private TextView tvContent;
		private ImageView ivIcon;
	}
}
ImageLoader的代码:

package com.liangdianshui.asynchronouslyload;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.util.LruCache;
import android.widget.ImageView;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by 两点水 on 2016/5/22.
 */
public class ImageLoader {

	private ImageView mImageView;
	private String mUrl;
	private final int URL_BITMAP = 0;
	private LruCache<String, Bitmap> mCache;   //使用Lru缓存(使用的Lru算法:近期最少使用算法)

	/**
	 * 使用缓存肯定要先声明缓存空间,因此在构造方法中声明缓存空间
	 */
	public ImageLoader() {
		//获取程序最大使用的内存
		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		int cacheSize = maxMemory / 4;  //缓存大小为最大缓存的四分之一
		//创建缓存,把缓存大小传进去
		mCache = new LruCache<String, Bitmap>(cacheSize) {
			@Override
			protected int sizeOf(String key, Bitmap value) {
				//每次存入缓存的时候都会调用这个方法,因此我们把图片的大小放进去
				return value.getByteCount();
			}
		};
	}

	/**
	 * 把图片加入到缓存
	 *
	 * @param url
	 * @param bitmap
	 */
	public void addBitmapToCache(String url, Bitmap bitmap) {
		//LruCache好比是一个map,采用键值对的形式去保存图片
		if (getBitmapFromCache(url) == null) {
			//如果缓存中没有这个Bitmap,就把bitmap放进缓存
			mCache.put(url, bitmap);
		}
	}

	/**
	 * 从缓存中获取图片
	 *
	 * @param url
	 */
	public Bitmap getBitmapFromCache(String url) {
		return mCache.get(url); //根据url获取图片
	}

	Handler mHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			switch (msg.what) {
				case URL_BITMAP:
//					if (mImageView.getTag().equals(mUrl)) {
//						mImageView.setImageBitmap((Bitmap) msg.obj);
//					}
					//因为传过来的对象更改了,这里也要跟着更改
					ImgHolder holder = (ImgHolder) msg.obj;
					if (holder.imageView.getTag().equals(holder.url)) {
						holder.imageView.setImageBitmap(holder.bitmap);
					}
					break;
			}
		}
	};


	/**
	 * 多线程加载图片(Thread+Handler)
	 * 根据url获取的itmap显示在ImageView中
	 *
	 * @param imageView
	 * @param url
	 */
	public void showImageByThread(final ImageView imageView, final String url) {
		mImageView = imageView;
		mUrl = url;

		//从缓存中取出图片
//		Bitmap bitmap = getBitmapFromCache(url);
		//判断缓存中是否含有这张图片,没有的话去网络下载图片
//		if (bitmap == null) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					Bitmap bitmap = getBitmapFromURL(url);
					//把下载下来的图片加到缓存中
					if (bitmap != null) {
						addBitmapToCache(url, bitmap);
					}
					Message message = new Message();
//					message.obj = bitmap;
					//为了保证ImageView与这时候传递过来的图像一一对应的关系
					message.obj = new ImgHolder(imageView, bitmap, url);
					message.what = URL_BITMAP;
					mHandler.sendMessage(message);
				}
			}).start();  //记得start();
//		} else {
//			Message message = new Message();
//			message.obj = bitmap;
			//为了保证ImageView与这时候传递过来的图像一一对应的关系
//			message.obj = new ImgHolder(imageView, bitmap, url);
//			message.what = URL_BITMAP;
//			mHandler.sendMessage(message);
//		}
	}

	/**
	 * 根据rul获取bitmap
	 *
	 * @param url
	 * @return
	 */

	private Bitmap getBitmapFromURL(String url) {
		InputStream inputStream = null;
		try {
			URL urlBitmap = new URL(url);
			HttpURLConnection urlConnection = (HttpURLConnection) urlBitmap.openConnection();
			inputStream = new BufferedInputStream(urlConnection.getInputStream());
			Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
			Thread.sleep(1000); //模拟网速慢的情况,为了更好的显示ImageView刷新多次的情况
			urlConnection.disconnect(); //关闭http连接
			return bitmap;
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			try {
				inputStream.close(); //关闭流
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 新建一个类,记录ImageView,bitmap和url
	 */
	private class ImgHolder {
		public Bitmap bitmap;
		public ImageView imageView;
		public String url;

		public ImgHolder(ImageView iv, Bitmap bm, String url) {
			this.imageView = iv;
			this.bitmap = bm;
			this.url = url;
		}
	}


}
效果图:


        使用AsyncTask实现上面的效果,其实AsyncTask也是根据多线程来实现的,因此基本的实现方式是一样的,直接贴代码:

package com.liangdianshui.asynchronouslyload;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.LruCache;
import android.widget.ImageView;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by 两点水 on 2016/5/22.
 */
public class ImageLoader {

	private ImageView mImageView;
	private String mUrl;
	private final int URL_BITMAP = 0;
	private LruCache<String, Bitmap> mCache;   //使用Lru缓存(使用的Lru算法:近期最少使用算法)

	/**
	 * 使用缓存肯定要先声明缓存空间,因此在构造方法中声明缓存空间
	 */
	public ImageLoader() {
		//获取程序最大使用的内存
		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		int cacheSize = maxMemory / 4;  //缓存大小为最大缓存的四分之一
		//创建缓存,把缓存大小传进去
		mCache = new LruCache<String, Bitmap>(cacheSize) {
			@Override
			protected int sizeOf(String key, Bitmap value) {
				//每次存入缓存的时候都会调用这个方法,因此我们把图片的大小放进去
				return value.getByteCount();
			}
		};
	}

	/**
	 * 把图片加入到缓存
	 *
	 * @param url
	 * @param bitmap
	 */
	public void addBitmapToCache(String url, Bitmap bitmap) {
		//LruCache好比是一个map,采用键值对的形式去保存图片
		if (getBitmapFromCache(url) == null) {
			//如果缓存中没有这个Bitmap,就把bitmap放进缓存
			mCache.put(url, bitmap);
		}
	}

	/**
	 * 从缓存中获取图片
	 *
	 * @param url
	 */
	public Bitmap getBitmapFromCache(String url) {
		return mCache.get(url); //根据url获取图片
	}

	Handler mHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			switch (msg.what) {
				case URL_BITMAP:
//					if (mImageView.getTag().equals(mUrl)) {
//						mImageView.setImageBitmap((Bitmap) msg.obj);
//					}
					//因为传过来的对象更改了,这里也要跟着更改
					ImgHolder holder = (ImgHolder) msg.obj;
					if (holder.imageView.getTag().equals(holder.url)) {
						holder.imageView.setImageBitmap(holder.bitmap);
					}
					break;
			}
		}
	};


	/**
	 * 多线程加载图片(Thread+Handler)
	 * 根据url获取的itmap显示在ImageView中
	 *
	 * @param imageView
	 * @param url
	 */
	public void showImageByThread(final ImageView imageView, final String url) {
		mImageView = imageView;
		mUrl = url;

		//从缓存中取出图片
//		Bitmap bitmap = getBitmapFromCache(url);
		//判断缓存中是否含有这张图片,没有的话去网络下载图片
//		if (bitmap == null) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				Bitmap bitmap = getBitmapFromURL(url);
				//把下载下来的图片加到缓存中
				if (bitmap != null) {
					addBitmapToCache(url, bitmap);
				}
				Message message = new Message();
//					message.obj = bitmap;
				//为了保证ImageView与这时候传递过来的图像一一对应的关系
				message.obj = new ImgHolder(imageView, bitmap, url);
				message.what = URL_BITMAP;
				mHandler.sendMessage(message);
			}
		}).start();  //记得start();
//		} else {
//			Message message = new Message();
//			message.obj = bitmap;
		//为了保证ImageView与这时候传递过来的图像一一对应的关系
//			message.obj = new ImgHolder(imageView, bitmap, url);
//			message.what = URL_BITMAP;
//			mHandler.sendMessage(message);
//		}
	}

	/**
	 * 根据rul获取bitmap
	 *
	 * @param url
	 * @return
	 */

	private Bitmap getBitmapFromURL(String url) {
		InputStream inputStream = null;
		try {
			URL urlBitmap = new URL(url);
			HttpURLConnection urlConnection = (HttpURLConnection) urlBitmap.openConnection();
			inputStream = new BufferedInputStream(urlConnection.getInputStream());
			Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
//			Thread.sleep(1000); //模拟网速慢的情况,为了更好的显示ImageView刷新多次的情况
			urlConnection.disconnect(); //关闭http连接
			return bitmap;
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				inputStream.close(); //关闭流
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 新建一个类,记录ImageView,bitmap和url
	 */
	private class ImgHolder {
		public Bitmap bitmap;
		public ImageView imageView;
		public String url;

		public ImgHolder(ImageView iv, Bitmap bm, String url) {
			this.imageView = iv;
			this.bitmap = bm;
			this.url = url;
		}
	}


	/**
	 * 通过AsyncTask异步加载图片显示到ImageView
	 *
	 * @param imageView
	 * @param url
	 */
	public void showImageByAsyncTask(ImageView imageView, String url) {
		Bitmap bitmap = getBitmapFromCache(url);
		if (bitmap == null) {  //判断缓存是否有对应的图片
			new MyAsyncTask(imageView, url).execute(url);
		} else {
			imageView.setImageBitmap(bitmap);
		}
	}

	/**
	 * 创建MyAsyncTask内部类
	 * 通过AsyncTask异步加载图片
	 */
	private class MyAsyncTask extends AsyncTask<String, Void, Bitmap> {

		private ImageView mImageView;
		private String mUrl;

		/**
		 * 创建构造方法初始化ImagaeView
		 */
		public MyAsyncTask(ImageView imageView, String url) {
			mImageView = imageView;
			mUrl = url;
		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
		}

		@Override
		protected Bitmap doInBackground(String... params) {
			String url = params[0];
			Bitmap bitmap = getBitmapFromURL(url);
			if (bitmap != null) {
				addBitmapToCache(url, bitmap); //增叫图片到缓存
			}
			return bitmap;
		}

		@Override
		protected void onPostExecute(Bitmap bitmap) {
			super.onPostExecute(bitmap);
			if (mImageView.getTag().equals(mUrl)) {
				mImageView.setImageBitmap(bitmap);
			}
		}
	}

}
Adapter的代码:

package com.liangdianshui.asynchronouslyload;

import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

/**
 * Created by 两点水 on 2016/5/12.
 */
public class MyAdapter extends BaseAdapter {

	private Context context;
	private List<DataBean> list;
	private ViewHolder mHolder;
	private ImageLoader mImaeLoader;

	public MyAdapter(Context context, List<DataBean> list) {
		this.context = context;
		this.list = list;
		mImaeLoader = new ImageLoader();  //因为创建了缓存空间,所以放在构造方法,只创建一次
	}

	@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.item_layout, null);
			mHolder = new ViewHolder();
			mHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
			mHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
			mHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
			convertView.setTag(mHolder);
		} else {
			mHolder = (ViewHolder) convertView.getTag();
		}
//		mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//默认加载的图片
		String url = list.get(position).getDataIconUrl();
		mHolder.ivIcon.setTag(url);//为防止listview显示的图片错乱,重复,闪烁
//		new ImageLoader().showImageByThread(mHolder.ivIcon, url);
		/**
		 * 注释多线程异步加载图片的代码
		 */
//		Bitmap bitmapFromCache = mImaeLoader.getBitmapFromCache(url);
//		if (bitmapFromCache != null) {
//			mHolder.ivIcon.setImageBitmap(bitmapFromCache);
//		} else {
//			mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);
//			mImaeLoader.showImageByThread(mHolder.ivIcon, url);
//		}

		/**
		 *使用AsyncTask的方式实现多线程
		 */
		mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//默认加载的图片
		mImaeLoader.showImageByAsyncTask(mHolder.ivIcon, url);

		mHolder.tvTitle.setText(list.get(position).getDataTitle());
		mHolder.tvContent.setText(list.get(position).getDataContent());
		return convertView;
	}

	class ViewHolder {
		private TextView tvTitle;
		private TextView tvContent;
		private ImageView ivIcon;
	}
}

       效果图跟上面多线程实现的效果图是一样的!
ListView滚动时的高效优化:
           为什么要进行ListView滚动时的优化呢?当Item的界面很复杂的时候,我们的做法是一边滚动时还在加载图片的,加载完成后在主线程中更新ImageView,如果刚好在滚动的时候,更新ImageVIew,因为都是在主线程工作,这时候可能会有卡顿的现象!
       为了解决这种卡顿的现象,我们可以在用户滚动ListView的时候不更新ImageVeiw,只有当用户停止滚动的时候才更新,这样就不卡顿了!
       因此Adapter首先要监听滑动事件,在第一次加载的时候进行加载更新可见项item的视图,之后都是在ListView滑动停止的时候才更新加载图片,其余情况不加载图片!

package com.liangdianshui.asynchronouslyload;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import java.util.List;

/**
 * Created by 两点水 on 2016/5/12.
 */
public class MyAdapter extends BaseAdapter implements AbsListView.OnScrollListener {

    private Context context;
    private List<DataBean> list;
    private ViewHolder mHolder;
    private ImageLoader mImaeLoader;
    private int mStart, mEnd;//当前可见项的起始位置
    public static String URLS[];//用于保存所有的图片URL地址
    private boolean mFirstIn;//用于判断是否首次启动预加载

    public MyAdapter(Context context, List<DataBean> list, ListView listView) {
        this.context = context;
        this.list = list;
        mFirstIn = true;
        mImaeLoader = new ImageLoader(listView);  //因为创建了缓存空间,所以放在构造方法,只创建一次
        //保存所有的图片URL地址
        URLS = new String[list.size()];
        for (int i = 0; i < URLS.length; i++) {
            URLS[i] = list.get(i).getDataIconUrl();
        }
        //实现listview滑动监听接口
        listView.setOnScrollListener(this);
    }

    @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.item_layout, null);
            mHolder = new ViewHolder();
            mHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
            mHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
            mHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
            convertView.setTag(mHolder);
        } else {
            mHolder = (ViewHolder) convertView.getTag();
        }
//		mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//默认加载的图片
        String url = list.get(position).getDataIconUrl();
        mHolder.ivIcon.setTag(url);//为防止listview显示的图片错乱,重复,闪烁

//		new ImageLoader().showImageByThread(mHolder.ivIcon, url);
        /**
         * 多线程异步加载图片
         */
//		Bitmap bitmapFromCache = mImaeLoader.getBitmapFromCache(url);
//		if (bitmapFromCache != null) {
//			mHolder.ivIcon.setImageBitmap(bitmapFromCache);
//		} else {
//			mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);
//			mImaeLoader.showImageByThread(mHolder.ivIcon, url);
//		}

        /**
         *使用AsyncTask的方式实现多线程
         */
//        mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//默认加载的图片
        mImaeLoader.showImageByAsyncTask(mHolder.ivIcon, url);
        mHolder.tvTitle.setText(list.get(position).getDataTitle());
        mHolder.tvContent.setText(list.get(position).getDataContent());
        return convertView;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        //滚动状态为停止时,加载当前可见的数据项
        if (scrollState == SCROLL_STATE_IDLE) {
            mImaeLoader.loadPartImageView(mStart, mEnd);
        } else {//滑动没有停止时,停止任务
            mImaeLoader.CancelAllTask();
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        mStart = firstVisibleItem;
        mEnd = firstVisibleItem + visibleItemCount;
        //首次启动预加载
        if (mFirstIn && visibleItemCount > 0) {
            mImaeLoader.loadPartImageView(mStart, mEnd);
            mFirstIn = false;
        }
    }

    class ViewHolder {
        private TextView tvTitle;
        private TextView tvContent;
        private ImageView ivIcon;
    }
}
ImageLoader中写一个加载可见项视图Item的方法,然后修改下异步加载图片的方法:

package com.liangdianshui.asynchronouslyload;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.LruCache;
import android.widget.ImageView;
import android.widget.ListView;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by 两点水 on 2016/5/22.
 */
public class ImageLoader {

    private ImageView mImageView;
    private String mUrl;
    private final int URL_BITMAP = 0;
    private LruCache<String, Bitmap> mCache;   //使用Lru缓存(使用的Lru算法:近期最少使用算法)
    private ListView mlistView;
    private Set<MyAsyncTask> mTasks;

    /**
     * 使用缓存肯定要先声明缓存空间,因此在构造方法中声明缓存空间
     */
    public ImageLoader(ListView listView) {
        this.mlistView = listView;
        mTasks = new HashSet<>();
        //获取程序最大使用的内存
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        int cacheSize = maxMemory / 4;  //缓存大小为最大缓存的四分之一
        //创建缓存,把缓存大小传进去
        mCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                //每次存入缓存的时候都会调用这个方法,因此我们把图片的大小放进去
                return value.getByteCount();
            }
        };
    }

    /**
     * 把图片加入到缓存
     *
     * @param url
     * @param bitmap
     */
    public void addBitmapToCache(String url, Bitmap bitmap) {
        //LruCache好比是一个map,采用键值对的形式去保存图片
        if (getBitmapFromCache(url) == null) {
            //如果缓存中没有这个Bitmap,就把bitmap放进缓存
            mCache.put(url, bitmap);
        }
    }

    /**
     * 从缓存中获取图片
     *
     * @param url
     */
    public Bitmap getBitmapFromCache(String url) {
        return mCache.get(url); //根据url获取图片
    }

    Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case URL_BITMAP:
//					if (mImageView.getTag().equals(mUrl)) {
//						mImageView.setImageBitmap((Bitmap) msg.obj);
//					}
                    //因为传过来的对象更改了,这里也要跟着更改
                    ImgHolder holder = (ImgHolder) msg.obj;
                    if (holder.imageView.getTag().equals(holder.url)) {
                        holder.imageView.setImageBitmap(holder.bitmap);
                    }
                    break;
            }
        }
    };


    /**
     * 多线程加载图片(Thread+Handler)
     * 根据url获取的itmap显示在ImageView中
     *
     * @param imageView
     * @param url
     */
    public void showImageByThread(final ImageView imageView, final String url) {
        mImageView = imageView;
        mUrl = url;

        //从缓存中取出图片
//		Bitmap bitmap = getBitmapFromCache(url);
        //判断缓存中是否含有这张图片,没有的话去网络下载图片
//		if (bitmap == null) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = getBitmapFromURL(url);
                //把下载下来的图片加到缓存中
                if (bitmap != null) {
                    addBitmapToCache(url, bitmap);
                }
                Message message = new Message();
//					message.obj = bitmap;
                //为了保证ImageView与这时候传递过来的图像一一对应的关系
                message.obj = new ImgHolder(imageView, bitmap, url);
                message.what = URL_BITMAP;
                mHandler.sendMessage(message);
            }
        }).start();  //记得start();
//		} else {
//			Message message = new Message();
//			message.obj = bitmap;
        //为了保证ImageView与这时候传递过来的图像一一对应的关系
//			message.obj = new ImgHolder(imageView, bitmap, url);
//			message.what = URL_BITMAP;
//			mHandler.sendMessage(message);
//		}
    }

    /**
     * 根据rul获取bitmap
     *
     * @param url
     * @return
     */
    private Bitmap getBitmapFromURL(String url) {
        InputStream inputStream = null;
        try {
            URL urlBitmap = new URL(url);
            HttpURLConnection urlConnection = (HttpURLConnection) urlBitmap.openConnection();
            inputStream = new BufferedInputStream(urlConnection.getInputStream());
            Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
//			Thread.sleep(1000); //模拟网速慢的情况,为了更好的显示ImageView刷新多次的情况
            urlConnection.disconnect(); //关闭http连接
            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close(); //关闭流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 新建一个类,记录ImageView,bitmap和url
     */
    private class ImgHolder {
        public Bitmap bitmap;
        public ImageView imageView;
        public String url;

        public ImgHolder(ImageView iv, Bitmap bm, String url) {
            this.imageView = iv;
            this.bitmap = bm;
            this.url = url;
        }
    }


    /**
     * 通过AsyncTask异步加载图片显示到ImageView
     *
     * @param imageView
     * @param url
     */
    public void showImageByAsyncTask(ImageView imageView, String url) {
        Bitmap bitmap = getBitmapFromCache(url);
        if (bitmap == null) {  //判断缓存是否有对应的图片
//            new MyAsyncTask(imageView, url).execute(url);
            imageView.setImageResource(R.mipmap.ic_launcher);
        } else {
            imageView.setImageBitmap(bitmap);
        }
    }

    /**
     * 创建MyAsyncTask内部类
     * 通过AsyncTask异步加载图片
     */
    private class MyAsyncTask extends AsyncTask<String, Void, Bitmap> {

        private ImageView mImageView;
        private String mUrl;

        /**
         * 创建构造方法初始化ImagaeView
         */
        public MyAsyncTask(ImageView imageView, String url) {
            mImageView = imageView;
            mUrl = url;
        }

        public MyAsyncTask(String url) {
            mUrl = url;
        }


        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            String url = params[0];
            Bitmap bitmap = getBitmapFromURL(url);
            if (bitmap != null) {
                addBitmapToCache(url, bitmap); //增叫图片到缓存
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
//            if (mImageView.getTag().equals(mUrl)) {
//                mImageView.setImageBitmap(bitmap);
//            }
            //从ListView中获取Imageview
            ImageView imageView = (ImageView) mlistView.findViewWithTag(mUrl);
            if (imageView != null && bitmap != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }

    /**
     * 加载部分可见的图片
     */
    public void loadPartImageView(int start, int end) {
        for (int i = start; i < end; i++) {
            String url = MyAdapter.URLS[i];//得到可见项目起始中的各个url
            //得到缓存中的Bitmap
            Bitmap bitmap = getBitmapFromCache(url);
            //bitmap为空就下载,非空就直接使用
            if (bitmap == null) {
                MyAsyncTask task = new MyAsyncTask(url);
                task.execute(url);
                mTasks.add(task);
            } else {
                //从ListView中获取Imageview
                ImageView imageView = (ImageView) mlistView.findViewWithTag(url);
                imageView.setImageBitmap(bitmap);
            }
        }
    }

    /**
     * 取消当前正在运行的所有任务
     */
    public void CancelAllTask() {
        if (mTasks != null) {
            for (MyAsyncTask task :
                    mTasks) {
                task.cancel(true);
            }
        }
    }

}
Demo地址:http://download.youkuaiyun.com/detail/two_water/9540297




Android异步加载解决方案 Android的LazyLoad主要体现在网络数据(图片)异步加载、数据库查询、复杂业务逻辑处理以及费时任务操作导致的异步处理等方面。在介绍Android开发过程中,异步处理这个常见的技术问题之前,我们简单回顾下Android开发过程中需要注意的几个地方。 Android应用开发过程中必须遵循单线程模型(SingleThreadModel)的原则。因为Android的UI操作并不是线程安全的,所以涉及UI的操作必须在UI线程中完成。但是并非所有的操作都能在主线程中进行,Google工程师在设计上约定,Android应用在5s内无响应的 立即下载

相关推荐

EPLAN中3D宏文件的创建与优化技巧(以开关电源为例)

本文以开关电源为例,详细讲解了在EPLAN中创建和优化3D宏文件(.ema)的全流程。从搭建宏项目、导入模型,到精确定义安装面、调整视野方向,再到定义3D连接点并关联部件库,旨在帮助电气工程师在设计阶段实现精准布局、避免安装冲突,从而提升设计效率与质量。

weixin_29219539的博客 547

Android异步加载的方式

Android异步加载的方式

xiaokang666的博客 816

Matlab 2023b 科研党必备:MOSEK 10.1.25 安装与配置全记录(附License过期解决方案)

本文详细介绍了在Matlab 2023b中安装与配置MOSEK 10.1.25的全过程,特别针对科研用户提供学术许可申请、证书文件部署及环境集成的实用指南。文章还包含常见问题解决方案和性能调优建议,帮助用户高效完成优化计算任务。

weixin_30598225的博客 171

页面异步加载优化的几种方案

其实很简单的实现,我们就是仿造 LayoutInflater 那样子线程加载布局,在主线程添加布局嘛。自定义View如下,继承方式实现一个协程作用域,内部实现子线程加载布局,主线程替换占位View。关于自定义协程作用域相关的问题如果不了解的,可以看看我之前的[协程系列文章](https://juejin.cn/post/7121132393922035720。

chuyouyinghe的专栏 1178

Linux虚拟机mysql安装教程(详细步骤)出现了一个错误:依赖检测失败

Linux虚拟机安装mysql的详细步骤(有报错预警哦)

m0_74953387的博客 5257

别再手动算频谱了!用这个在线FFT工具,5分钟搞定JSON/CSV数据分析

本文介绍了一款高效的在线FFT工具,帮助用户快速分析JSON/CSV格式的时域数据,5分钟内完成频谱分析。通过傅里叶变换(FFT)算法,大幅提升计算效率,解决传统手动计算的痛点,适用于工业振动分析、设备故障诊断等场景。

weixin_29172201的博客 258

Android AsyncLayoutInflater 异步加载布局

AsyncLayoutInflater是 Android 提供的一个用于异步加载布局的工具类。可以在异步线程上加载布局文件,以避免在主线程上加载布局过于耗时而导致的 UI卡顿问题。

简单记录工作和学习 4227

[终于解决]Ubuntu14.04 32位安装移动网卡(0bda:b711)驱动8188gu tplink-WN726n

大致梳理一下问题解决的流程 首先,在台式机做了双系统,台式机只有一个网线接口,由于项目要求,需要占用网口传输数据,所以用之前买的tplink-WN726n免驱版2.0的移动网卡 【note】免驱版只能在Windows下安装使用,在Ubuntu系统中无法使用,所以,需要另辟蹊径。 找了很多资料,尝试很多方法,有的复杂有的简单,终于解决。 【思路】首先在Ubuntu系统中输入lsusb,查看是否检测到USB网卡设备。然后从Github中复制代码,构建,安装,然后modprobe一下,到前面那步还不行,就再来一步

瑞o 1万+

Android异步加载

用异步的方式去加载数据 为什么要使用异步加载? 1.提高用户的体验,用户在加载数据的时候不会感到明显的卡顿 2.Android UI单线程模型,所有的耗时操作会另起线程,否则会阻塞UI线程 异步加载最常用的两种方式: 1.基于多线程,通过多线程或者线程池进行异步加载; 2.通过Android 封装好的AsyncTask,AsyncTask的底层是基于线程池实现的 本文主要介绍异步加载...

u011846345的专栏 647

gseapy python包GO、KEGG富集(注释)分析

文档案例参考:https://gseapy.readthedocs.io/en/latest/gseapy_example.html#Over-representation-analysis-by-Enrichr-web-services安装:建议安装最新版(这里安装的1.04):https://github.com/zqfang/GSEApy/releases。

weixin_42357472的博客 3610

图形推理2-四大类六提示

图形推理笔记2

小y的学习笔记 6739

关于Android异步这一篇就够了

Android中实现异步操作的方式有多种,每种方式都有其特定的应用场景和优缺点。以下是一些常见的异步实现方式及其优缺点,并附带简单的示例代码。

VitorLiu的博客 1674

基于STM32L4XX 、HAL库的TMC2209-LA-T步进电机驱动器驱动程序应用设计

/ R/W=0 表示写。uint32_t gconf_value = (0 << 0) // I_scale_analog: 禁用,使用UART控制电流。uint32_t ihold_irun = (8 << 0) // 保持电流 8/31 最大值。

PP_Cottage的博客 449

安卓初始化页面时view的异步加载

Rxjava 2 -导入io.reactivex.rxjava2:rxjava:${Version.rxjava2}在初始化页面时 inflate耗时较久的view1. 可以先用as的 *和去检测中间代码的耗时时间; initView()中复杂页面的加载放到 AsyncLoadView() 中 , initView()可只放整体框架界面,便于快速进入此页面(活动或碎片等); 因为原来R.layout.search_left 处的布局被异步加载了,所以原来的位置用一块纯色view填充,等异步加载成功之后替换掉

coderfc的博客 790

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Android图片管理组件(双缓存+异步加载)

ImageManager2这个类具有异步从网络下载图片,从sd读取本地图片,内存缓存,硬盘缓存,图片使用动画渐现等功能,已经将其应用在包含大量图片的应用中一年多,没有出现oom Android程序常常会内存溢出,网上也有很多解决方案,如软引用,手动调用recycle等等。但经过我们实践发现这些方案,都没能起到很好的效果,我们的应用依然会出现很多oom,尤其我们的应用包含大量的图片。and

leeo1010的专栏 1174

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Android实现图片缓存与异步加载

ImageManager2这个类具有异步从网络下载图片,从sd读取本地图片,内存缓存,硬盘缓存,图片使用动画渐现等功能,已经将其应用在包含大量图片的应用中一年多,没有出现oom。 Android程序常常会内存溢出,网上也有很多解决方案,如软引用,手动调用recycle等等。但经过我们实践发现这些方案,都没能起到很好的效果,我们的应用依然会出现很多oom,尤其我们的应用包含大量的图片。androi...

augfun的博客 413

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

用JavaScript生成Android SDK的下载地址(2)——异步加载、解析xml,得到全部SDK的下载地址...

2.1 解决“浏览器卡顿”   解决办法是,改为异步加载。这样浏览器可以继续工作,下载完成后会触发回调函数。   xml_loadFile函数支持异步加载,只需将第2个参数设为回调函数就行了。我们还可以利用闭包函数,来简化回调函数的编写。   “加载并做xsl转换”这个操作比较固定,我们可以写一个函数来封装它(doload)。同时还可以作一些界面改进,比如我为它加了点线边框、加载状态提...

weixin_30332241的博客 100

Android线程二、异步加载-新闻列表

2.20晚

简单记录 460

Android图片管理组件(双缓存、异步加载)

ImageManager2这个类具有异步从网络下载图片,从sd读取本地图片,内存缓存,硬盘缓存,图片使用动画渐现等功能,已经将其应用在包含大量图片的应用中一年多,没有出现oom Android程序常常会内存溢出,网上也有很多解决方案,如软引用,手动调用recycle等等。但经过我们实践发现这些方案,都没能起到很好的效果,我们的应用依然会出现很多oom,尤其我们的应用包含大量的图片。a

u011052996的专栏 662

Android 图片异步加载的体会,SoftReference已经不再适用

在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map>  这样软引用的方式缓存网络图片。具体的例子见这篇文章。 核心代码如下: 1 public class AsyncImageLoader { 2 3 private HashMap> imageCache; 4 5 public

小琼琼的博客 350

android页面布局代码实现方法,【Android】纯代码建立页面布局(含异步加载图片)...

开发环境:macOS 10.12 + Android Studio 2.2,MinSDK Android 5.1java先看看整体效果android 本示例是基于Fragment进行的,直接上代码:缓存【界面结构】网络在 Fragment 中,采用 ScrollView + LinearLayout 实现。app1 2 xmlns:tools="http://schemas.android.com...

weixin_31899339的博客 791

android纯代码构造的页面,【Android】纯代码创建页面布局(含异步加载图片)

开发环境:macOS 10.12 + Android Studio 2.2,MinSDK Android 5.1先看看总体效果本示例是基于Fragment进行的,直接上代码:【界面结构】在 Fragment 中,采用 ScrollView + LinearLayout 实现。1 2 xmlns:tools="http://schemas.android.com/tools"3 android:la...

weixin_32918953的博客 378

Android ListView 异步加载刷新(更多)的思路

Android中ListView   适配器数据如果更改后,没有在UI线程及时调用适配器Adapter的通知更新方法将会抛出异常。 直接操作适配器的数据不安全。 网络的数据解析也是耗时任务,比如JSON转换。以下以JSON为例。 虽然ListView正逐渐被CardView取代,但是基本思路还是一样的。 这里在实践中总结了2种思路。 1.克隆数据方

lingshi210的专栏 1257
上一篇: JAVA_流(Stream)
下一篇: Android Studio_Android Studio Template
Two_Water
博客等级 码龄12年 573粉丝 134原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值