Android 使用 AsyncTask 来下载图片

来源:互联网 发布:程序员有必要考研吗 编辑:程序博客网 时间:2024/04/28 00:29
Android使用AsyncTask 有如下好处:
1. 线程的开销较大,如果每个任务都要创建一个线程,那么应用程序的效率要低很多;

2. 线程无法管理,匿名线程创建并启动后就不受程序的控制了,如果有很多个请求发送,那么就会启动非常多的线程,系统将不堪重负;

3. 另外,在新线程中更新UI还必须要引入handler,这让代码看上去非常臃肿;
为了解决这一问题,Android在1.5版本引入了AsyncTask. AsyncTask的特点是任务在主线程之外运行,而回调方法是在主线程中执行,这就有效地避免了使用Handler带来的麻烦。阅读AsyncTask的源码可知,AsyncTask是使用java.util.concurrent 框架来管理线程以及任务的执行的,concurrent框架是一个非常成熟,高效的框架,经过了严格的测试。这说明AsyncTask的设计很好的解决了匿名线程存在的问题。

AsyncTask定义了三种泛型类型 Params,Progress和Result.
  1. Params启动任务执行的输入参数,比如HTTP请求的URL;
  2. Progress后台任务执行的百分比;
  3. Result后台执行任务最终返回的结果,比如String;
子类必须实现抽象方法doInBackground(Params… p) ,在此方法中实现任务的执行工作,比如连接网络获取数据等。通常还应该实现onPostExecute(Result r)方法,因为应用程序关心的结果在此方法中返回。需要注意的是AsyncTask一定要在主线程中创建实例。

AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,需要注意的是这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。在任务的执行过程中,这些方法被自动调用,运行过程,
onPreExecute()当任务执行之前开始调用此方法,可以在这里显示进度对话框。
doInBackground(Params…)此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
onProgressUpdate(Progress…)此方法在主线程执行,用于显示任务执行的进度。
onPostExecute(Result)此方法在主线程执行,任务执行的结果作为此方法的参数返回。

view source
print?
01class GetImageTask extends AsyncTask<String, Void, Bitmap>{  
02      InputStream is =null;  
03          
04      @Override  
05      protectedBitmap doInBackground(String... params) {  
06          // TODO Auto-generated method stub  
07          URL myFileUrl =null;  
08          Bitmap bitmap =null;  
09          InputStream is =null;  
10        HttpURLConnection conn =null;  
11        try{  
12            myFileUrl =newURL(params[0]);  
13        }catch(MalformedURLException e) {  
14            e.printStackTrace();  
15        
16        try{  
17            conn = (HttpURLConnection)myFileUrl  
18                    .openConnection();  
19            conn.setDoInput(true);  
20            conn.connect();  
21            is =conn.getInputStream();  
22            bitmap =BitmapFactory.decodeStream(is);  
23            is.close();  
24        }catch(IOException e) {  
25            e.printStackTrace();  
26        }finally{                 
27                try{  
28                    if(is !=null){  
29                    is.close();  
30                    }  
31                    if( conn !=null){  
32                        conn.disconnect();  
33                    }  
34                }catch(IOException e) {  
35                    // TODO Auto-generated catch block  
36                    e.printStackTrace();  
37                }                 
38        
39        returnbitmap;  
40    
41  
42    @Override  
43    protectedvoidonCancelled() { 
44        // TODO Auto-generated method stub  
45        super.onCancelled(); 
46    
47  
48    @Override  
49    protectedvoidonPostExecute(Bitmap result) {  
50        // TODO Auto-generated method stub        
51        mImageAndTextView.setImage(result);           
52        mImageAndTextView.postInvalidate(0,0, mScreenWidth ,mImageHeight +30);      //只更新稍比图片大一些的区域   
53        super.onPostExecute(result);  
54    
55        
56}
 在开发Android应用时必须遵守单线程模型的原则:Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则:

  1.不要阻塞UI线程
  2.确保只在UI线程中访问Android UI工具包

  当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。

  比如说从网上获取一个网页,在一个TextView中将其源代码显示出来,这种涉及到网络操作的程序一般都是需要开一个线程完成网络访问,但是在获得页面源码后,是不能直接在网络操作线程中调TextView.setText()的因为其他线程中是不能直接访问主UI线程成员。

  Android提供了几种在其他线程中访问UI线程的方法。

  java代码:
  Activity.runOnUiThread( Runnable )
  View.post( Runnable )
  View.postDelayed( Runnable, long )

  Hanlder
  这些类或方法同样会使你的代码很复杂很难理解。然而当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。

  为了解决这个问题,Android 1.5提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。不需要借助线程和Handler即可实现。

  AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result。
  Params 启动任务执行的输入参数,比如HTTP请求的URL。
  Progress 后台任务执行的百分比。
  Result 后台执行任务最终返回的结果,比如String。

  AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。

  1) 子类化AsyncTask
  2) 实现AsyncTask中定义的下面一个或几个方法

  onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。

  doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。

  onProgressUpdate(Progress...),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

  onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread。

  为了正确的使用AsyncTask类,以下是几条必须遵守的准则:

  1) Task的实例必须在UI thread中创建
  2) execute方法必须在UI thread中调用
  3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法
  4) 该task只能被执行一次,否则多次调用时将会出现异常

综合以下网址:

http://www.oschina.net/question/195301_31313

http://android.tgbus.com/Android/tutorial/201109/369193.shtml