在上一个例子中,我们是在LoadImage的onPostExecute中修改的UI,不是说只允许在主线程中修改UI吗?我们看一下源代码是如何操作的。

MainActicity.java

package cn.lixyz.asynctest;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar; import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection; public class MainActivity extends Activity{ private Button button;
private ImageView imageView;
private ProgressBar progressBar;
private String URL="http://ww3.sinaimg.cn/bmiddle/612c96afjw1ewwftl3uqkj20u00koq48.jpg"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获取组件
button = (Button) findViewById(R.id.button);
imageView = (ImageView) findViewById(R.id.imageView);
progressBar = (ProgressBar) findViewById(R.id.progressBar); //给button设置点击事件,点击按钮,启动异步任务
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new LoadImage().execute(URL);
}
}); } class LoadImage extends AsyncTask<String,Void,Bitmap>{ //开始执行耗时操作,连接网络获取图片,并且将Bitmap返回
@Override
protected Bitmap doInBackground(String... params) {
String url = params[0];
Bitmap bitmap = null;
URLConnection connection;
InputStream is;
try {
connection = new URL(url).openConnection();
Thread.sleep(5000);
is = connection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bitmap = BitmapFactory.decodeStream(bis);
is.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return bitmap;
} //onPreExcute方法是在doInBackGround方法前执行,用于做一些初始化操作,这里将progressBar显示出来
@Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setVisibility(View.VISIBLE);
} //doInBackGround方法执行后,会自动执行该方法,获取到doInBackGround返回的对象,然后更改UI
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
progressBar.setVisibility(View.GONE);
imageView.setImageBitmap(bitmap);
}
}
}

acticity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="4">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
<ProgressBar
android:id="@+id/progressBar"
android:visibility="gone"
android:layout_centerInParent="true"
style="@style/Widget.AppCompat.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout> <Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="点击载入" />
</LinearLayout>

先找到AsyncTask的构造函数:

    public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
}; 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 occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}

可以看到在AsyncTask的构造函数中,仅仅初始化了两个变量 mWorker 和 mFuture

接着启动AsyncTask,我们找到 execute 方法:

    @MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}

可以看到,在 execute() 方法中,只执行了一个 executeOnExecutor() ,我们继续看executeOnExecutor方法:

    @MainThread
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;
}

可以看到,在 executeOnExecutor() 方法中,先判断了AsyncTask的状态,如果是 RUNNING 或者是 FINISHED 的话,则会抛出 IllegalStateException 异常,如果不是,则将AsyncTask的状态设置为 RUNNING  ,然后执行 onPreExecute() 方法,我们再看这个方法:

    @MainThread
protected void onPreExecute() {
}

这个方法又没有做任何操作,之前我们讲过, onPreExecute() 方法是在执行 doInBackGround() 之前执行,用来做一些初始化操作的,所以如果我们有需要的话,就需要自己重写 onPreExecute() 方法了。

  接着看 executeOnExecutor() 方法,在执行完 onPreExecute() 方法之后,继续往下,将 params 赋值给 mWorker.mParams 之后,又执行了 exec.execute(mFuture) , mFuture 是在前面的构造方法中初始化的,我们看代码:

    public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
}; 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 occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}

  可以看到在这里调用了 doInBackground() 方法,并最后返回了 postResult(result) ,再继续看,找到 postResult(result)

    private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}

  可以看到,在这部分代码中,显示获取到了一个Handler,然后调用这个Handler对象的obtainMessage()方法得到一个Message对象,我们看一下获取到的这个Handler对象:

    private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}

  发现是一个 InternalHandler 对象,继续找这个 InternalHandler 对象

    private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
} @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}

  这里就清楚了,获取到的是一个 MainLooper ,也就是说获取的是在主线程中的Handler,也就是说,上面的操作最后将Message发送到了主线程中,然后根据发送过来的消息是  MESSAGE_POST_RESULT  还是 MESSAGE_POST_PROGRESS 来判断该执行什么方法

  如果是 MESSAGE_POST_RESULT  ,我们查看finish方法:

    private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}

  到这里,就一目了然了,调用了onPostResult方法更新UI。

  整个流程走完,会发现其实AsyncTask还是Handler机制,只不过是对线程做了优化和封装而已

更多内容:

  Android应用AsyncTask处理机制详解及源码分析

  Android异步类AsyncTask详解

Android笔记(三十六) AsyncTask是如何执行的?的更多相关文章

  1. Android中GridView拖拽的效果【android进化三十六】

      最 近看到联想,摩托罗拉等,手机launcher中有个效果,进入mainmenu后,里面的应用程序的图标可以拖来拖去,所以我也参照网上给的代码,写了 一个例子.还是很有趣的,实现的流畅度没有人家的 ...

  2. Android笔记三十四.Service综合实例二

    综合实例2:client訪问远程Service服务 实现:通过一个button来获取远程Service的状态,并显示在两个文本框中. 思路:如果A应用须要与B应用进行通信,调用B应用中的getName ...

  3. 论文阅读笔记三十六:Mask R-CNN(CVPR2017)

    论文源址:https://arxiv.org/pdf/1703.06870.pdf 开源代码:https://github.com/matterport/Mask_RCNN 摘要 Mask R-CNN ...

  4. 【Unity 3D】学习笔记三十六:物理引擎——刚体

    物理引擎就是游戏中模拟真是的物理效果.如两个物体发生碰撞,物体自由落体等.在unity中使用的是NVIDIA的physX,它渲染的游戏画面很逼真. 刚体 刚体是一个很很中要的组件. 默认情况下,新创的 ...

  5. Android笔记(七十六) 点菜DEMO

    一个朋友让看一下他的代码,一个点菜的功能,他和我一样,初学者,代码比我的都混乱,也是醉了,干脆想着自己写个demo给他看,原本想着听简单,半个小时应该就可以搞定,真正写的时候,画了3h+,汗颜... ...

  6. Android笔记(十六) 简易计算器

    实现功能: 简单计算器 布局及美化 采用LinearLayout嵌套LinearLayout实现布局. 要求 1. 按钮所有文字居于右下角 2. 按钮为白色,点击变成橘色 3. 显示屏文字居右显示并且 ...

  7. PHP学习笔记三十六【try 二】

    <?php //定义一个顶级异常处理器 要定义在最上面 function my_exception($e) { echo "我是顶级异常处理:".$e->getMess ...

  8. BizTalk开发系列(三十六) Orchestration单实例执行

    BizTalk 是高效的消息处理引擎,采用多线程并发的方式来处理消息.也就是说当有消息被接收的时候就会产生一个新的消息处理实例.但有时目标系统可能并没有并发处理 的能力, 这时就需要在BizTalk中 ...

  9. Nodejs学习笔记(十六)--- Pomelo介绍&入门

    目录 前言&介绍 安装Pomelo 创建项目并启动 创建项目 项目结构说明 启动 测试连接 聊天服务器 新建gate和chat服务器 配置master.json 配置servers.json ...

  10. Nodejs学习笔记(十六)—Pomelo介绍&入门

    前言&介绍 Pomelo:一个快速.可扩展.Node.js分布式游戏服务器框架 从三四年前接触Node.js开始就接触到了Pomelo,从Pomelo最初的版本到现在,总的来说网易出品还算不错 ...

随机推荐

  1. Mysql按日、周、月进行分组统计

    我们在用 Mysql 制作数据可视化图表时候,经常需要按照天.周.月等不同的粒度对数据进行分组统计.而我们的时间可能是 “2017/12/5 0:0:0” 这种准确的时间. 所以在进行分组之前我们需要 ...

  2. Nginx记录-Proxy_pass多个应用配置(转载)

    1. 在http节点下,加入upstream节点. upstream linuxidc {       server 10.0.6.108:7080;       server 10.0.0.85:8 ...

  3. React之改变页面上方图标

    首先在public/index.html中 <!-- <link rel="shortcut icon" href="%PUBLIC_URL%/bitbug6 ...

  4. windows中怎么添加定时任务

    linux中有crontab定时任务,很方便 其实windows也有类似的 需求:定时执行python脚本 1.Windows键+R,调出此窗口,输入compmgmt.msc 2. 每分钟都执行一次脚 ...

  5. LeetCode 328. 奇偶链表(Odd Even Linked List)

    328. 奇偶链表 328. Odd Even Linked List 题目描述 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起.请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是 ...

  6. LeetCode 13. 罗马数字转整数(Roman to Integer)

    13. 罗马数字转整数 13. Roman to Integer 题目描述 罗马数字包含以下七种字符: I,V,X,L,C,D 和 M. 字符        数值  I           1  V  ...

  7. This view is not constrained, it only has designtime positions, so it will jump to (0,0) unless you

    Android Studio报错 这个视图只是编辑时位置,在运行时视图会跳转到(0,0) 解决办法: 在Design界面下,有个魔棒工具,Infer Constrains,点击之后就可以了

  8. AR*客户地点分配OU

    DECLARE p_cust_acct_site_rec hz_cust_account_site_v2pub.cust_acct_site_rec_type; p_cust_site_use_rec ...

  9. 第一二章、C++简介和基本语法

    C++简介 C++包含了三种编程模式,分别是面向过程.面向对象和泛型编程. 程序执行过程 C++编程格式 C++每个程序都会有main()函数作为入口,基本编程包括预处理/头文件.函数.输入输出语句等 ...

  10. python基础 — 循环重新输入

    后续完善各种循环案例 while True: try: str_num = input('input a number:') num = float(str_num) print("你输入的 ...