android studio for android learning (二十一 )异步任务AsyncTask加载美女图片攻略及AsyncTask源码详解

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中添加下面。

 <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/49366421
2.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

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
接触过自定义控件的开发者一看,笑了,立马关了网页。但是…你真的知道怎么绘制居中文本吗? 我不会?开玩笑,不就是: X=控件宽度/2 - 文本宽度/2;Y=控件高度/2 + 文本宽度/2 好吧,那我试一下。 1.自定义控件基本步骤 自定义View的属性 在View的构造方法中获得我们自定义的属性 #重写onMesure # 重写onDraw OK,简单,直接干起来。 1. 自定义View的属性 按照最简单的来,属性有:文本,文本颜色,文本大小。 我们在 /value/attrs.xml 中这么写: ?xml
首先,自定义控件分为三类: 自定义的组合控件 继承View的自定义控件 继承ViewGroup的自定义控件 在这里,我要写的是第二种,也就是继承自View的自定义控件,第一种自定义的组合控件,我已经写过了,可以在我的博客中可以找到 现在来看一下继承View的自定义控件 首先,需要写一个类继承自View,那么,它也有三个构造方法,有一个参数的构造方法实在代码中new这个自定义控件时被调用;有两个参数的构造方法是在布局中使用这个自定义控件的时候调用,有三个参数的构造方法,实在使用到这个自定义控件的样式时被调用

WindowManager的分析 - 2016-07-22 18:07:46

一、Window和WindowManager Window:表示一个窗口,从下面Window的源码中可以看出它有且只有一个实现类PhoneWindow。 The only existing implementation of this abstract class is * android.policy.PhoneWindow, which you should instantiate when needing a * Window. WindowManager:它是系统提供我们操作Window的一个接口

MTK6580-Psensor hal层驱动分析 - 2016-07-22 18:07:25

一、HAL 层Sensor 流程         Hal 就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。也就是说,把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在用户空间,而Linux内核驱动程序运行在内核空间。 Sensor 打开设备时序图:  其中SensorDevice 属于 JNI 层,与 HAL 进行通信的接口 ; 在 JNI 层调用了 HAL 层的 open_sensors() 方法
ART世界探险(2) - 从java byte code说起 Dalvik时代,如果不做JIT的话,只需要了解java字节码和Dalivk的字节码就够了。但是,到了ART时代,我们可能还要至少学习两种新东西:一个是编译后端的IR中间代码。比如,我们假如使用LLVM做为编译后端的话,需要做从dex到LLVM IR的转换工作。这个IR可能还不只一层,比如分中层的MIR和底层的LIR。 最后,我们还得了解机器指令。仅就ARM来说,现在是64位时代了,我们需要了解的就是AArch64和AArch32两种状态下的A

使用AndFix实现Android热修复 - 2016-07-22 18:07:19

AndFix Github: https://github.com/alibaba/AndFix AndFix介绍 AndFix是一个Android App的在线热补丁框架。使用此框架,我们能够在不重复发版的情况下,在线修改App中的Bug。AndFix就是 “Android Hot-Fix”的缩写。  就目前来说,AndFix支持Android 2.3到6.0版本,并且支持arm 与 X86系统架构的设备。完美支持Dalvik与ART的Runtime。  AndFix 的补丁文件是以 .apatch 结

[置顶] VR学习 - 2016-07-22 18:07:15

VR学习 由于到去的公司从事VR这方面的开发,为了不打无准备之战,因此学习了一下Google的CardBoard VR实现。(仅仅是表皮,只是看Demo但是还是值得花点功夫看看) 效果图 这里的实现效果其实是,使用到了手机的传感器,陀螺仪(具体的往后面看) 学习Demo(再往深研究) 首先我们先看一下Demo中清单文件的权限和Activity的要求。 //请求网络权限 uses-permission android:name = "android.permission.INTERNET" / //手机NF

语音识别 - 2016-07-22 18:07:58

我使用 Speech Recognizer Intent 来获取 User Input ,然后再翻译成文本。但是我想让intent 连续的获取 user input 然后翻译成文本,来看用户是否说了某个词。现在的代码能实现,但是每次程序开始侦听输入时,电话就会发出短期的警笛声,准备输入。 有什么方法来删除已经播放过的又一次播放的声音? 代码: import java.util.ArrayList;import android.app.Activity;import android.content.Inte
前面已经分析了Android应用程序窗口View的的测量,布局过程,接下来分析View的draw过程. 在 frameworks/base/core/java/android/view/ ViewRootImpl.java中的 performTraversals()函数里调用 performLayout()函数进行布局之后,接着会调用 performDraw()函数进行绘制,现在就从这个函数开始分析 第一步: performDraw() 在 frameworks/base/core/java/androi
介绍 本篇主要是对个人对LinphoneManger类的理解及对上面的注释,这是对linphone研究的一个开始. 会慢慢对linphone逐步分析, 随着时间的推进, 我会对linphone有进一步的了解,希望希望了解的同学能跟上我的脚步. 简介 LinphoneManager类是Linphone的主要操作管理类. 主要功能: 官方 /** * * Manager of the low level LibLinphone stuff. br / * Including: ul * li Starting