在Android活动和服务中,大多数回调都在主线程上运行。这使更新UI变得很容易,但是在主线程上运行处理器或I / O繁重的任务可能会导致UI暂停并变得无响应(有关随后发生情况的官方文档)。
您可以通过将这些较重的任务放在后台线程中来解决此问题。
一种实现方法是使用AsyncTask,它提供了一个框架,可简化背景线程的使用,并在后台线程完成其工作之前,之中和之后执行UI线程任务。
扩展时可以覆盖的方法AsyncTask:
onPreExecute():在执行任务之前在UI线程上调用
doInBackground():执行完成后立即在后台线程上调用onPreExecute()。
onProgressUpdate():调用后在UI线程上调用publishProgress(Progress...)。
onPostExecute():在后台计算完成后在UI线程上调用
public class MyCustomAsyncTask extends AsyncTask<File, Void, String> { @Override protected void onPreExecute(){ // 它在后台线程执行之前在UI线程上运行。 super.onPreExecute(); // 执行预线程化任务,例如初始化变量。 Log.v("myBackgroundTask", "Starting Background Task"); } @Override protected String doInBackground(File... params) { //磁盘密集型工作。这在后台线程上运行。 // Search through a file for the first line that contains "Hello", and return // 那条线。 try (Scanner scanner = new Scanner(params[0])) { while (scanner.hasNextLine()) { final String line = scanner.nextLine(); publishProgress(); // 告诉UI线程我们取得了进展 if (line.contains("Hello")) { return line; } } return null; } } @Override protected void onProgressUpdate(Void...p) { // 在调用publishProgress后在UI线程上运行 Log.v("阅读另一行!") } @Override protected void onPostExecute(String s) { // 完全执行doInBackground()方法后,此操作将在UI线程上运行 // 此函数接收从doInBackground()方法返回的result(String s)。 // 使用找到的字符串更新UI。 TextView view = (TextView) findViewById(R.id.found_string); if (s != null) { view.setText(s); } else { view.setText("找不到匹配项。"); } } }
MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>(); // 使用用户提供的文件名运行任务。 asyncTask.execute(userSuppliedFilename);
或者简单地:
new MyCustomAsyncTask().execute(userSuppliedFilename);
定义a时,AsyncTask我们可以在< >方括号之间传递三种类型。
定义为<Params, Progress, Result>(请参阅参数部分)
在前面的示例中,我们使用了类型<File, Void, String>:
AsyncTask<File, Void, String> // 参数具有文件类型 // 进度有未使用的类型 // 结果的类型为字符串
Void 当您要将类型标记为未使用时使用。
请注意,您无法通过基本类型(即int,float和另外6人)作为参数。在这种情况下,你应该通过他们的包装类,例如Integer代替int或Float代替float。
AsyncTask和Activity生命周期
AsyncTasks不遵循Activity实例的生命周期。如果在“活动”中启动AsyncTask并旋转设备,则“活动”将被销毁并创建一个新实例。但是AsyncTask不会死。它将继续存在直到完成。
解决方案:AsyncTaskLoader
加载程序的一个子类是AsyncTaskLoader。此类执行与AsyncTask相同的功能,但效果更好。它可以更轻松地处理活动配置更改,并且在片段和活动的生命周期内运行。令人高兴的是,在使用AsyncTask的任何情况下都可以使用AsyncTaskLoader。任何时候需要将数据加载到内存中以便活动/片段进行处理时,AsyncTaskLoader都能做得更好。