android开发步步为营之88:基于LruCache和AsyncTask的网络相册开发
来源:互联网 发布:阿里云 图像识别 api 编辑:程序博客网 时间:2024/05/16 18:54
哈哈,这个题目有点像当年读研时候的论文题目,基于XX技术的XX系统的开发。本文主要是想讲一下AsyncTask,AsyncTask在android 3.0之前的版本使用它的execute()方法,默认会开启一个只有cpu个数*2+1个线程的线程池,所以项目里面到处使用的话就会造成,某些页面加载数据的时候,需要等待线程池中有空闲的线程才能执行。android 3.0之后,google索性将使用execute()方法来执行异步任务的时候,直接改成一条条顺序执行了,这样已经没有了多线程的意义,看下源代码:
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); private static final int MESSAGE_POST_RESULT = 0x1; private static final int MESSAGE_POST_PROGRESS = 0x2; private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } }
可以看到默认的执行器是顺序执行任务的,所以我们推荐使用AsyncTask的executeOnExecutor(executor,params)方法,这个方法可以创建的自己的线程池,有3种线程池
//单个任务建议用 Executor mSingeThreadExecutor = Executors.newSingleThreadExecutor(); //不设线程个数,建议还是别这样用,免得占用cpu过长时间 Executor mCacheExecutor = Executors.newCachedThreadPool(); //开启固定个数线程的线程池 Executor mFixedExecutor = Executors.newFixedThreadPool(6);
另外本文使用了LruCache, support v4的包里包含了android.support.v4.util.LruCache,LRU==Least Recently Used 近期最少使用算法,根据分配给它的内存空间,内存不足的时候将新加入的数据替换近期最少使用的数据,这样一方面通过缓存技术,加快页面的加载速度,另外一方面,自动管理内存不用开发人员去操心。好的,给出全部的代码:
package com.figo.study.activity;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.AsyncTask;import android.os.Bundle;import android.support.v4.util.LruCache;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.GridView;import android.widget.ImageView;import com.figo.study.R;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;import java.util.ArrayList;import java.util.concurrent.Executor;import java.util.concurrent.Executors;public class AsyncTaskActivity extends Activity { //单个任务建议用// Executor mSingeThreadExecutor = Executors.newSingleThreadExecutor(); //不设线程个数,建议还是别这样用,免得占用cpu过长时间// Executor mCacheExecutor = Executors.newCachedThreadPool(); //开启固定个数线程的线程池 Executor mFixedExecutor = Executors.newFixedThreadPool(6); //内存自动回收 private LruCache<String, Bitmap> mLruCache; private GridView mGridView; private ArrayList<String> alImgUrls = new ArrayList<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_async_task); initView(); for (int a = 0; a < 80; a++) { alImgUrls.add("http://www.onegreen.org/desk/Upload_desk/200902/20090205181316946.jpg"); } } private void initView() { mGridView = (GridView) findViewById(R.id.gv_album); int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 10; mLruCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); } }; mGridView.setAdapter(new PictureAdapter()); } class PictureAdapter extends BaseAdapter { @Override public Object getItem(int position) { return null; } @Override public int getCount() { return alImgUrls.size(); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { holder = new ViewHolder(); //从xml页面实例化视图 convertView = LayoutInflater.from(AsyncTaskActivity.this).inflate(R.layout.layout_item_image, null); //填充我们定义的容器里面的控件 holder.img = (ImageView) convertView.findViewById(R.id.img_show); convertView.setTag(holder); } else { //直接从视图里面获取控件容器 holder = (ViewHolder) convertView.getTag(); } //不再推荐这么写了,因为execute使用的是默认线程池,android 3.0之后,execute是按顺序一个个执行的 new DownloadPicTask(holder.img).execute(alImgUrls.get(position)); new DownloadPicTask(holder.img).executeOnExecutor(mFixedExecutor, alImgUrls.get(position)); return convertView; } } // 视图容器 public final class ViewHolder { public ImageView img; } //下载图片异步任务 class DownloadPicTask extends AsyncTask<String, Integer, Bitmap> { ImageView mImg; public DownloadPicTask(ImageView imgView) { mImg=imgView; } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected void onPostExecute(Bitmap bitmap) { if(mImg!=null) { mImg.setImageBitmap(bitmap); } } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } @Override protected Bitmap doInBackground(String... params) { try { return getBitmap(params[0].toString()); } catch (Exception e) { return null; } } } //获取网络图片 public Bitmap getBitmap(String path) throws Exception { if(mLruCache.get(path)!=null) { return mLruCache.get(path); }else { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5 * 1000); conn.setRequestMethod("GET"); InputStream inStream = conn.getInputStream(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { Bitmap bitmap = BitmapFactory.decodeStream(inStream); mLruCache.put(path,bitmap); return bitmap; } } return null; }}
你会发现运行速度是杠杠的!运行效果如下:
1 0
- android开发步步为营之88:基于LruCache和AsyncTask的网络相册开发
- android开发步步为营之40:AsyncTask的用法
- android开发步步为营之104:文字加阴影效果和描边效果的实现
- android开发步步为营之52:AsyncTask处理过程中自定义旋转的菊花
- android开发步步为营之89: Executor+LruCache动态加载图片,保证不导致OOM
- android开发步步为营之91:自定义AlertDialog
- android开发步步为营之94:使用PathEffect画虚线和虚线框
- android开发步步为营之86:关于对阿拉伯语页面文字从右往左的支持
- android开发步步为营之12:AutoCompleteTextView和MultiAutoCompleteTextView
- android开发步步为营之16:发信息和打电话
- android开发步步为营之103:android分享音频视频图片和文字功能的实现
- android网络相册(带磁盘缓存DiskLruCache 和内存缓存LruCache)
- android开发步步为营之90:android图片处理技术之三(Gradient渐变图片的绘制)
- android开发步步为营之17:MideaPlayer的用法
- android开发步步为营之18:闹钟AlarmManager的使用
- android开发步步为营之26:进度条对话框ProgressDialog的用法
- android开发步步为营之27:上下文菜单ContextMenu的用法
- android开发步步为营之29:选项菜单OptionsMenu的用法
- 欢迎使用CSDN-markdown编辑器
- 使用DBUtils反射虚拟实体(实际数据库没有相对应的表)
- ImageButton点击改变图片
- BZOJ_P1067&Codevs_P2439 [SCOI2007]降雨量(线段树)
- Android实战(五)------Myeclipse新建运行Android项目
- android开发步步为营之88:基于LruCache和AsyncTask的网络相册开发
- 黑马程序员——java学习起始
- 【C】使用位运算符写一个整数计算器(图解)
- 关于interrupt,interrupted,isInterrupted的一点看法。
- mybatis报错:当要返回刚刚插入数据的id时
- 【代码】将一张正方形头像裁剪为原型,并保存在沙盒中
- UVA10048 Audiophobia (floyd变形)
- Chessboard(HDUOJ_5100)
- base64加密解密