继续前一个话题,在非UI线程中更新UI组件,除了使用前一篇博文提到的Handler以外,还有另一种常用的方法——异步任务(AsyncTask)。
异步任务类AsyncTask<Params,Progress,Result>类是一个抽象类,通常用于被继承。继承时需要指定三个泛型参数:
Params:启动任务执行的输入参数的类型。
Progress:后台任务完成的进度值的类型。
Result:后台执行任务完成后返回结果的类型。
这三个参数单独理解起来比较抽象,结合重写的AsyncTask的4个方法就好理解了:
1、doInBackground(Params...):这是在新线程中执行的后台任务,通常用于比较耗时的操作,将其放在新线程中以免阻塞UI线程。该方法返回Result类型的值。在该方法中可以调用publishProgress(Progress...values)方法来更新任务的执行进度。
2、onProgressUpdate(Progress...values):在doInBackground()方法中调用publishProgress()方法时,会触发这个方法,在这个方法中可以针对当前后台的进度进行一些显示进度之类的操作。
3、onPostExecute(Result result):当doInBackground()方法完成后,系统会自动调用onPostExecute方法,并将doInBackground返回值传给该方法。
4、onPreExecute():该方法在doInBackground方法启动之前被调用,用于完成一些初始化的准备工作。
以上四个方法都是回调方法,由系统负责调用。需要注意的是以上四个方法,只有doInBackground方法是在新线程中进行,其余三个方法,都是在当前线程(也就是创建AsyncTask对象的线程)中执行的,因此可以进行UI更新的操作。
具体使用AsyncTask的步骤为:
1、在UI线程中创建AsyncTask对象。
2、在UI线程中调用该对象的execute(Param...params)方法。
AsyncTask类其实很简单,直接理解比较抽象。举个例子就很容易明白了。比如我们有个程序要从网络上接收数据并进行显示。由于网络传输是比较耗时的操作,因此最好不要直接在UI线程里操作,否则UI阻塞会造成程序没有响应。实际上android是禁止在UI线程中进行网络操作的,如果这么做android会直接抛出异常。此时就可以用AsyncTask类了。
定义一个新类DownTask,继承自AsyncTask<Param,Progress,Result>。根据具体的要求来设置三个泛型参数。比如我们后台任务是从网络上读取文本,那么传入doInBackground的就是一个URL对象;我们根据当前进度来更新UI,那么Progress类型可以是Integer的,代表当前读入的行数;我们最后要把读到的字符显示在界面上,那么Result就是String类型,因此我们继承的AsyncTask类型就为AsyncTask<URL,Integer,String>。当然也可以是其他类型,比如我们如果我们的URL是固定死的,那么在启动后台任务时可以不指定输入参数,即Param类型可以是Void;也可以指定读取的最大行数,Integer类型,代表我们读取到这么多行就结束doInBackground任务....等等,根据实际需要,都可以灵活定义的。
闲话少叙,在新定义的类中,改写上述四个方法:
1、doInBackground方法:完成实际的读取任务,就是通过Socket从网络读取文本流,并将其保存起来。并不断更新当前进度,调用publishProgress方法
2、onPreExecute方法:下载之前的一些准备工作,比如在界面上准备好一个进度条。
3、onProgressUpdate方法:负责根据当前读取的行数,实时更新进度条的进度值。
4、onPostExecute方法:在doInBackground方法完成之后,会返回一个String对象,代表读取到的文本。本方法就负责将String对象包含的文本显示到UI界面上。
定义完DownTask类之后,在UI线程中new一个DownTask对象,然后调用它的execute方法就可以了。是不是很简单:)
异步任务类AsyncTask<Params,Progress,Result>类是一个抽象类,通常用于被继承。继承时需要指定三个泛型参数:
Params:启动任务执行的输入参数的类型。
Progress:后台任务完成的进度值的类型。
Result:后台执行任务完成后返回结果的类型。
这三个参数单独理解起来比较抽象,结合重写的AsyncTask的4个方法就好理解了:
1、doInBackground(Params...):这是在新线程中执行的后台任务,通常用于比较耗时的操作,将其放在新线程中以免阻塞UI线程。该方法返回Result类型的值。在该方法中可以调用publishProgress(Progress...values)方法来更新任务的执行进度。
2、onProgressUpdate(Progress...values):在doInBackground()方法中调用publishProgress()方法时,会触发这个方法,在这个方法中可以针对当前后台的进度进行一些显示进度之类的操作。
3、onPostExecute(Result result):当doInBackground()方法完成后,系统会自动调用onPostExecute方法,并将doInBackground返回值传给该方法。
4、onPreExecute():该方法在doInBackground方法启动之前被调用,用于完成一些初始化的准备工作。
以上四个方法都是回调方法,由系统负责调用。需要注意的是以上四个方法,只有doInBackground方法是在新线程中进行,其余三个方法,都是在当前线程(也就是创建AsyncTask对象的线程)中执行的,因此可以进行UI更新的操作。
具体使用AsyncTask的步骤为:
1、在UI线程中创建AsyncTask对象。
2、在UI线程中调用该对象的execute(Param...params)方法。
AsyncTask类其实很简单,直接理解比较抽象。举个例子就很容易明白了。比如我们有个程序要从网络上接收数据并进行显示。由于网络传输是比较耗时的操作,因此最好不要直接在UI线程里操作,否则UI阻塞会造成程序没有响应。实际上android是禁止在UI线程中进行网络操作的,如果这么做android会直接抛出异常。此时就可以用AsyncTask类了。
定义一个新类DownTask,继承自AsyncTask<Param,Progress,Result>。根据具体的要求来设置三个泛型参数。比如我们后台任务是从网络上读取文本,那么传入doInBackground的就是一个URL对象;我们根据当前进度来更新UI,那么Progress类型可以是Integer的,代表当前读入的行数;我们最后要把读到的字符显示在界面上,那么Result就是String类型,因此我们继承的AsyncTask类型就为AsyncTask<URL,Integer,String>。当然也可以是其他类型,比如我们如果我们的URL是固定死的,那么在启动后台任务时可以不指定输入参数,即Param类型可以是Void;也可以指定读取的最大行数,Integer类型,代表我们读取到这么多行就结束doInBackground任务....等等,根据实际需要,都可以灵活定义的。
闲话少叙,在新定义的类中,改写上述四个方法:
1、doInBackground方法:完成实际的读取任务,就是通过Socket从网络读取文本流,并将其保存起来。并不断更新当前进度,调用publishProgress方法
2、onPreExecute方法:下载之前的一些准备工作,比如在界面上准备好一个进度条。
3、onProgressUpdate方法:负责根据当前读取的行数,实时更新进度条的进度值。
4、onPostExecute方法:在doInBackground方法完成之后,会返回一个String对象,代表读取到的文本。本方法就负责将String对象包含的文本显示到UI界面上。
定义完DownTask类之后,在UI线程中new一个DownTask对象,然后调用它的execute方法就可以了。是不是很简单:)