android studio for android learning (二十一 )异步任务AsyncTask加载美女图片攻略及AsyncTask源码详解
2016-07-21 19:47
761 查看
1.android 的UI线程阻超过5秒就会引发ANR(Application not responding)异常,如果等待超过3秒,你就会失去用户。
2.在android中组件的启动线程被称为主线程(也称UI线程),一般不在这线程中进行耗时的工作,所以我们将线程分为两种,分别是main thread和worker thread,当应用程度运行是时,系统默认的启动线程就是主线程,主要用来加载UI,完成和用户间的交互,所有这些都在同一个线程中进行,所以不能在这个线程中进行耗时工作,不能阻塞UI,android也规定不能在UI线程之外的地方来操作UI元素。
3.这就关系到主线程和工作线程的通信问题,有两种方式来解决线程之间的通信问题,一种是handler机制,在之前的博客中已描述,如果你还不了解,可以点击这里。Handler消息传递机制全解,另一种就是现在要介绍的AsyncTask机制。
4.asyncTask是android提供给我们的一个多线程编程框架,需要定义一个类来继承AsyncTask这个抽象类,并实现其唯一的一个doInBackgroud抽象方法。主要是三个泛型参数,4个关键步骤。
AsyncTask < Params, Progress, Result >
Params: 指定的是我们传递给异步任务执行时的参数的类型Progress: 指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型
Result: 指定的是异步任务执行完后返回给UI线程的结果的类型
5.如果不指定上面的参数可以写成三个Void,四个关键步骤是
onPreExecute(): 这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的,通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出ProgressDialogdoInBackground(Params… params): 在onPreExecute()方法执行完后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread来执行这个方法(即在worker thread当中执行),执行完后将执行结果发送给最后一个 onPostExecute 方法,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作
onProgressUpdate(Progess… values): 这个方法也是在UI Thread当中执行的,在异步任务执行的时候,有时需要将执行的进度返回给UI界面,例如下载一张网络图片,我们需要时刻显示其下载的进度,就可以使用这个方法来更新进度。这个方法在调用之前,我们需要在 doInBackground 方法中调用一个 publishProgress(Progress) 的方法来将进度时时刻刻传递给 onProgressUpdate 方法来更新
onPostExecute(Result… result): 当异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,我们可以将返回的结果显示在UI控件上
注意:除了 doInBackground 方法之外的三个方法,都不是必须有的,因此必须要实现的方法是 doInBackground 方法,这个方法是运行在后台中的,其他三个方法都是运行在UI线程中,具体流程如下。
6.实例:通过异步任务AsyncTask加载美女图片,并显示到ImageView控件上,首先要做的事是添加网络授权,在androidmanifest.xml中添加下面。
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
布局文件main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.dragon.asynctask.Main"> <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentTop="true" android:layout_centerHorizontal="true"/> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="13dp" android:text="下载"/> </RelativeLayout>
核心代码:main.java
package com.dragon.asynctask; import android.app.ProgressDialog; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageView; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class Main extends AppCompatActivity { private final String TAG="asynctask"; private ImageView mImageView; private Button mButton; private ProgressDialog mDialog; // the path of image private String mImagePath="http://g.hiphotos.baidu.com/image/h%3D360/sign=4df699dff536afc3110c39638318eb85/908fa0ec08fa513d682eb8c13f6d55fbb2fbd92d.jpg"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // add Dialog mDialog = new ProgressDialog(this); // this dialog will never occur,if your network is good. mDialog.setTitle("attention"); mDialog.setMessage("waiting ... ..."); mImageView = (ImageView)findViewById(R.id.image); // mImageView.setScaleType(ImageView.ScaleType.FIT_XY);//when picture doesn't fit your phone,if can use this. mButton = (Button) findViewById(R.id.button); // listener mButton.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v){ // new async task DownTask task = new DownTask(); // must be execute int the UI thread also called Main thread. task.execute(mImagePath); } }); } // AsyncTask provided by google. public class DownTask extends AsyncTask<String,Void,Bitmap> { @Override protected void onPreExecute(){ mDialog.show(); } // the params is variable protected Bitmap doInBackground(String ... params){ URL imageUrl = null; Bitmap mBitmap=null; InputStream inputData=null; HttpURLConnection urlConn=null; try{ imageUrl = new URL(params[0]); }catch (MalformedURLException e){ e.printStackTrace(); } // get the net data using httpclient. try { urlConn =(HttpURLConnection) imageUrl.openConnection(); urlConn.setDoInput(true); urlConn.connect(); // convert to inputStream inputData = urlConn.getInputStream(); // decode mBitmap = BitmapFactory.decodeStream(inputData); inputData.close(); }catch(IOException e){ Log.e(TAG,e.getMessage()); }finally{ try { if(inputData != null){ inputData.close(); } if( urlConn != null){ urlConn.disconnect(); } } catch (IOException e) { e.printStackTrace(); } } return mBitmap; } // when doinbackground is over, next thing we should do. @Override protected void onPostExecute(Bitmap result){ super.onPostExecute(result); // show picture in the UI view. mImageView.setImageBitmap(result); // disable this dialog. mDialog.dismiss(); // let the button invisible, so we can see more comfortable, you konw. mButton.setVisibility(View.INVISIBLE); } } }
7.效果图,有失真,想看高清,自己试下代码,github链接地址
8.补充原则:
AsyncTask类必须在UI Thread当中加载,在Android中这些都是自动完成的AsyncTask的对象必须在UI Thread当中实例化
execute方法必须在UI Thread当中调用
不要手动的去调用AsyncTask的四个方法,这些都是由Android系统自动调用的
AsyncTask任务只能被执行一次
9.如果取消Task,可以通过调用cancle方法,这个较简单就不介绍了。
10.AsyncTask源码分析:
public abstract class AsyncTask<Params, Progress, Result> { //获得当前运行状态的cup数 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //根据当前机器CUP的个数决定线程池中的线程个数 private static final int CORE_POOL_SIZE = CPU_COUNT + 1; //获得线程池中最大线程数 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; //线程的存活时间 private static final int KEEP_ALIVE = 1; //线程工厂,为线程池创建所需线程 private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); } }; //线程池中的缓存队列,此处为128个 private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128); /** * An {@link Executor} that can be used to execute tasks in parallel. */ //根据以上参数,构造线程池执行器 public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); /** * An {@link Executor} that executes tasks one at a time in serial * order. This serialization is global to a particular process. */ //获得顺序执行的线程池执行器 public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); //异步任务处理结果码和进度更新码 private static final int MESSAGE_POST_RESULT = 0x1; private static final int MESSAGE_POST_PROGRESS = 0x2; //内部类,消息的执行者handler对象 private static final InternalHandler sHandler = new InternalHandler(); //线程池中默认的执行器 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; //异步任务回调接口 private final WorkerRunnable<Params, Result> mWorker; private final FutureTask<Result> mFuture; //当前异步任务的状态,初始状态为“未执行”状态 private volatile Status mStatus = Status.PENDING; private final AtomicBoolean mCancelled = new AtomicBoolean(); private final AtomicBoolean mTaskInvoked = new AtomicBoolean(); ...................... /** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ //创建一个新的异步任务,该构造方法必须在UI线程中调用 public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } }; mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { postResultIfNotInvoked(get()); } 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); } } }; } .................. }
11.有AR/VR开发感兴趣的朋友可以加入下面的交流群。
Reference:
1.http://blog.csdn.net/dmk877/article/details/493664212.http://blog.csdn.net/feiduclear_up/article/details/46860015
3.http://www.cnblogs.com/smyhvae/p/3866570.html
4.http://www.cnblogs.com/mythou/p/3191174.html
5.http://www.cnblogs.com/_ymw/p/4140418.html
6.http://blog.csdn.net/wdaming1986/article/details/40828453
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories