Android AsyncTask 源码分析详解

掌握Android开发中的AsyncTask异步处理 本文还有配套的精品资源,点击获取 简介:在Android开发中, AsyncTask 是处理后台任务并在UI线程中更新结果的一种简便方式,以避免UI阻塞。本文将介绍如何在Android活动中使用 AsyncTask 来执行异步任务,包括其三个泛型参数的定义、主要方法的使用,以及一个简单的实践示例。尽管 AsyncTask 有其限制,... 阅读详情

一、AsyncTask 简介

AsyncTask
public abstract class AsyncTask
extends Object
java.lang.Object
    ↳ android.os.AsyncTask< Params, Progress, Result >

      AsyncTask是一个抽象类,它是由Android封装的一个轻量级异步类,它可以很方便的使用UI线程,执行后台任务,并可以把执行的程序和运行的结果给Ui线程处理,而无需实现Thread和handler。

二、AsyncTask 使用

1、AsyncTask的泛型类型

      异步任务使用的三种类型如下:

Params : 执行时发送给任务的参数类型。
Progress : 后台执行任务进度的进度类型。
Result : 异步任务最终返回的结果类型。

      并非所有类型都始终由异步任务使用。如果不指定,只需使用以下类型Void:

private class MyTask extends AsyncTask<Void, Void, Void> { ... }

2、五个方法

执行异步任务时,任务将执行4个方法:
1、onPreExecute(),刚开始执行的时候调用,可以用于进行一些界面上的初始化操作,比如说显示一个进度条对话框
2、doInBackground(Params...),在onPreExecute()完成执行后立即在后台线程上调用,执行在异步线程, 耗时的操作在这个方法中执行。返回结果被传递到 onPostExecute(), 在执行任务时调用publishProgress()把执行进度传递给 onProgressUpdate()。
3、onProgressUpdate(Progress...)执行在UI线程, 更新进度信息, 调用publishProgress() 时被回调。
4、onPostExecute(Result),执行在UI线程, 一般在执行完后台任务后更新UI的操作, 显示结果等
除了上面四个方法,AsyncTask还提供了onCancelled()方法,它同样在主线程中执行,当异步任务取消时,onCancelled()会被调用,这个时候onPostExecute()则不会被调用,但是要注意的是,AsyncTask中的cancel()方法并不是真正去取消任务,只是设置这个任务为取消状态,我们需要在doInBackground()判断终止任务。就好比想要终止一个线程,调用interrupt()方法,只是进行标记为中断,需要在线程内部进行标记判断然后中断线程。

3、AsyncTask 使用的实例

      我在前面的博客里写了一个AsyncTask 使用OKHttp 实现断点下载大文件实例,效果图如下:
这里写图片描述
      想了解怎么使用的可以看Android 启动服务配合AsyncTask 使用OKHttp 实现断点下载大文件实例这篇文章。

三、 AsyncTask 源码分析

      我打开的是Android 8.1 版本的AsyncTask 源码;

1、构造函数:

/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 *  创建一个新的异步任务。, 必须在UI线程上调用此构造函数。
 */
public AsyncTask() {
    this((Looper) null);
}

/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 *
 * @hide
 */
public AsyncTask(@Nullable Handler handler) {
    this(handler != null ? handler.getLooper() : null);
}

/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 *
 * @hide
 */
public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() 
        ? getMainHandler()
        : new Handler(callbackLooper);

    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            ...
            return result;
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
            ...
        }
    };
}

      在构造函数里面,能看到创建了三个变量,分别是mHandler、mWorker以及mFuture。

(1)mHanlder

      因为第二个以及第三个构造函数都被隐藏的缘故,所以 mHandler 只能是 getMainHandler(),我们看下这个方法的实现。

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

private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }

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

      AsyncTask 里面使用的是InternalHanler ,里面绑定了主线程的Looper和消息队列。如果handler收到的是MESSAGE_POST_RESULT消息,就会执行finish()方法,最后调用onPostExecute()方法。如果handler收到的是MESSAGE_POST_PROGRESS消息,就会执行onProfressUpdate()方法。

(2)mWorker

      mWorker 是 WorkerRunnable 类型的内部类对象:

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

       WorkerRunnable 实现了Callable 接口,接口中只有一个 call() 方法。因为不论是继承Thread类还是实现Runnable 方法,执行完任务以后都无法直接返回结果。而Callable接口弥补了这个缺陷,当call()方法执行完毕以后会返回一个泛型对象,而mWorker 重写了 call方法。
      Callable 接口实际上是属于Executor 框架中的功能类,Callable 接口与Runnable 接口的功能类似,但提供了比Runnable更强大的功能,主要表现为以下三点:
(1)Callable可以在任务接受后提供一个返回值,Runnable无法提供这个功能。
(2)Callable中的call()方法可以抛出异常,而Runnable的run()方法不能抛出异常。
(3)运行Callable可以拿到一个Future对象,Future对象表示异步计算的结果,他提供了检查计算是否完成的方法。由于线程属于异步计算模型,因此无法从别的线程中得到函数的返回值,在这种情况下就可以使用Future来监视目标线程调用call()方法的情况,但调用Future的get()方法以获取结果时,当前线程就会阻塞,直到call()方法的返回结果。
       我们继续看下call()方法里面执行了什么:

public Result call() throws Exception {
    //先设置mTaskInvoked为true,表示线程已经开始
    mTaskInvoked.set(true);
    Result result = null;
    try {
        //设置当前的线程级别为标准优先级后台线程级别
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        //noinspection unchecked
        result = doInBackground(mParams);
        Binder.flushPendingCommands();
    } catch (Throwable tr) {
        mCancelled.set(true);
        throw tr;
    } finally {
        postResult(result);
    }
    return result;
}

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

       首先要明确的一点,call() 一定是在线程池的子线程中执行的,并没有执行在主线程中。当call() 执行的时候,先设置mTaskInvoked 为true,表示线程已经开始。接下来设置当前的线程级别为标准优先级后台线程级别,使您的线程略低于正常优先级,因此它将不太可能影响用户界面的响应性。然后在子线程中执行doInBackground()方法并将处理结果返回,最后将执行完的结果交给postResult()。继续看postResult() 方法,getHandler 获取的其实就是刚刚定义的mHandler,这时mHandler就会收到的是MESSAGE_POST_RESULT消息,就会执行finish()方法,最后调用onPostExecute()方法。

(3)mFuture
public class FutureTask<V> implements RunnableFuture<V> {
    ... 
}

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     * 将此Future设置为其计算结果,除非它已被取消。
     */
    void run();
}

      mFuture 实现了RunnableFuture接口,而Runnablefuture 最终继承Runnable 和 Future 接口,这里我们说一下Future接口:
  在Future接口中声明了5个方法,下面依次解释每个方法的作用:
1、cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
2、isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
3、isDone方法表示任务是否已经完成,若任务完成,则返回true;
4、get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
5、get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
也就是说Future提供了三种功能:
(1)判断任务是否完成;
(2)能够中断任务;
(3)能够获取任务执行结果。
  因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。所以FutureTask既能当做一个Runnable直接被Thread执行,也能作为Future用来得到Callable的计算结果。
  我们来看下mFuture的done 方法实现了哪些内容:

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);
    }
}

private void postResultIfNotInvoked(Result result) {
    final boolean wasTaskInvoked = mTaskInvoked.get();
    if (!wasTaskInvoked) {
        postResult(result);
    }
}

  当任务的状态的变化时就会执行done 此方法,然后可以看到执行了postResultIfNotInvoked()方法。当wasTaskInvoked 为false的时候执行postResult(result) 方法,但是在执行mWorker的call()方法的时候,已经将wasTaskInvoked设为了true。所以当任务执行完后或者取消后才会执行postResult(result)这个方法。

2、execute 方法

  在实例化了AsyncTask对象之后,我们就可以调用AsyncTask的execute方法执行任务,execute代码如下所示:

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

@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params) {
    if (mStatus != Status.PENDING) {
        switch (mStatus) {
            case RUNNING:
                //如果当前AsyncTask已经处于运行状态,那么就抛出异常,不再执行新的任务
                throw new IllegalStateException("Cannot execute task:"
                    + " the task is already running.");
            case FINISHED:
                //如果当前AsyncTask已经把之前的任务运行完成,那么也抛出异常,不再执行新的任务
                throw new IllegalStateException("Cannot execute task:"
                    + " the task has already been executed "
                    + "(a task can be executed only once)");
        }
    }
    //将AsyncTask的状态置为运行状态
    mStatus = Status.RUNNING;
    //在真正执行任务前,先调用onPreExecute方法
    onPreExecute();
    // sDefaultExecutor 执行 mFuture
    mWorker.mParams = params;
    exec.execute(mFuture);
    //最后将AsyncTask自身返回
    return this;
}

  在execute方法上,注意到有@MainThread,所以这个方法是在主线程中执行的。在方法里执行了executeOnExecutor()方法,并把sDefaultExecutor也传了进去,我们先看executeOnExecutor() 方法。一开始先判断了AsyncTask的状态,当状态不是PENDING即任务尚未开始执行时,抛出两个异常并不再执行,这就意味着Asynctask只能执行一次。当AsyncTask 的状态为尚未开始执行的时候,将状态改为运行状态并执行onPreExecute()方法,用 mWorker.mParams 保存传入的参数,然后调用sDefaultExecutor执行 mFuture。
  sDefaultExecutor是SerialExecutor的一个实例:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static class SerialExecutor implements Executor {
    // mTasks是一个维护Runnable的双端队列实例,ArrayDeque没有容量限制,其容量可自增长
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    // mActive 正在执行的任务
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
        // 向队尾插入一个Runnable
        mTasks.offer(new Runnable() {
            public void run() {
                try {
                    // 开始执行任务
                    r.run();
                } finally {
                    // 调用scheduleNext() 执行下一个Runnable
                    scheduleNext();
                }
            }
        });
        // 如果mActive 为空 执行下一个Runnable
        if (mActive == null) {
            scheduleNext();
        }
    }

    protected synchronized void scheduleNext() {
        // mTasks.poll() 取出队列头部的元素,并从队列中移除 
        // 将取出队列的Runnable 赋值给mActive,如果不为空则交给THREAD_POOL_EXECUTOR去执行
        if ((mActive = mTasks.poll()) != null) {
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

  SerialExecutor是一个串行的线程池,当sDefaultExecutor执行execute()方法的时候,开始执行SerialExecutor类的execute() 方法,会向mTasks 的队尾添加一个新建的Runnable,其内部会调用 r.run();无论任务r正常执行完成还是抛出异常,都会在finally中执行scheduleNext方法,用于执行mTasks中的下一个任务。因此,我们可以看出SerialExecutor是一个接一个的处理任务,是串型执行任务,而不是并行执行任务。当mActive 为空的时候, 也会开始执行下一个Runnable。这里的任务都是交给THREAD_POOL_EXECUTOR(线程池)去处理的,我们看下THREAD_POOL_EXECUTOR:

/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 */
public static final Executor THREAD_POOL_EXECUTOR;

static {
    // 创建一个线程池
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            sPoolWorkQueue, sThreadFactory);
    //允许核心线程超时
    threadPoolExecutor.allowCoreThreadTimeOut(true);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

  THREAD_POOL_EXECUTOR指的就是threadPoolExecutor,他的核心线程和线程池允许创建的最大线程数都是由CPU的核数来计算出来的,它采用的阻塞队列是LinkedBlockingQueue。

总结

  关于源码的讲解到这里就结束了,我们来梳理下整个流程。当我们继承AsyncTask实现自定义的异步任务时,会初始化三个值,分别是mHandler、mWorker以及mFuture。然后当我们调用AsyncTask的execute方法执行任务的时候,在execute()方法里先判断一下状态,然后将状态改为运行状态并执行onPreExecute()方法,用 mWorker.mParams 保存传入的参数,然后通过SerialExecutor线程池用于任务的排队,让需要执行的多个耗时任务,按顺序排列,最后再调用THREAD_POOL_EXECUTOR线程池去真正地执行任务mFuture,进而会执行mWorker 的call() 方法,先设置mTaskInvoked 为true,表示线程已经开始。接下来设置当前的线程级别为标准优先级后台线程级别,然后在子线程中执行doInBackground()方法并将处理结果返回,最后将执行完的结果交给postResult()。在postResult方法中,获取到mHandler,这时mHandler就会收到的是刚刚发出的MESSAGE_POST_RESULT消息,然后执行finish()方法,最后调用onPostExecute()方法,并将AsyncTask的状态设置为完成状态。

Android最全最简单的异步任务AsyncTask使用解析 Android最全最简单的异步任务AsyncTask使用解析.一步到位彻底理解异步任务。 立即下载

相关推荐

nnDetection实战:手把手教你用Python在自家电脑上跑通第一个肺结节检测模型

本文详细介绍了如何使用nnDetection框架在普通电脑上实现肺结节检测模型的搭建与运行。从环境配置、数据预处理到模型训练与推理,手把手教你完成医学图像检测的全流程,特别适合初学者入门医学AI领域。

weixin_32377497的博客 330

Android AsyncTask 详解

将复杂工作异步化、线程化对于Android 的性能的提高起到了很重要的作用,Android 框架为开发提供了很多辅助程序,这一篇着重分析Android AsyncTask的原理。

私房菜 6810

利用AI辅助工具Codex在30分钟内高效生成发明专利说明书草案

Codex 是什么?简单说,它是 OpenAI 推出的一个高级 AI 工作平台,最初定位是软件开发辅助工具,但现在它的能力边界已经远远超出了写代码。根据 OpenAI 官方信息,每周有超过 500 万人使用 Codex,其中 40% 的新用户是非开发者,包括分析师、营销人员、研究人员等。这意味着 Codex 正在从一个程序员专属工具,演变为一个面向广泛知识工作者的生产力中枢。 那么,它和我们今天要谈的“写发明专利”有什么关系?核心在于 Codex 的“角色专属插件”和“上下文构建”能力。它不再只是根据零散的

weixin_29053067的博客 318

Android AsyncTask(线程间通信)

1.AsyncTask 在Android中我们可以通过Thread+Handler实现多线程通信,一种经典的使用场景是:在新线程中进行耗时操作,当任务完成后通过Handler向主线程发送Message,这样主线程的Handler在收到该Message之后就可以进行更新UI的操作。上述场景中需要分别在Thread和Handler中编写代码逻辑,为了使得代码更加统一,我们可以使用AsyncTask类。 AsyncTask是Android提供的一个助手类,它对Thread和Handler进行了封装,方便我们使用。

zenmela2011的专栏 6742

CCS TMSC6748 报错Error connecting to the target: (Error -600 @ 0x0)

CCS TMSC6748 报错Error connecting to the target:(Error -600@ 0x0)

AS_the_deer1717的博客 6632

BRepNet与图神经网络融合:提升3D CAD加工特征识别的精度与泛化能力

本文探讨了BRepNet与图神经网络(GNN)融合技术如何显著提升3D CAD加工特征识别的精度与泛化能力。通过将CAD模型视为图结构,利用GNN的消息传递机制增强对复杂拓扑关系的理解,并结合BRepNet的局部特征提取,该融合方法在MFCAD++数据集上实现了高达99.53%的准确率,有效解决了传统方法在处理复杂相交特征时的局限性,为智能制造提供了关键技术支撑。

android的专栏 774

Android 异步任务类之AsyncTask 完全解析

Android 异步任务类之AsyncTask 完全解析

weixin_42504805的博客 2366

【干货】SAP特殊库存:Q库存(项目库存)全解析,搞懂ETO模式的核心!

在 SAP 系统中,

我小时候很黑的博客 901

40. 【Android教程】AsyncTask:异步任务

AsyncTask 类通常用来在执行后台任务的同时刷新 UI,通过调用execute()方法触发后台任务的执行,首先会回调 AsyncTask 的,接着回调来执行自定义的后台任务,最后回调。

这是一个web全栈开发的博客,取其精华去其糟粕,争取让大家一看就懂,一学就会,一用就成~ 2212

MIKE 21 教程 2.2 Domain, Time, Module Selection设置教学

上一节讲解了水动力模型的基本概念与文件创建MIKE 21 教程 2.1水动力模型介绍​本节讲解水动力模型前三个模块的设置此模块需导入之前绘制好的网格文件,导入后可预览网格文件点击上方的Domain Specification可查看网格的数据统计与高程属性,快速检查网格文件有无明显错误 点击上方的Boundary names,可查看之前定义的出入水边界。在网格文件中,我们对边界只能以数字属性进行区分,这里可以对数字属性进行命名,在name中直接修改即可。本实例中我们的2代表入水边界,3代表出水边界。因为博主日

Hello Word 3865

SAP_SD模块销售开票计划预收款系统配置及前台操作说明

在 SAP SD 中,开票计划(Billing Plan)是一种允许根据时间节点或里程碑对销售订单进行分期开票的功能。其中最常见的一种应用就是预收款(Down Payment Billing),即在销售订单中直接定义某个百分比或金额作为预收款,系统在开票时自动生成预收账单。大额合同或长期项目型销售(先收 20%,交货前收 30%,交货后收 50%)。分期付款模式(分阶段收款)。必须预收款才能安排生产或交货的业务。后台路径:SPRO—销售与分享—销售—销售凭证—销售凭证项目—定义项目类别。

我小时候很黑的博客 1407

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

工匠若水 http://blog.youkuaiyun.com/yanbober 1 背景 当使用线程和Handler组合实现异步处理时,当每次执行耗时操作都创建一条新线程进行处理,性能开销会比较大。为了提高性能我们使用AsyncTask实现异步处理(其实也是线程和handler组合实现),因为其内部使用了java提供的线程池技术,有效的降低了线程创建数量及限定了同时运行的线程数,还有一些

朱志辉的博客 738

【计算机视觉 | MMDetection】关于mmdetection如何计算参数量、计算量和速度FPS

【计算机视觉 | MMDetection】关于mmdetection如何计算参数量、计算量和速度FPS

wzk4869的博客 3021

2024年Android最全Android应用AsyncTask处理机制详解及源码分析(3),2024年最新安卓面试题及答案100套

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的14套腾讯、字节跳动、阿里、百度等2021面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

2401_84123077的博客 939

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

【转载】Android应用AsyncTask处理机制详解及源码分析

【工匠若水 http://blog.youkuaiyun.com/yanbober 转载烦请注明出处,尊重分享成果】 1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个知识点。前面我们分析了Handler异步机制原理(不了解的可以阅读我的《Android异步消息处理机制详解及源码分析》文章),这里继续分析Android的另一个异步机制Async...

aoshu5722的博客 174

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Android应用AsyncTask处理机制详解及源码分析,移动互联网开发

Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个知识点。前面我们分析了Handler异步机制原理(不了解的可以阅读我的《Android异步消息处理机制详解及源码分析》文章),这里继续分析Android的另一个异步机制AsyncTask的原理。 当使用线程和Handler组合实现异步处理时,当每次执行耗时操作都创建一条新线程进行处理,性能开销会比较大。为了提高性能我们使用AsyncTask实现异步处理(其实也是线程和handler组合实现),因为其内部使用了java提供的线

m0_64383184的博客 446

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Android应用AsyncTask处理机制详解及源码分析,flutter环境搭建

mDialog.show(); } //这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务 protected Boolean doInBackground(Void… params) { while (mCount < 100) { publishProgress(mCount); mCount += 20; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }

m0_65145685的博客 140
上一篇: Android 画板(简单的自定义控件)
下一篇: Android QQ、微信、Facebook和推特第三方登录
谦行
博客等级 码龄11年 182粉丝 35原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值