Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android studio for android learning (二十一 )異步任務AsyncTask加載美女圖片攻略及AsyncTask源碼詳解

android studio for android learning (二十一 )異步任務AsyncTask加載美女圖片攻略及AsyncTask源碼詳解

編輯:關於Android編程

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控件的初始化的操作,例如彈出ProgressDialog doInBackground(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中添加下面。

 

布局文件main.xml




    

核心代碼: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 {
        @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 {
    //獲得當前運行狀態的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 sPoolWorkQueue =
            new LinkedBlockingQueue(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 mWorker;
    private final FutureTask 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() {
            public Result call() throws Exception {
                    mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

        mFuture = new FutureTask(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);
                }
            }
        };
    }
..................

}

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved