Android 基本用法

示例

在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都能做得更好。