如何在Android中实现异步任务

介绍

在Android应用程序中,当我们需要与可能需要时间的外部资源(例如从外部API或数据库获取数据)进行交互时,我们希望主UI保持交互,并在长时间运行的进程处于活动状态时阻止UI线程工作。另请注意,默认情况下,不允许在Android的UI线程中运行网络任务。

如果主线程用于获取外部数据,则在获取数据时主UI将不会保持交互,并且如果数据获取过程遇到异常,则可能显示异常行为。在这种情况下,android的异步任务变得很方便,尤其是使用后台线程更新UI的部分。

异步任务是将主线程的工作卸载到某个后台线程的几种方法之一。虽然AsyncTask不是唯一的选择,但这是一个简单而且非常常见的选择。

在开始之前,我想访问谷歌的开发者页面,其包含有关AsyncTask的信息,网址:https://developer.android.com/reference/android/os/AsyncTask,以查看和实现AsyncTask有关的一些内容。

这个AsyncTask类是一个abstract类。实现通常是在UI线程上运行的类的子类。AsyncTask的实现,即子类,将覆盖至少一种方法,通常是两种方法。

当执行异步任务时,任务将执行4个步骤,如Android开发人员页面中所述的,网址为https://developer.android.com/reference/android/os/AsyncTask:

  1. onPreExecute,在执行任务之前在UI线程上调用。此步骤用于设置任务,例如通过在用户界面中显示微调器。
  2. doInBackground(Params...,在完成执行后立即在后台线程上调用。此步骤用于执行可能需要很长时间的后台计算。异步任务的参数将传递给此步骤。计算结果必须由此步骤返回,并将传递回最后一步。此步骤还可用于发布一个或多个进度单位。这些值发布在UI线程上,在steponProgressUpdate(Progress...) 中
  3. onProgressUpdate(Progress...,在调用publishProgress(Progress...步骤后在UI线程上调用。执行的时间是不确定的。此方法用于在后台计算仍在执行时显示用户界面中的任何形式的进度。例如,它可用于为进度条设置动画或在文本字段中显示日志。
  4. onPostExecute(Result),在后台计算完成后在UI线程上调用。后台计算的结果作为参数传递给该步骤。

我将通过代码来说明工作机制。代码来自我为Udacity的Android纳米学位课程所做的顶点项目。完整代码可在https://github.com/benktesh/Capstone-Project获得。在本演示中,我使用代码块中显示的轻量级代码,如下所示:

package benktesh.smartstock;
import android.app.ActivityOptions;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
import java.util.ArrayList;
import benktesh.smartstock.Model.Stock;
import benktesh.smartstock.UI.CommonUIHelper;
import benktesh.smartstock.UI.StockDetailActivity;
import benktesh.smartstock.Utils.MarketAdapter;
import benktesh.smartstock.Utils.NetworkUtilities;
import benktesh.smartstock.Utils.PortfolioAdapter;
import benktesh.smartstock.Utils.SmartStockConstant;public class MainActivity extends AppCompatActivity implementsMarketAdapter.ListItemClickListener, PortfolioAdapter.ListItemClickListener {private static final String TAG = MainActivity.class.getSimpleName();CommonUIHelper mCommonUIHelper;ArrayList<Stock> mMarketData;private Toast mToast;//The following are for market summaryprivate MarketAdapter mAdapter;private RecyclerView mMarketRV;private ProgressBar spinner;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Toolbar toolbar = findViewById(R.id.toolbar);setSupportActionBar(toolbar);spinner = findViewById(R.id.progressbar);FloatingActionButton fab = findViewById(R.id.fab);fab.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Intent Email = new Intent(Intent.ACTION_SEND);Email.setType(getString(R.string.label_emailtype));Email.putExtra(Intent.EXTRA_EMAIL,new String[]{getString(R.string.label_developer_contat_email)});  //developer 's emailEmail.putExtra(Intent.EXTRA_SUBJECT,R.string.label_feedback_subject); // Email 's SubjectEmail.putExtra(Intent.EXTRA_TEXT, getString(R.string.label_address_developer) + "");  //Email 's Greeting textstartActivity(Intent.createChooser(Email, getString(R.string.label_send_feedback)));}});if (mCommonUIHelper == null) {mCommonUIHelper = new CommonUIHelper(this);}mMarketRV = findViewById(R.id.rv_market_summary);LinearLayoutManager layoutManager = new LinearLayoutManager(this);mMarketRV.setLayoutManager(layoutManager);mMarketRV.setHasFixedSize(true);mAdapter = new MarketAdapter(mMarketData, this);mMarketRV.setAdapter(mAdapter);LoadView();}private void LoadView() {Log.d(TAG, "Getting Market Data Async");new NetworkQueryTask().execute(SmartStockConstant.QueryMarket);}private void MakeToast(String msg) {Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();}public boolean onCreateOptionsMenu(Menu menu) {return mCommonUIHelper.ConfigureSearchFromMenu(menu);}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.if (mCommonUIHelper.MakeMenu(item)) return true;return super.onOptionsItemSelected(item);}@Overridepublic void onListItemClick(Stock data) {if (mToast != null) {mToast.cancel();}Intent intent = new Intent(this.getApplicationContext(), StockDetailActivity.class);intent.putExtra(SmartStockConstant.ParcelableStock, data);Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(this).toBundle();startActivity(intent, bundle);}/*This is an async task that fetches data from network and new data is applied to adapter.Also makes a long toast message when fails to retrieve information from the networkIt takes void, void and returns ArrayList<?>*/class NetworkQueryTask extends AsyncTask<String, Integer, ArrayList<Stock>> {private String query;@Overrideprotected void onPreExecute() {if (spinner != null) {spinner.setVisibility(View.VISIBLE);}}@Overrideprotected ArrayList<Stock> doInBackground(String... params) {query = params[0];ArrayList<Stock> searchResults = null;try {searchResults = NetworkUtilities.getStockData(getApplicationContext(), query);for (int i = 0; i <= 100; i = i + 25) {Thread.sleep(500);publishProgress(i);}} catch (Exception e) {Log.e(TAG, e.toString());}return searchResults;}@Overrideprotected void onProgressUpdate(Integer... progress) {super.onProgressUpdate(progress);Toast.makeText(getApplicationContext(), "Progress:  " + progress[0] + "(%)", Toast.LENGTH_SHORT).show();}@Overrideprotected void onPostExecute(ArrayList<Stock> searchResults) {super.onPostExecute(searchResults);if (searchResults != null && searchResults.size() != 0) {mAdapter.resetData(searchResults);}if (spinner.getVisibility() == View.VISIBLE) {spinner.setVisibility(View.GONE);}}}
}

NetworkQueryTask类作为类MainActivity的子类实现和子类扩展了Android的AsyncTask abstract类。子类可以定义如下:

private class NetworkQueryTask extends AsyncTask<T1, T2, T3> {...}

T1,T2和T3是参数的数据类型,而它们每个人都有一些特定的含义。

上面定义的任务可以执行如下:

new NetworkAsyncTask().execute(param1);

param1的类型与T1的类型相同。

将MainActivity在UI线程上运行。' onCreate(..)'方法确实设置了UI。设置涉及为回收器视图等创建适配器,最后调用 LoadView()。LoadView()方法执行AsyncTask从网络获取数据和更新视图的适配器。

在这样做的过程中,我们创建了一个从AsyncTask中扩展的子类NetworkQueryTask。该类有三个参数string,Void 和ArrayList<Stock>。stock是一个存储Stock信息的简单类。一旦进程开始,我们希望我们可以在doInBackground(..)方法中看到微调器。

在上面的任务中,这三个参数表示用于doInBackground(T1 param1),onProgressUpdate(T2 param2) 和onPostExecute(T3 param3)的输入参数的类型。当doInBackground步骤完成执行时,param3将是doInBackground步骤的输出,并将成为该onPostExecute(param3)方法的输入。

子类通常至少覆盖一种方法,最常见的是doInBackground(..)方法,也包括第二种方法,即onPostExecute()。该onProgressUpdate 和onPreExecute()方法是可选的,可以跳过的。因此,如果没有关于进度更新的任何事情,那么就不需要覆盖onProgressUpdate ,然后param2 可以是在类定义本身中的Void类型。例如,假设需要将string参数传递给doInBackground()而不需要onProgressUpdate()方法,并且该onPostExecute()方法接受一个string参数,那么类定义将如下所示:

private class NetworkQueryTask extends AsyncTask<String, Void, String> {...}

因此,我们可以说这三个参数分别代表doInBackground输入,onProgressUpdate()输入和onPostExecute输入。doInBackground输出的参数类型与onPostExectute()输入相同。此外,如果async任务是作为启动而忘记诸如触发某事,那么所有参数都可以是void。例如,在这种情况下,子类的定义如下所示:

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

上面的类执行如下:

new NetworkAsyncTask().execute();

AsyncTasks不知道应用程序中的其他活动,因此必须在销毁活动时正确处理。因此,AsycnTask不适合长时间运行的操作,因为如果应用程序在后台运行,当Android的终止调用AsyncTask的应用程序时,AsyncTask不会被杀死,我们必须管理的如何处理AsyncTask结果的过程。因此,AsyncTasks在获取不长时间运行的数据时很有用。AyscTask还有其他选择,包括IntentServices,Loader和JobScheduler以及许多基于Java的实现。

原文地址:https://www.codeproject.com/Articles/1277153/Implementing-Async-Tasks-in-Android

在Android中实现异步任务相关推荐

  1. 浅谈Android中的异步加载之ListView中图片的缓存及优化三

    隔了很久没写博客,现在必须快速脉动回来.今天我还是接着上一个多线程中的异步加载系列中的最后一个使用异步加载实现ListView中的图片缓存及其优化.具体来说这次是一个综合Demo.但是个人觉得里面还算 ...

  2. android 实现异步加载图片,Android中ImageView异步加载图片类

    本源码是从网络找到经修改以方便直接调用感觉用着还可以 首先在项目中添加一个专门加载图片的类AsyncImageLoaderpackage com.demo.core; import java.io.I ...

  3. linux的ftp轮询上传文件,Android中实现异步轮询上传文件

    前言 前段时间要求项目中需要实现一个刷卡考勤的功能,因为涉及到上传图片文件,为加快考勤的速度,封装了一个异步轮询上传文件的帮助类 效果 先上效果图 设计思路 数据库使用的框架是GreenDao,一个非 ...

  4. Android中的多线程编程与异步处理

    Android中的多线程编程与异步处理 引言 在移动应用开发中,用户体验是至关重要的.一个流畅.高效的应用能够吸引用户并提升用户满意度.然而,移动应用面临着处理复杂业务逻辑.响应用户输入.处理网络请求 ...

  5. Android线程之异步消息处理机制(二)——Message、Handler、MessageQueue和Looper

    异步消息处理机制解析 Android中的异步消息处理主要有四个部分组成,Message.Handler.MessageQueue和Looper. 1.Message Message是在线程之间传递的消 ...

  6. 具体解释Android中AsyncTask的使用

    在Android中实现异步任务机制有两种方式,Handler和AsyncTask. Handler模式须要为每个任务创建一个新的线程,任务完毕后通过Handler实例向UI线程发送消息,完毕界面的更新 ...

  7. 详解Android中AsyncTask的使用

    在Android中实现异步任务机制有两种方式,Handler和AsyncTask. Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更 ...

  8. Android中使用Handler和异步任务(AsyncTack)来为UI线程执行费时操作

    出于性能优化的考虑,Android的UI线程不是线程安全的.这致使我们不能在Android的UI线程中执行一些费时的操作,如下载.刷新等.Android中只允许UI线程对Activity中的UI组件进 ...

  9. android 异步刷新 方法,android应用中实现异步更新UI的方法有哪些

    android应用中实现异步更新UI的方法有哪些 发布时间:2020-12-07 17:12:00 来源:亿速云 阅读:144 作者:Leah android应用中实现异步更新UI的方法有哪些?相信很 ...

最新文章

  1. 我用的archlinux+slim+openbox+tint2+feh+thunar+gnome-terminal+gvim+fcitx
  2. Java 堆内存模型
  3. 自动加密企业关键业务数据 赛门铁克推出全新信息保护解决方案
  4. 异常的捕获 try...catch java
  5. C#LeetCode刷题之#4-两个排序数组的中位数(Median of Two Sorted Arrays)
  6. Linux 命令(19)—— tar 命令
  7. 浏览器调试动态js脚本
  8. 软件测试 vb,使用VB6.0进行自动化测试
  9. MATLAB自定义函数并绘制
  10. matlab发动机建模,基于MATLAB/SIMULINK的航空发动机建模与仿真研究
  11. js校验 身份证号18位
  12. MSN机器人 博客助手 for I-Favourite
  13. R语言 formula()
  14. 936烙铁芯发热芯型号判断
  15. 使用Apache Spark SQL探索标普500和石油价格
  16. 三重邪骨手机版怎么登录服务器未响应,三重邪骨锁血版
  17. 浅谈企业数据安全治理
  18. 申请抖音企业认证流程
  19. ubuntu服务器的安装(转载)
  20. WiFi(Wireless Fidelity)基础(四)

热门文章

  1. python查找字符串出现次数_Python搜索文本文件并计算指定字符串的出现次数
  2. 安卓rtmp推流app_同城直播电商APP小程序平台开发
  3. ul c语言,IMX6UL裸机实现C语言蜂鸣器实验
  4. 如何更改应用路径_【电脑】实用技巧分享:如何更改电脑桌面路径?
  5. python模拟访问js_python模拟http请求,返回“浏览器不支持javascript,请设置您的浏览器开启javascript支持”...
  6. c语言计算分段函数_Rust能够取代C语言吗?
  7. 免扣(抠)PNG格式图片,让你告别抠图之痛!
  8. 创意合成广告欣赏:让人脑洞大开的设计
  9. 平安夜海报PNG免扣素材来了,全都在这|搜图114
  10. 万能电商Banner素材模板,一切产品为王