如何在Android中实现异步任务

在Android应用程序中,当咱们须要与可能须要时间的外部资源(例如从外部API或数据库获取数据)进行交互时,咱们但愿主UI保持交互并阻止UI线程在长时间运行的进程中运行很活跃。 另请注意,默认状况下,不容许在Android的UI线程中运行网络任务。 若是主线程用 在Android应用程序中,当咱们须要与可能须要时间的外部资源(例如从外部API或数据库获取数据)进行交互时,咱们但愿主UI保持交互并阻止UI线程在长时间运行的进程中运行很活跃。另请注意,默认状况下,不容许在Android的UI线程中运行网络任务。java

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

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

在开始以前,我想访问谷歌的开发者页面包含的信息AsyncTask在https://developer.android.com/reference/android/os/AsyncTask审议有关实施一些内容AsyncTask秒。github

这个AsyncTask班是一个abstract班级。实现一般是在UI线程上运行的类的子类。(AsyncTask即子类)的实现将覆盖至少一种方法,一般是两种方法。数据库

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

onPreExecute,在执行任务以前在UI线程上调用。此步骤用于设置任务,例如经过在用户界面中显示微调器。 doInBackground(Params...,在完成执行后当即在后台线程上调用。此步骤用于执行可能须要很长时间的后台计算。异步任务的参数将传递给此步骤。计算结果必须由此步骤返回,并将传递回最后一步。此步骤还可用于发布一个或多个进度单位。这些值发布在UI线程中steponProgressUpdate(Progress...) onProgressUpdate(Progress...,在调用publishProgress(Progress...步骤后在UI线程上调用。执行的时间是不肯定的。此方法用于在后台计算仍在执行时显示用户界面中的任何形式的进度。例如,它可用于为进度条设置动画或在文本字段中显示日志。 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 implements
        MarketAdapter.ListItemClickListener, PortfolioAdapter.ListItemClickListener {

    private static final String TAG = MainActivity.class.getSimpleName();
    CommonUIHelper mCommonUIHelper;
    ArrayList<Stock> mMarketData;
    private Toast mToast;
    //The following are for market summary
    private MarketAdapter mAdapter;
    private RecyclerView mMarketRV;
    private ProgressBar spinner;

    @Override
    protected 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() {
            @Override
            public 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 email Email.putExtra(Intent.EXTRA_SUBJECT, R.string.label_feedback_subject); // Email 's Subject
                Email.putExtra(Intent.EXTRA_TEXT, 
                 getString(R.string.label_address_developer) + "");  //Email 's Greeting text startActivity(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); } @Override public 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); } @Override public 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 network It takes void, void and returns ArrayList<?> */ class NetworkQueryTask extends AsyncTask<String, Integer, ArrayList<Stock>> { private String query; @Override protected void onPreExecute() { if (spinner != null) { spinner.setVisibility(View.VISIBLE); } } @Override protected 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; } @Override protected void onProgressUpdate(Integer... progress) { super.onProgressUpdate(progress); Toast.makeText(getApplicationContext(), "Progress: " + progress[0] + "(%)", Toast.LENGTH_SHORT).show(); } @Override protected 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类。子类能够定义以下:app

private class NetworkQueryTask extends AsyncTask<T1, T2, T3> {...}
复制代码

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

上面定义的任务能够执行以下:async

new NetworkAsyncTask().execute(param1);
复制代码

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

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

在这样作的过程当中,咱们建立了一个NetworkQueryTask从中扩展的子类AsyncTask。该类有三个参数string,Void 和ArrayList。股票是一个存储信息的简单类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的实现。

相关文章
相关标签/搜索