前言:

以前看了些关于图片优化处理缓存比较全的视频(感谢慕风网),现在回顾觉得还是挺好的也就总结出来下,感觉针对图片做处理这块还真的用的比较多,本文章只要使用异步线程AsyncTask、自定义的ImageLoader和LRU算法来实现,还专门对AsyncTask针对线程管理和自定义核心线程和总运行线程并针对某些可能比较耗时没处理完阻塞线程进行的管理,当然这块有很多第三方框架可以实现,但还是自己写些自己见解的东西比较好,希望对你们有所帮助!

文章总体实现几点:

1、通过异步加载避免阻塞UI线程

2、通过自定义ImageLoader+LRU算法机制实现三级缓存图片

3、通过监听ListView的滑动状态尽可能的优化获取图片资源方式

效果图:

1、先说下什么叫异步加载?

其实顾名思义就是使用异步去访问加载网络请求数据(╯﹏╰);这不是跟没说一样吗?其实我也没有合理的解释,除非你懂啥叫异步?不就是不同步嘛(妖,那还不是跟没说一样(╯﹏╰))。好吧,所谓异步线程就是开启多条不是可以同步处理的线程处理,当然这线程数还是需要加以控制管理的,不然会造成程序特别耗性能,也就是我们常用到的AsyncTask。

2、那为什么需要使用异步?

首先,为了提高用户的体验,加载页面数据不会感觉到明显的卡顿,当然还有一点Android机制是main线程不可以进行些耗时操作,不然会阻塞UI线程报ANR异常,所以不得不开启子线程来处理。

3、异步加载有哪几种方式?

(1)、多线程/线程池实现。

(2)、AsyncTask(当然这种方式也就是线程池和handler进行了封装)

4、先来了解下AsyncTask

1、看一个类当然是从它的构造方法,首先分析下其都做了哪些操作

public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
};mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
final Result result = get();postResultIfNotInvoked(result);
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
}
};
}

首先构造方法里面创建了两个对象WorkerRunnable和FutureTask,然后我们继续接着看下这两个对象在什么情况下给调用呢?

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {if (mStatus != Status.PENDING) {switch (mStatus) {case RUNNING:throw new IllegalStateException("Cannot execute task:"+ " the task is already running.");case FINISHED:throw new IllegalStateException("Cannot execute task:"+ " the task has already been executed "+ "(a task can be executed only once)");}}mStatus = Status.RUNNING;onPreExecute();mWorker.mParams = params;exec.execute(mFuture);return this;}

这里看到最后使用了exec.execute(mFruture)调用了,这里是线程池启动器,此时启动了线程池。并执行了FutureTask,而WorkerRunnable是作为了callback的回调。最终执行了mWorker里面的call方法。对于线程池,其代码比较复杂也就大概了解至此。对于开启线程就需要先申请内存空间,再执行run方法,线程池就是需要开启多条线程,其实预先申请5条(默认),要是之后的呢?那么就先将其转为task任务暂存,等条件达到也就是有空余的线程可以出来处理时再去取task执行。线程处理完成任务之后当然需要更新UI上的数据,那么这就需要使用到了handler机制了,再继续往下看源代码。

private void finish(Result result) {if (isCancelled()) {onCancelled(result);} else {onPostExecute(result);}mStatus = Status.FINISHED;}方法调用了他,我们继续看谁调用了finishprivate static class InternalHandler extends Handler {@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {AsyncTaskResult result = (AsyncTaskResult) msg.obj;switch (msg.what) {case MESSAGEPOSTRESULT:// There is only one resultresult.mTask.finish(result.mData[0]);break;case MESSAGEPOSTPROGRESS:result.mTask.onProgressUpdate(result.mData);break;}}}

在finish 线程 结束前,这里就使用handler接收处理Message,然后执行了onProgressUpdapte()方法,这就是可以进行UI更新操作了。

最后说下Handler还有AsyncTask的描述为什么是The task instance must be created on the UI thread ? 了解Handler机制的人就知道,其实Handler在处理消息队列(MessageQueue)的时候就需要使用到轮询器(Looper)来进行循环获取消息,虽然我们可以new 很多个Handler但是他们本身就只存在一个Looper,当然UI线程中系统就默认帮我们开启了一个Looper,这样主线程就不需要去创建Looper了,要是不在UI线程初始化使用AsyncTask,那么在子线程中就需要自身去创建 个Looper提供给Handler使用,不然就会报异常。当然这样做还是会出现问题,因为AsyncTask使用到prepare需要在更新UI数据,其必须是在UI主线程的Looper中才可以实现(因为AsyncTask本身使用的就是UI线程下的Handler处理),它还是会因为创建出来的Looper不是UI Looper导致异常。所以要想使用AsyncTask就必须要在UI线程中初始化使用,还有一个AsyncTask对象只能调用一次excuste且需要在UI线程中调用。

AsyncTask总体运行机制:FutureTask获取任务执行run方法,run方法中调用了WorkerRunnable的call方法回调然后调用了doInBackground方法,doInbackground方法再将处理结果通过handler处理调用onProgressUpdapte和onPostExecute或者onCancelled方法进行数据更新操作(当然这只是一小部分)。

5、接下来就讲解下AsyncTask初始化参数信息和其里面几个方法的作用

先说下AsyncTask初始化参数代表的含义:
/***Params:doInBackground方法的参数类型;请求类型,如:url就是String类型的网址链接*Progress:AsyncTask所执行的后台任务的进度类型;如果不需要更新进度就直接返回void*Result:后台任务的返回结果类型。
**/
public abstract class AsyncTask<Params, Progress, Result> 

AsyncTask的调用无非就以下几个方法:

onPreExecute() //此方法会在后台任务执行前被调用,用于进行一些准备工作
doInBackground(Params... params) //此方法中定义要执行的后台任务,在这个方法中可以调用publishProgress来更新任务进度(publishProgress内部会调用onProgressUpdate方法)
onProgressUpdate(Progress... values) //由publishProgress内部调用,表示任务进度更新
onPostExecute(Result result) //后台任务执行完毕后,此方法会被调用,参数即为后台任务的返回结果
onCancelled() //此方法会在后台任务被取消时被调用

6、接着编写自定义的ImageLoader+LRU算法组合实现图片加载缓存(三级缓存)

思路:

存:
1、先异步访问网络获取图片资源
2、将网络获取到的图片资源通过LRU算法缓存到SD卡和内存中

取:

1、先从运行内存中获取图片对象

2、内存中没有在到本地SD卡上获取

3、本地SD卡上也没有再去网络上获取

实现代码:

package com.example.lainanzhou.imagecachedemo.utils;import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Message;
import android.os.StatFs;
import android.util.Log;
import android.util.LruCache;
import android.widget.ImageView;
import android.widget.ListView;import com.example.lainanzhou.imagecachedemo.R;
import com.example.lainanzhou.imagecachedemo.adapter.NewsAdapter;import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;/*** TODO:* 通过AsyncTask和LRU算法实现图片三级缓存的图片操作类* 存:* 1.先网络获取* 2.存到运行内存中和写到sd卡上* 取:* 1.先取运行内存中的图片缓存* 2.再取sd卡图片缓存资源* 3.最后取网络上的图片资源* 还有避免图片出现显示错乱情况(ListView的缓存机制复用convertView导致)* 设置View的Tag即可避免** @author Joker* @createDate 2016/7/15.*/
public class ImageLoader {private static ImageLoader mImageLoader;private ImageView iv;private String mUrl;public static LruCache<String, Bitmap> mLruCache;private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;private android.os.Handler mHandler = new android.os.Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);if (iv.getTag() == mUrl) {//获取ImageView的tag区别设置图片避免图片显示错乱Bitmap bitmap = (Bitmap) msg.obj;iv.setImageBitmap(bitmap);}}};private int mCorePoolSize = 10;private int  mMaximumPoolSize = 20;private int mKeepAliveTime ;private TimeUnit unit = TimeUnit.MILLISECONDS;// BlockingQueue<Runnable> workQueue = new// ArrayBlockingQueue<Runnable>(10);// 阻塞队列private BlockingQueue<Runnable> workQueue = newLinkedBlockingQueue<Runnable>();// 阻塞队列private ThreadFactory threadFactory = Executors.defaultThreadFactory();// RejectedExecutionHandler handler = new// ThreadPoolExecutor.AbortPolicy();//如果出现错误,则直接抛出异常// RejectedExecutionHandler handler = new// ThreadPoolExecutor.CallerRunsPolicy();// 如果出现错误,直接执行加入的任务// RejectedExecutionHandler handler = new// ThreadPoolExecutor.DiscardOldestPolicy();//// 如果出现错误,移除第一个任务,执行加入的任务private RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();// 如果出现错误,不做处理//第一种设置AsyncTask线程池方式private ThreadPoolExecutor mExecutor = new ThreadPoolExecutor(mCorePoolSize,// 核心线程数 : 10mMaximumPoolSize,// 最大线程数 : 20mKeepAliveTime,// 保持的时间长度unit,// keepAliveTime单位workQueue,// 任务队列threadFactory,// 线程工厂handler);// 错误捕获器//第二种修改AsyncTask线程池方式private ExecutorService mExecutorService = Executors.newFixedThreadPool(10);public synchronized static ImageLoader instance() {if (mImageLoader == null) {mImageLoader = new ImageLoader();//获取程序运行时最大内存空间long maxMemory = Runtime.getRuntime().maxMemory();int cacheSize = (int) (maxMemory / 4);mLruCache = new LruCache<String, Bitmap>(cacheSize) {//获取每次加载对象缓存的内存大小;默认返回的是元素的个数而非内存大小@Overrideprotected int sizeOf(String key, Bitmap value) {//每次存对象都会走的方法return value.getByteCount();}};}return mImageLoader;}private ImageLoader() {}/*** 直接开启线程处理方式显示图片* 加锁避免疯狂滑动开启多余线程处理同个url** @param imageView* @param url*/public void showImageFromThread(final ImageView imageView, final String url) {//取缓存Bitmap bitmap = getBitmapFromCache(url);//缓存存在就直接显示if (bitmap != null) {imageView.setImageBitmap(bitmap);Log.d(getClass().getSimpleName(), "取内存缓存" + url);} else {synchronized (url) {new Thread() {@Overridepublic void run() {super.run();iv = imageView;mUrl = url;Bitmap bitmap = getBitmapFromUrl(url);//缓存图片addBitmap2Cache(url, bitmap);Message mes = Message.obtain();mes.obj = bitmap;mHandler.sendMessage(mes);}}.start();}}}/*** 从Url获取bitmap对象** @param urlString* @return*/private Bitmap getBitmapFromUrl(String urlString) {Bitmap bitmap = null;InputStream is = null;try {URL url = new URL(urlString);HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();is = new BufferedInputStream(urlConnection.getInputStream());bitmap = BitmapFactory.decodeStream(is);//将流对象转成bitmap对象urlConnection.disconnect();//释放资源} catch (IOException e) {e.printStackTrace();} finally {try {if (is != null)is.close();} catch (IOException e) {e.printStackTrace();}}return bitmap;}public void showImageFromAsyncTask(ImageView imageView, String urlString, boolean isLoader) {//取缓存Bitmap bitmap = getBitmapFromCache(urlString);if (bitmap == null) {if (isLoader) {bitmap = getBitmapFromSdCard(urlString);if (bitmap == null && isLoader)
//                    new ImageAsyncTask(imageView).execute(urlString);//缓存没有就网络加载new ImageAsyncTask(imageView,urlString);//缓存没有就网络加载else if (imageView.getTag().equals(urlString)) {addBitmap2Cache(urlString, bitmap);//缓存到内存imageView.setImageBitmap(bitmap);//有缓存就直接显示Log.d(getClass().getSimpleName(), "取Sd卡缓存" + urlString);}} else if (imageView.getTag().equals(urlString)) {imageView.setImageResource(R.mipmap.ic_launcher);//设置默认图片}} else if (imageView.getTag().equals(urlString)) {imageView.setImageBitmap(bitmap);//有缓存就直接显示Log.d(getClass().getSimpleName(), "取内存缓存" + urlString);}}class ImageAsyncTask extends AsyncTask<String, Void, Bitmap> {private ImageView mImageView;private String url;public ImageAsyncTask(ImageView imageView,String... parmas) {this.executeOnExecutor(mExecutor,parmas);
//            this.executeOnExecutor(mExecutorService,parmas);mImageView = imageView;}@Overrideprotected Bitmap doInBackground(String... params) {url = params[0];Bitmap bitmap = getBitmapFromUrl(url);//缓存图片if (bitmap != null) {addBitmap2Cache(url, bitmap);writeBitmap2SdCard(bitmap, url);}return bitmap;}@Overrideprotected void onPostExecute(Bitmap bitmap) {super.onPostExecute(bitmap);if (bitmap == null && mImageView.getTag().equals(url))mImageView.setImageResource(R.mipmap.ic_launcher);//设置默认图片else if (mImageView.getTag().equals(url))mImageView.setImageBitmap(bitmap);}}/*** 加载停止可见的图片资源** @param start* @param visibleCount*/public void loadVisibleImages(ListView listView, int start, int visibleCount, boolean isLoader) {for (int i = start; i < visibleCount; i++) {//            new ImageAsyncTask(imageView).execute(urlList.get(i).getImageUrl());ImageView imageView = (ImageView) listView.findViewWithTag(NewsAdapter.mUrls[i]);showImageFromAsyncTask(imageView, NewsAdapter.mUrls[i], isLoader);}}/*** 添加图片到缓存中** @param url* @param bitmap*/private void addBitmap2Cache(String url, Bitmap bitmap) {if (getBitmapFromCache(url) == null) {mLruCache.put(url, bitmap);Log.d(getClass().getSimpleName(), "内存缓存" + url);}}/*** 从缓存中获取图片资源** @param url* @return*/private Bitmap getBitmapFromCache(String url) {return mLruCache.get(url);}private void writeBitmap2SdCard(Bitmap bitmap, String path) {if (bitmap == null) {return;}//判断sdcard上的空间if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {//SD空间不足return;}//创建缓存目录,系统一运行就得创建缓存目录的String filename = convertUrlToFileName(path);String dir = getDirectory();File dirFile = new File(dir);if (!dirFile.exists())dirFile.mkdirs();File file = new File(dirFile + "/" + filename);try {file.createNewFile();OutputStream outStream = new FileOutputStream(file);bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);outStream.flush();outStream.close();} catch (IOException e) {e.printStackTrace();}}/*** 计算sdcard上的剩余空间**/private int freeSpaceOnSd() {StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());double sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat.getBlockSize()) / 1024 * 1024;return (int) sdFreeMB;}private Bitmap getBitmapFromSdCard(String url) {String path = getDirectory() + "/" + convertUrlToFileName(url);File file = new File(path);if (file.exists()) {Bitmap bmp = BitmapFactory.decodeFile(path);if (bmp == null) {file.delete();} else {return bmp;}}return null;}/*** 取SD卡路径**/private String getSDPath() {boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);//判断sd卡是否存在if (sdCardExist) {//获取根目录return Environment.getExternalStorageDirectory().getPath();}return "";}/*** 将url转成文件名**/private String convertUrlToFileName(String url) {String[] strs = url.split("/");return strs[strs.length - 1];}/*** 获得缓存目录**/private String getDirectory() {String dir = getSDPath() + "/" + "imgCache";return dir;}
}

7.设置Adapter针对ListView的滑动事件的监听

只有在滑动状态是停止的时候才去访问网络加载数据。

代码实现:

package com.example.lainanzhou.imagecachedemo.adapter;import android.content.Context;
import android.util.Log;
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 com.example.lainanzhou.imagecachedemo.R;
import com.example.lainanzhou.imagecachedemo.bean.NewsBean;
import com.example.lainanzhou.imagecachedemo.utils.ImageLoader;import java.util.List;/*** TODO:* 处理ListView显示数据和监听当前ListView滑动状态来加载数据** @author Joker* @createDate 2016/7/15.*/
public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener {private LayoutInflater mLayoutInflater;private List<NewsBean> mBeanList;private boolean isFirst = false;private int start;private int end;private ListView mListView;public static String[] mUrls;public NewsAdapter(Context context, ListView listView, List<NewsBean> data) {mLayoutInflater = LayoutInflater.from(context);mBeanList = data;mListView = listView;mListView.setOnScrollListener(this);}@Overridepublic int getCount() {return mBeanList == null ? 0 : mBeanList.size();}@Overridepublic Object getItem(int position) {return mBeanList == null ? null : mBeanList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder;if (convertView == null) {viewHolder = new ViewHolder();convertView = mLayoutInflater.inflate(R.layout.item_layout, null);viewHolder.iv = (ImageView) convertView.findViewById(R.id.imageView);viewHolder.tv_titile = (TextView) convertView.findViewById(R.id.title);viewHolder.tv_content = (TextView) convertView.findViewById(R.id.content);convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}String ivUrl = mBeanList.get(position).getImageUrl();viewHolder.iv.setTag(ivUrl);//设置网路图片//        mImageLoader.showImageFromAsyncTask(viewHolder.iv, ivUrl);//        ImageLoader.instance().showImageFromAsyncTask(viewHolder.iv, ivUrl);viewHolder.tv_titile.setText(mBeanList.get(position).getTitle());viewHolder.tv_content.setText(mBeanList.get(position).getContent());return convertView;}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {//只有滑动状态发生改变才会走的方法,首次进来不会走if (scrollState == SCROLL_STATE_IDLE) {//停止状态//网络加载停止时可见项//            ImageLoader.instance().loadVisibleImages(mListView, start, end);showImageLoader(start, end, true);} else {//其他状态//停止网络加载任务showImageLoader(start, end, false);}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {//滑动就会走的方法,首次进来也会走start = firstVisibleItem;end = start + visibleItemCount;if (!isFirst && visibleItemCount > 0) {if (mUrls == null)mUrls = new String[mBeanList.size()];//            ImageLoader.instance().loadVisibleImages(mListView, start, end);for (int i = start; i < start + mBeanList.size(); i++) {mUrls[i] = mBeanList.get(i - start).getImageUrl();}showImageLoader(start, end, true);isFirst = true;return;}showImageLoader(start, end, false);}class ViewHolder {private ImageView iv;private TextView tv_titile;private TextView tv_content;}private void showImageLoader(int firstVisibleItem, int visibleCounts, boolean isLoader) {ImageLoader.instance().loadVisibleImages(mListView, firstVisibleItem, visibleCounts, isLoader);Log.d(getClass().getSimpleName(), "滑动状态:" + isLoader);}
}

8.MainActivity的调用

代码实现:

package com.example.lainanzhou.imagecachedemo;import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;import com.example.lainanzhou.imagecachedemo.adapter.NewsAdapter;
import com.example.lainanzhou.imagecachedemo.bean.NewsBean;import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {private ListView mListView;private String url = "http://www.imooc.com/api/teacher?type=4&num=30";private List<NewsBean> mBeanList = new ArrayList<>();private int start, visibleCounts;//可见item条目起始标志private boolean isFirst;private NewsAdapter mNewsAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mListView = (ListView) findViewById(R.id.listView);new NewsAsyncTask().execute(url);//启动异步请求}class NewsAsyncTask extends AsyncTask<String, Void, List<NewsBean>> {@Overrideprotected List<NewsBean> doInBackground(String... params) {return getJsonDataFromUrl(params[0]);//传进来的参数只有一个url}@Overrideprotected void onPostExecute(List<NewsBean> newsBeen) {super.onPostExecute(newsBeen);//更新UI数据界面mNewsAdapter = new NewsAdapter(MainActivity.this, mListView, mBeanList);mListView.setAdapter(mNewsAdapter);}}/*** 从url中获取结果** @param param* @return*/private List<NewsBean> getJsonDataFromUrl(String param) {try {InputStream is = new URL(url).openStream();String jsonString = radStream(is);try {JSONObject jsonObject = new JSONObject(jsonString);JSONArray jsonArray = jsonObject.getJSONArray("data");for (int i = 0; i < jsonArray.length(); i++) {NewsBean newsBean = new NewsBean();jsonObject = jsonArray.getJSONObject(i);newsBean.setImageUrl(jsonObject.getString("picSmall"));newsBean.setTitle(jsonObject.getString("name"));newsBean.setContent(jsonObject.getString("description"));mBeanList.add(newsBean);}} catch (JSONException e) {e.printStackTrace();}} catch (IOException e) {e.printStackTrace();}return mBeanList;}/*** 获取输入流结果** @param is* @return*/private String radStream(InputStream is) {String result = "";try {String line = "";//将输入字节流转化为字符流来处理InputStreamReader isr = new InputStreamReader(is, "utf-8");//读取字符流BufferedReader br = new BufferedReader(isr);try {while ((line = br.readLine()) != null) {result += line;}//关闭流br.close();isr.close();} catch (IOException e) {e.printStackTrace();}} catch (UnsupportedEncodingException e) {e.printStackTrace();}return result;}}

最后附带项目链接地址:点击打开链接

(原创)使用AsyncTask(带修改线程池方式)+自定义ImageLoader+LRU算法对图片三级缓存及其显示优化(只有在ListView滑动停止的时候才去网络请求获取图片数据)相关推荐

  1. Android HTTP网络请求获取JSON数据

  2. Android AsyncTask两种线程池分析和总结

    转自:http://bbs.51cto.com/thread-1114378-1-1.html Android AsyncTask两种线程池分析和总结 (一)    前言 在android Async ...

  3. Android之AsyncTask两种线程池分析和总结

    Android AsyncTask两种线程池分析和总结 (一)    前言 在android AsyncTask里面有两种线程池供我们调用 1.    THREAD_POOL_EXECUTOR, 异步 ...

  4. android AsyncTask 只能在线程池里单个运行的问题

    android 的AysncTask直接调用Execute会在在一个线程池里按调用的先后顺序依次执行. 如果应用的所有网络获取都依赖这个来做,当有一个网络请求柱塞,就导致其它请求也柱塞了. 在3.0 ...

  5. Android之从网络上获取图片的两种方式讲解:thread+handle和AsyncTask方式

    从网络上获取图片是一个比较耗时的操作,放在主线程会导致阻塞主线程,响应超时,所以我们不能把它放在主线程里操作,必须放在一个子线程里,我打算采用两种方式去实现.1.采用thread去获取图片,获取到后通 ...

  6. 【苹果相册推送】软件安装表现到ListView中,把网络请求来的数据存储下来

    推荐内容IMESSGAE相关 作者推荐内容 iMessage苹果推软件 *** 点击即可查看作者要求内容信息 作者推荐内容 1.家庭推内容 *** 点击即可查看作者要求内容信息 作者推荐内容 2.相册 ...

  7. 微信小程序教学第二章(含视频):小程序中级实战教程之预备篇 - 封装网络请求及 mock 数据...

    § 封装网络请求及 mock 数据 本文配套视频地址: v.qq.com/x/page/i055- 开始前请把 ch2-3 分支中的 code/ 目录导入微信开发工具 上一节中,我们对 index.j ...

  8. ios获取网络请求失败相关数据

    ios获取网络请求失败相关数据 很多时候和后台处理数据的时候很多时候后台会在网络请求失败的某些不同情况下带回不同的数据这个时候如何获取数据及拿到需要处理的数据: //如果请求失败 对象是NSURLSe ...

  9. java 请求url 返回数据_java后台发起get请求获取响应数据|chu

    本文实例为大家分享了java后台发起get请求获取响应数据,供大家参考,具体内容如下 学习记录: 话不多说直接上代码: package com.jl.chromeTest; import java.i ...

最新文章

  1. 2018年爱奇艺校招笔试
  2. python turtle循环图案-有趣的Python turtle绘图
  3. 组合的输出pascal程序
  4. 网页设计师应向肖像画家吸取的11个理念
  5. 安装scapy遇到的问题
  6. 使用Google Custom Search打造站内搜索
  7. Python-selenium-操作元素
  8. JAX-WS发布WebService
  9. OPPO R9s刷机教程 可解锁线刷包 救砖升级
  10. VOIP Codec 三剑客之 ISAC/ILBC -- ISAC (3) High Band Encode 模块
  11. HMI-48-【多媒体】Title界面实现 3
  12. Java图形界面开发—简易登录注册小程序
  13. Nginx实现https反向代理配置
  14. 我在谷歌大脑见习机器学习的一年:Node.js创始人的尝试笔记
  15. 网页占满整个屏幕_CSS网页背景图片等比例占满整个页面的解决方案
  16. tkinter显示图片
  17. 《计算机工程与应用》投稿录用经历记录
  18. 【JavaScript-进阶】详解数据类型,内存分配,API元素对象获取
  19. WMS仓储自动化是什么?有哪些用途
  20. 消除类游戏(C++)

热门文章

  1. split-horizon产生的路由欺骗
  2. 平安夜的真实来历(平安夜的由来)
  3. golang windows 设置桌面背景和屏幕保护
  4. 考研英语(五)——定语从句
  5. Flink系列文档-(YY08)-Flink核心概念
  6. windows如何批量修改文件名
  7. 二维上怪物的随机移动、有倾向性移动的小算法
  8. 蓝图(Blueprint)理解
  9. MacPorts使用
  10. 京东JOS API 接入使用笔记