android异步加载图片显示,并且对图片进行缓存实例

step1:新建项目DataAsyncLoad,如下图所示

 


step2:设置应用的UI界面

a.应用的主界面    main.xml


[html]
<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    > 
<ListView   
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    android:id="@+id/listView" 
    /> 
</LinearLayout> 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ListView 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/listView"
    />
</LinearLayout>

b.每个ListView的界面  listview_item.xml


[html]
<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="horizontal" > 
    <ImageView  
        android:layout_width="42dp" 
        android:layout_height="42dp" 
        android:id="@+id/imageView"   
        /> 
 
    <TextView  
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" 
        android:textSize="18sp" 
        android:textColor="#FFFFFF" 
        android:id="@+id/textView"         
        /> 
</LinearLayout> 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    <ImageView
        android:layout_width="42dp"
        android:layout_height="42dp"
        android:id="@+id/imageView" 
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textColor="#FFFFFF"
        android:id="@+id/textView"       
        />
</LinearLayout>
step3:写一些辅助类     cn.roco.data.utilsMD5.java


[java]
package cn.roco.data.utils; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 
 
public class MD5 { 
    public static String getMD5(String content) { 
        try { 
            MessageDigest digest = MessageDigest.getInstance("MD5"); 
            digest.update(content.getBytes()); 
            return getHashString(digest); 
             
        } catch (NoSuchAlgorithmException e) { 
            e.printStackTrace(); 
        } 
        return null; 
    } 
     
    private static String getHashString(MessageDigest digest) { 
        StringBuilder builder = new StringBuilder(); 
        for (byte b : digest.digest()) { 
            builder.append(Integer.toHexString((b >> 4) & 0xf)); 
            builder.append(Integer.toHexString(b & 0xf)); 
        } 
        return builder.toString(); 
    } 

package cn.roco.data.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5 {
 public static String getMD5(String content) {
  try {
   MessageDigest digest = MessageDigest.getInstance("MD5");
   digest.update(content.getBytes());
   return getHashString(digest);
   
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  }
  return null;
 }
 
    private static String getHashString(MessageDigest digest) {
        StringBuilder builder = new StringBuilder();
        for (byte b : digest.digest()) {
            builder.append(Integer.toHexString((b >> 4) & 0xf));
            builder.append(Integer.toHexString(b & 0xf));
        }
        return builder.toString();
    }
}

 


step4:写应用使用的JavaBean  cn.roco.data.domain.Contact.java

[java]
package cn.roco.data.domain; 
 
public class Contact { 
    private int id; 
    private String name; 
    private String image; 
 
    public int getId() { 
        return id; 
    } 
 
    public void setId(int id) { 
        this.id = id; 
    } 
 
    public String getName() { 
        return name; 
    } 
 
    public void setName(String name) { 
        this.name = name; 
    } 
 
    public String getImage() { 
        return image; 
    } 
 
    public void setImage(String image) { 
        this.image = image; 
    } 
 
    public Contact(int id, String name, String image) { 
        this.id = id; 
        this.name = name; 
        this.image = image; 
    } 
    public Contact(){ 
         
    } 

package cn.roco.data.domain;

public class Contact {
 private int id;
 private String name;
 private String image;

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getImage() {
  return image;
 }

 public void setImage(String image) {
  this.image = image;
 }

 public Contact(int id, String name, String image) {
  this.id = id;
  this.name = name;
  this.image = image;
 }
 public Contact(){
  
 }
}

step5:写一个应用的service层,用于对javabean进行操作  cn.roco.data.service.ContactService.java


[java]
package cn.roco.data.service; 
 
import java.io.File; 
import java.io.FileOutputStream; 
import java.io.InputStream; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.List; 
 
import org.xmlpull.v1.XmlPullParser; 
 
import android.net.Uri; 
import android.util.Xml; 
 
import cn.roco.data.domain.Contact; 
import cn.roco.data.utils.MD5; 
 
public class ContactService { 
    /**
     * 获取联系人数据
     * 
     * @return
     * @throws Exception
     */ 
    public static List<Contact> getContacts() throws Exception { 
        String path = "http://192.168.1.100:8080/Hello/contact.xml"; 
        HttpURLConnection connection = (HttpURLConnection) new URL(path) 
                .openConnection(); 
        connection.setConnectTimeout(5000); 
        connection.setRequestMethod("GET"); 
        if (connection.getResponseCode() == 200) { 
            return parseXML(connection.getInputStream()); 
        } 
        return null; 
    } 
    /**转化XML获取数据
     * 服务器端的xml文件如下。。。。。。
     * <?xml version="1.0" encoding="UTF-8"?>
        <contacts>
            <contact id="1">
                <name>Roco_1</name>
                <image src=http://up.2cto.com/2013/0417/20130417032102399.png" />
            </contact>
            .......
        </contacts>*/ 
    private static List<Contact> parseXML(InputStream inputStream) 
            throws Exception { 
        List<Contact> contacts = new ArrayList<Contact>(); 
        Contact contact = null; 
 
        XmlPullParser pullParser = Xml.newPullParser(); 
        pullParser.setInput(inputStream, "UTF-8"); 
        int event = pullParser.getEventType(); 
        while (event != XmlPullParser.END_DOCUMENT) { 
            switch (event) { 
            case XmlPullParser.START_TAG: 
                if ("contact".equals(pullParser.getName())) { 
                    contact = new Contact(); 
                    contact.setId(new Integer(pullParser.getAttributeValue(0))); 
                } else if ("name".equals(pullParser.getName())) { 
                    contact.setName(pullParser.nextText()); 
                } else if ("image".equals(pullParser.getName())) { 
                    contact.setImage(pullParser.getAttributeValue(0)); 
                } 
                break; 
            case XmlPullParser.END_TAG: 
                if ("contact".equals(pullParser.getName())) { 
                    contacts.add(contact); 
                    contact = null; 
                } 
            } 
            event = pullParser.next(); 
        } 
        return contacts; 
    } 
 
    /**
     * 获取网络图片,如果图片存在于缓存中,就返回该图片,否则从网络中加载该图片并缓存起来
     * 
     * @param path
     *            图片路径
     * @return
     */ 
    public static Uri getImage(String imagePath, File cacheDir) 
            throws Exception { 
        //缓存文件的文件名用MD5进行加密  
        File localFile = new File(cacheDir, MD5.getMD5(imagePath) 
                + imagePath.substring(imagePath.lastIndexOf(".")));  
        if (localFile.exists()) { 
            return Uri.fromFile(localFile); 
        } else { 
            HttpURLConnection connection = (HttpURLConnection) new URL( 
                    imagePath).openConnection(); 
            connection.setConnectTimeout(5000); 
            connection.setRequestMethod("GET"); 
            //将文件缓存起来  
            if (connection.getResponseCode() == 200) { 
                FileOutputStream outputStream = new FileOutputStream(localFile); 
                InputStream inputStream = connection.getInputStream(); 
                byte[] buffer = new byte[1024]; 
                int len = 0; 
                while ((len = inputStream.read(buffer)) != -1) { 
                    outputStream.write(buffer, 0, len); 
                } 
                inputStream.close(); 
                outputStream.close(); 
                return Uri.fromFile(localFile); 
            } 
        } 
        return null; 
    } 

package cn.roco.data.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;

import android.net.Uri;
import android.util.Xml;

import cn.roco.data.domain.Contact;
import cn.roco.data.utils.MD5;

public class ContactService {
 /**
  * 获取联系人数据
  *
  * @return
  * @throws Exception
  */
 public static List<Contact> getContacts() throws Exception {
  String path = "http://192.168.1.100:8080/Hello/contact.xml";
  HttpURLConnection connection = (HttpURLConnection) new URL(path)
    .openConnection();
  connection.setConnectTimeout(5000);
  connection.setRequestMethod("GET");
  if (connection.getResponseCode() == 200) {
   return parseXML(connection.getInputStream());
  }
  return null;
 }
 /**转化XML获取数据
  * 服务器端的xml文件如下。。。。。。
  * <?xml version="1.0" encoding="UTF-8"?>
  <contacts>
   <contact id="1">
    <name>Roco_1</name>
    <image src=http://up.2cto.com/2013/0417/20130417032102399.png" />
   </contact>
   .......
  </contacts>*/
 private static List<Contact> parseXML(InputStream inputStream)
   throws Exception {
  List<Contact> contacts = new ArrayList<Contact>();
  Contact contact = null;

  XmlPullParser pullParser = Xml.newPullParser();
  pullParser.setInput(inputStream, "UTF-8");
  int event = pullParser.getEventType();
  while (event != XmlPullParser.END_DOCUMENT) {
   switch (event) {
   case XmlPullParser.START_TAG:
    if ("contact".equals(pullParser.getName())) {
     contact = new Contact();
     contact.setId(new Integer(pullParser.getAttributeValue(0)));
    } else if ("name".equals(pullParser.getName())) {
     contact.setName(pullParser.nextText());
    } else if ("image".equals(pullParser.getName())) {
     contact.setImage(pullParser.getAttributeValue(0));
    }
    break;
   case XmlPullParser.END_TAG:
    if ("contact".equals(pullParser.getName())) {
     contacts.add(contact);
     contact = null;
    }
   }
   event = pullParser.next();
  }
  return contacts;
 }

 /**
  * 获取网络图片,如果图片存在于缓存中,就返回该图片,否则从网络中加载该图片并缓存起来
  *
  * @param path
  *            图片路径
  * @return
  */
 public static Uri getImage(String imagePath, File cacheDir)
   throws Exception {
  //缓存文件的文件名用MD5进行加密
  File localFile = new File(cacheDir, MD5.getMD5(imagePath)
    + imagePath.substring(imagePath.lastIndexOf(".")));
  if (localFile.exists()) {
   return Uri.fromFile(localFile);
  } else {
   HttpURLConnection connection = (HttpURLConnection) new URL(
     imagePath).openConnection();
   connection.setConnectTimeout(5000);
   connection.setRequestMethod("GET");
   //将文件缓存起来
   if (connection.getResponseCode() == 200) {
    FileOutputStream outputStream = new FileOutputStream(localFile);
    InputStream inputStream = connection.getInputStream();
    byte[] buffer = new byte[1024];
    int len = 0;
    while ((len = inputStream.read(buffer)) != -1) {
     outputStream.write(buffer, 0, len);
    }
    inputStream.close();
    outputStream.close();
    return Uri.fromFile(localFile);
   }
  }
  return null;
 }
}

 


step6:写一个Adapter用于对ListView进行数据更新 cn.roco.data.adapter.ContactAdapter.java


[java]
package cn.roco.data.adapter; 
 
import java.io.File; 
import java.util.List; 
import cn.roco.data.R; 
import cn.roco.data.domain.Contact; 
import cn.roco.data.service.ContactService; 
import android.content.Context; 
import android.net.Uri; 
import android.os.AsyncTask; 
import android.os.Handler; 
import android.os.Message; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.BaseAdapter; 
import android.widget.ImageView; 
import android.widget.TextView; 
/**适配器,用于更新View*/ 
public class ContactAdapter extends BaseAdapter { 
    private List<Contact> data; 
    private int listviewItem; 
    private File cache; 
    /**
     * LayoutInflater的作用类似于 findViewById(),不同点是LayoutInflater是用来找layout文件夹下的xml布局文件,并且实例化!
     * 而 findViewById()是找具体某一个xml下的具体 widget控件(如:Button,TextView等)。
     */ 
    private LayoutInflater layoutInflater; 
 
    public ContactAdapter(Context context, List<Contact> data, 
            int listviewItem, File cache) { 
        this.data = data; 
        this.listviewItem = listviewItem; 
        this.cache = cache; 
        this.layoutInflater = (LayoutInflater) context 
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);//取得xml里定义的view  
        /***
         * getSystemService()是Android很重要的一个API,它是Activity的一个方法,
         * 根据传入的NAME来取得对应的Object,然后转换成相应的服务对象。以下介绍系统相应的服务。 
         *  传入的Name                     返回的对象                   说明 
            WINDOW_SERVICE              WindowManager           管理打开的窗口程序 
            LAYOUT_INFLATER_SERVICE     LayoutInflater          取得xml里定义的view 
            ACTIVITY_SERVICE            ActivityManager         管理应用程序的系统状态 
            POWER_SERVICE               PowerManger             电源的服务 
            ALARM_SERVICE               AlarmManager            闹钟的服务 
            NOTIFICATION_SERVICE        NotificationManager     状态栏的服务 
            KEYGUARD_SERVICE            KeyguardManager         键盘锁的服务 
            LOCATION_SERVICE            LocationManager         位置的服务,如GPS 
            SEARCH_SERVICE              SearchManager           搜索的服务 
            VEBRATOR_SERVICE            Vebrator                手机震动的服务 
            CONNECTIVITY_SERVICE        Connectivity            网络连接的服务 
            WIFI_SERVICE                WifiManager             Wi-Fi服务 
            TELEPHONY_SERVICE           TeleponyManager         电话服务 
 
         */ 
    } 
 
    /** 得到数据的总数 */ 
    @Override 
    public int getCount() { 
        return data.size(); 
    } 
 
    /** 根据数据索引,得到集合中所对应的数据 */ 
    @Override 
    public Object getItem(int position) { 
        return data.get(position); 
    } 
 
    @Override 
    public long getItemId(int position) { 
        return position; 
    } 
 
    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
        ImageView imageView = null; 
        TextView textView = null; 
         
        if (convertView == null) { 
            convertView = layoutInflater.inflate(listviewItem, null); 
            imageView = (ImageView) convertView.findViewById(R.id.imageView); 
            textView = (TextView) convertView.findViewById(R.id.textView); 
            convertView.setTag(new DataWrapper(imageView, textView));//将内容包装起来以备以后使用  
        } else { 
            DataWrapper dataWrapper=(DataWrapper) convertView.getTag();//将包装类取出来  
            //从包装类中取数据  
            imageView=dataWrapper.getImageView(); 
            textView=dataWrapper.getTextView(); 
        } 
        Contact contact=data.get(position); 
        textView.setText(contact.getName()); 
        /**异步加载图片文件*/ 
        asynchImageLoad(imageView,contact.getImage()); 
        return convertView; 
    } 
     
    /*
    //该方法会创建很多的线程,也会很耗资源
    private void asynchImageLoad(final ImageView imageView, final String imagePath) {
        final Handler handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {//运行在主线程中
                Uri uri=(Uri) msg.obj;
                if (uri!=null&&imageView!=null) {
                    imageView.setImageURI(uri);
                }
            }
        };
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                try {
                    Uri uri=ContactService.getImage(imagePath, cache);
                    handler.sendMessage(handler.obtainMessage(10,uri));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        new Thread(runnable).start();
    }
    */ 
     
    /**异步加载图片文件*/ 
    private void asynchImageLoad(ImageView imageView, String imagePath) { 
        AsycImageTask asycImageTask=new AsycImageTask(imageView); 
        asycImageTask.execute(imagePath); 
    } 
    /**
     * 使用AsyncTask提高性能
     * 可选方法:
        1,  onprogressupdate(progress…) 可以使用进度条增加用户体验度。此方法在主线程执行,用户显示任务执行的进度。
        2,  onpreExecute()  这里是最新用户调用excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
        3,  onCancelled()  用户调用取消时,要做的操作。
        
         AsyncTask<Params, Progress, Result> 
         AsyscTask定义了三种泛型类型params,progress和result.
         1,  params启动任务执行的输入参数,比如http请求的URL
         2,  progress后台任务执行的百分比
         3,  result后台执行任务最终返回的结果,比如String,比如我需要得到的list。
        
            使用AsyncTask类,遵守的准则:1,  Task的实例必须在UI thread中创建;2,  Execute方法必须在UI thread中调用
            3,  不要手动的调用onPfreexecute(),onPostExecute(result)Doinbackground(params…),onProgressupdate(progress…)这几个方法;
            4,  该task只能被执行一次,否则多次调用时将会出现异常;
            AsyncTask的整个调用过程都是从execute方法开始的,一旦在主线程中调用execute方法,就可以通过onpreExecute方法,
            这是一个预处理方法,比如可以在这里开始一个进度框,同样也可以通过onprogressupdate方法给用户一个进度条的显示,增加用户体验;
            最后通过onpostexecute方法,相当于handler处理UI的方式,在这里可以使用在doinbackground得到的结果处理操作UI。
            此方法在主线程执行,任务执行的结果作为此方法的参数返回
     */ 
    private final class AsycImageTask extends AsyncTask<String, Integer, Uri>{ 
        private ImageView imageView; 
        public AsycImageTask(ImageView imageView) { 
            this.imageView=imageView; 
        } 
        /**
         *  后台执行,比较耗时的操作都可以放在这里。
            注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作
            ,通常需要较长的时间。在执行过程中可以调用
            Public progress(progress…)来更新任务的进度。
         */ 
        @Override 
        protected Uri doInBackground(String... params) {//子线程中执行  
            try { 
                return ContactService.getImage(params[0], cache); 
            } catch (Exception e) { 
                e.printStackTrace(); 
            } 
            return null; 
        } 
        /**
         * 相当于handler处理UI的方式,在这里可以使用在doinbackground得到的结果
         * 处理操作UI。此方法在主线程执行,任务执行的结果作为此方法的参数返回。
         */ 
        @Override 
        protected void onPostExecute(Uri result) {//运行在主线程  
            if (result!=null&&imageView!=null) { 
                imageView.setImageURI(result); 
            } 
        } 
         
    } 
     
    /**数据包装类*/ 
    private final class DataWrapper { 
        private ImageView imageView; 
        private TextView textView; 
 
        public ImageView getImageView() { 
            return imageView; 
        } 
 
        public TextView getTextView() { 
            return textView; 
        } 
 
        public DataWrapper(ImageView imageView, TextView textView) { 
            this.imageView = imageView; 
            this.textView = textView; 
        } 
    } 
 

package cn.roco.data.adapter;

import java.io.File;
import java.util.List;
import cn.roco.data.R;
import cn.roco.data.domain.Contact;
import cn.roco.data.service.ContactService;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
/**适配器,用于更新View*/
public class ContactAdapter extends BaseAdapter {
 private List<Contact> data;
 private int listviewItem;
 private File cache;
 /**
  * LayoutInflater的作用类似于 findViewById(),不同点是LayoutInflater是用来找layout文件夹下的xml布局文件,并且实例化!
  * 而 findViewById()是找具体某一个xml下的具体 widget控件(如:Button,TextView等)。
  */
 private LayoutInflater layoutInflater;

 public ContactAdapter(Context context, List<Contact> data,
   int listviewItem, File cache) {
  this.data = data;
  this.listviewItem = listviewItem;
  this.cache = cache;
  this.layoutInflater = (LayoutInflater) context
    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);//取得xml里定义的view
  /***
   * getSystemService()是Android很重要的一个API,它是Activity的一个方法,
   * 根据传入的NAME来取得对应的Object,然后转换成相应的服务对象。以下介绍系统相应的服务。
   *  传入的Name      返回的对象      说明
   WINDOW_SERVICE      WindowManager    管理打开的窗口程序
   LAYOUT_INFLATER_SERVICE  LayoutInflater    取得xml里定义的view
   ACTIVITY_SERVICE    ActivityManager   管理应用程序的系统状态
   POWER_SERVICE     PowerManger    电源的服务
   ALARM_SERVICE     AlarmManager    闹钟的服务
   NOTIFICATION_SERVICE   NotificationManager  状态栏的服务
   KEYGUARD_SERVICE    KeyguardManager   键盘锁的服务
   LOCATION_SERVICE    LocationManager   位置的服务,如GPS
   SEARCH_SERVICE     SearchManager    搜索的服务
   VEBRATOR_SERVICE    Vebrator     手机震动的服务
   CONNECTIVITY_SERVICE   Connectivity    网络连接的服务
   WIFI_SERVICE     WifiManager    Wi-Fi服务
   TELEPHONY_SERVICE    TeleponyManager   电话服务

   */
 }

 /** 得到数据的总数 */
 @Override
 public int getCount() {
  return data.size();
 }

 /** 根据数据索引,得到集合中所对应的数据 */
 @Override
 public Object getItem(int position) {
  return data.get(position);
 }

 @Override
 public long getItemId(int position) {
  return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  ImageView imageView = null;
  TextView textView = null;
  
  if (convertView == null) {
   convertView = layoutInflater.inflate(listviewItem, null);
   imageView = (ImageView) convertView.findViewById(R.id.imageView);
   textView = (TextView) convertView.findViewById(R.id.textView);
   convertView.setTag(new DataWrapper(imageView, textView));//将内容包装起来以备以后使用
  } else {
   DataWrapper dataWrapper=(DataWrapper) convertView.getTag();//将包装类取出来
   //从包装类中取数据
   imageView=dataWrapper.getImageView();
   textView=dataWrapper.getTextView();
  }
  Contact contact=data.get(position);
  textView.setText(contact.getName());
  /**异步加载图片文件*/
  asynchImageLoad(imageView,contact.getImage());
  return convertView;
 }
 
 /*
 //该方法会创建很多的线程,也会很耗资源
 private void asynchImageLoad(final ImageView imageView, final String imagePath) {
  final Handler handler=new Handler(){
   @Override
   public void handleMessage(Message msg) {//运行在主线程中
    Uri uri=(Uri) msg.obj;
    if (uri!=null&&imageView!=null) {
     imageView.setImageURI(uri);
    }
   }
  };
  Runnable runnable=new Runnable() {
   @Override
   public void run() {
    try {
     Uri uri=ContactService.getImage(imagePath, cache);
     handler.sendMessage(handler.obtainMessage(10,uri));
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  };
  new Thread(runnable).start();
 }
 */
 
 /**异步加载图片文件*/
 private void asynchImageLoad(ImageView imageView, String imagePath) {
  AsycImageTask asycImageTask=new AsycImageTask(imageView);
  asycImageTask.execute(imagePath);
 }
 /**
  * 使用AsyncTask提高性能
  * 可选方法:
  1,  onprogressupdate(progress…) 可以使用进度条增加用户体验度。此方法在主线程执行,用户显示任务执行的进度。
  2,  onpreExecute()  这里是最新用户调用excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
  3,  onCancelled()  用户调用取消时,要做的操作。
  
   AsyncTask<Params, Progress, Result>
   AsyscTask定义了三种泛型类型params,progress和result.
   1,  params启动任务执行的输入参数,比如http请求的URL
   2,  progress后台任务执行的百分比
   3,  result后台执行任务最终返回的结果,比如String,比如我需要得到的list。
  
   使用AsyncTask类,遵守的准则:1,  Task的实例必须在UI thread中创建;2,  Execute方法必须在UI thread中调用
   3,  不要手动的调用onPfreexecute(),onPostExecute(result)Doinbackground(params…),onProgressupdate(progress…)这几个方法;
   4,  该task只能被执行一次,否则多次调用时将会出现异常;
   AsyncTask的整个调用过程都是从execute方法开始的,一旦在主线程中调用execute方法,就可以通过onpreExecute方法,
   这是一个预处理方法,比如可以在这里开始一个进度框,同样也可以通过onprogressupdate方法给用户一个进度条的显示,增加用户体验;
   最后通过onpostexecute方法,相当于handler处理UI的方式,在这里可以使用在doinbackground得到的结果处理操作UI。
   此方法在主线程执行,任务执行的结果作为此方法的参数返回
  */
 private final class AsycImageTask extends AsyncTask<String, Integer, Uri>{
  private ImageView imageView;
  public AsycImageTask(ImageView imageView) {
   this.imageView=imageView;
  }
  /**
   *  后台执行,比较耗时的操作都可以放在这里。
   注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作
   ,通常需要较长的时间。在执行过程中可以调用
   Public progress(progress…)来更新任务的进度。
   */
  @Override
  protected Uri doInBackground(String... params) {//子线程中执行
   try {
    return ContactService.getImage(params[0], cache);
   } catch (Exception e) {
    e.printStackTrace();
   }
   return null;
  }
  /**
   * 相当于handler处理UI的方式,在这里可以使用在doinbackground得到的结果
   * 处理操作UI。此方法在主线程执行,任务执行的结果作为此方法的参数返回。
   */
  @Override
  protected void onPostExecute(Uri result) {//运行在主线程
   if (result!=null&&imageView!=null) {
    imageView.setImageURI(result);
   }
  }
  
 }
 
 /**数据包装类*/
 private final class DataWrapper {
  private ImageView imageView;
  private TextView textView;

  public ImageView getImageView() {
   return imageView;
  }

  public TextView getTextView() {
   return textView;
  }

  public DataWrapper(ImageView imageView, TextView textView) {
   this.imageView = imageView;
   this.textView = textView;
  }
 }

}


step7:应用的主程序  cn.roco.data.MainActivity.java


[java]
package cn.roco.data; 
 
import java.io.File; 
import java.util.List; 
 
import cn.roco.data.adapter.ContactAdapter; 
import cn.roco.data.domain.Contact; 
import cn.roco.data.service.ContactService; 
import android.app.Activity; 
import android.os.Bundle; 
import android.os.Environment; 
import android.os.Handler; 
import android.widget.ListView; 
 
public class MainActivity extends Activity { 
    private ListView listView; 
    /**缓存文件*/ 
    private File cache; 
     
    /**接受消息,处理消息 ,此Handler会与当前主线程一块运行
     * 使用匿名内部类来复写Handler当中的handlerMessage()方法  */ 
    Handler handler = new Handler() { 
        // 接受数据  
        public void handleMessage(android.os.Message msg) { 
            //设置适配器,将获取的数据使用适配器更新View  
            listView.setAdapter(new ContactAdapter(MainActivity.this, 
                    (List<Contact>) msg.obj, R.layout.listview_item, cache)); 
        }; 
    }; 
 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
        listView = (ListView) this.findViewById(R.id.listView); 
        /**在SD卡中生成缓存目录*/ 
        cache = new File(Environment.getExternalStorageDirectory(), "cache"); 
        /**如果目录不存在就新建一个*/ 
        if (!cache.exists())  cache.mkdir(); 
             
        new Thread(new Runnable() { 
            @Override 
            public void run() { 
                try { 
                    //获取联系人数据  
                    List<Contact> data= ContactService.getContacts(); 
                    // 向Handler发送消息,更新UI  
                    handler.sendMessage(handler.obtainMessage(22, data)); 
                } catch (Exception e) { 
                    e.printStackTrace(); 
                } 
            } 
        }).start(); 
    } 
     
    @Override 
    protected void onDestroy() { 
        /**清除缓存文件*/ 
        for (File file:cache.listFiles()) { 
            file.delete(); 
        } 
        cache.delete(); 
        super.onDestroy(); 
    } 
     

package cn.roco.data;

import java.io.File;
import java.util.List;

import cn.roco.data.adapter.ContactAdapter;
import cn.roco.data.domain.Contact;
import cn.roco.data.service.ContactService;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.widget.ListView;

public class MainActivity extends Activity {
 private ListView listView;
 /**缓存文件*/
 private File cache;
 
 /**接受消息,处理消息 ,此Handler会与当前主线程一块运行
  * 使用匿名内部类来复写Handler当中的handlerMessage()方法  */
 Handler handler = new Handler() {
  // 接受数据
  public void handleMessage(android.os.Message msg) {
   //设置适配器,将获取的数据使用适配器更新View
   listView.setAdapter(new ContactAdapter(MainActivity.this,
     (List<Contact>) msg.obj, R.layout.listview_item, cache));
  };
 };

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  listView = (ListView) this.findViewById(R.id.listView);
  /**在SD卡中生成缓存目录*/
  cache = new File(Environment.getExternalStorageDirectory(), "cache");
  /**如果目录不存在就新建一个*/
  if (!cache.exists())  cache.mkdir();
   
  new Thread(new Runnable() {
   @Override
   public void run() {
    try {
     //获取联系人数据
     List<Contact> data= ContactService.getContacts();
     // 向Handler发送消息,更新UI
     handler.sendMessage(handler.obtainMessage(22, data));
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  }).start();
 }
 
 @Override
 protected void onDestroy() {
  /**清除缓存文件*/
  for (File file:cache.listFiles()) {
   file.delete();
  }
  cache.delete();
  super.onDestroy();
 }
 
}

step8:AndroidManifest.xml


[html]
<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="cn.roco.data" android:versionCode="1" android:versionName="1.0"> 
    <uses-sdk android:minSdkVersion="8" /> 
     
    <!-- 访问Internet权限 --> 
    <uses-permission android:name="android.permission.INTERNET" /> 
    <!-- 在SD卡中创建和删除文件权限 --> 
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 
    <!-- 往SD卡中写入数据权限 --> 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
 
    <application android:icon="@drawable/icon" android:label="@string/app_name"> 
        <activity android:name=".MainActivity" android:label="@string/app_name"> 
            <intent-filter> 
                <action android:name="android.intent.action.MAIN" /> 
                <category android:name="android.intent.category.LAUNCHER" /> 
            </intent-filter> 
        </activity> 
 
    </application> 
</manifest> 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="cn.roco.data" android:versionCode="1" android:versionName="1.0">
 <uses-sdk android:minSdkVersion="8" />
 
 <!-- 访问Internet权限 -->
 <uses-permission android:name="android.permission.INTERNET" />
 <!-- 在SD卡中创建和删除文件权限 -->
 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
 <!-- 往SD卡中写入数据权限 -->
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

 <application android:icon="@drawable/icon" android:label="@string/app_name">
  <activity android:name=".MainActivity" android:label="@string/app_name">
   <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
  </activity>

 </application>
</manifest>
step9:编写服务器端的代码,主要是一个contact.xml文件


[html]
<?xml version="1.0" encoding="UTF-8"?> 
<contacts> 
    <contact id="1"> 
        <name>Roco_1</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032102399.png" /> 
    </contact> 
    <contact id="2"> 
        <name>Roco_2</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032103840.png" /> 
    </contact> 
    <contact id="3"> 
        <name>Roco_3</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032103320.png" /> 
    </contact> 
    <contact id="4"> 
        <name>Roco_4</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032103459.png" /> 
    </contact> 
    <contact id="5"> 
        <name>Roco_5</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032104874.png" /> 
    </contact> 
    <contact id="6"> 
        <name>Roco_6</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032104668.png" /> 
    </contact> 
    <contact id="7"> 
        <name>Roco_7</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032104615.png" /> 
    </contact> 
    <contact id="8"> 
        <name>Roco_8</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032105398.png" /> 
    </contact> 
    <contact id="9"> 
        <name>Roco_9</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032106799.png" /> 
    </contact> 
    <contact id="10"> 
        <name>Roco_10</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032106442.png" /> 
    </contact> 
    <contact id="11"> 
        <name>Roco_11</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032108933.png" /> 
    </contact> 
    <contact id="12"> 
        <name>Roco_12</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032108268.png" /> 
    </contact> 
    <contact id="13"> 
        <name>Roco_13</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032108395.png" /> 
    </contact> 
    <contact id="14"> 
        <name>Roco_14</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032110808.png" /> 
    </contact> 
    <contact id="15"> 
        <name>Roco_15</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032110349.png" /> 
    </contact> 
    <contact id="16"> 
        <name>Roco_16</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032111248.png" /> 
    </contact> 
    <contact id="17"> 
        <name>Roco_17</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032112162.png" /> 
    </contact> 
    <contact id="18"> 
        <name>Roco_18</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032112322.png" /> 
    </contact> 
    <contact id="19"> 
        <name>Roco_19</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032112787.png" /> 
    </contact> 
    <contact id="20"> 
        <name>Roco_20</name> 
        <image src=http://up.2cto.com/2013/0417/20130417032112445.png" /> 
    </contact> 
</contacts> 

<?xml version="1.0" encoding="UTF-8"?>
<contacts>
 <contact id="1">
  <name>Roco_1</name>
  <image src=http://up.2cto.com/2013/0417/20130417032102399.png" />
 </contact>
 <contact id="2">
  <name>Roco_2</name>
  <image src=http://up.2cto.com/2013/0417/20130417032103840.png" />
 </contact>
 <contact id="3">
  <name>Roco_3</name>
  <image src=http://up.2cto.com/2013/0417/20130417032103320.png" />
 </contact>
 <contact id="4">
  <name>Roco_4</name>
  <image src=http://up.2cto.com/2013/0417/20130417032103459.png" />
 </contact>
 <contact id="5">
  <name>Roco_5</name>
  <image src=http://up.2cto.com/2013/0417/20130417032104874.png" />
 </contact>
 <contact id="6">
  <name>Roco_6</name>
  <image src=http://up.2cto.com/2013/0417/20130417032104668.png" />
 </contact>
 <contact id="7">
  <name>Roco_7</name>
  <image src=http://up.2cto.com/2013/0417/20130417032104615.png" />
 </contact>
 <contact id="8">
  <name>Roco_8</name>
  <image src=http://up.2cto.com/2013/0417/20130417032105398.png" />
 </contact>
 <contact id="9">
  <name>Roco_9</name>
  <image src=http://up.2cto.com/2013/0417/20130417032106799.png" />
 </contact>
 <contact id="10">
  <name>Roco_10</name>
  <image src=http://up.2cto.com/2013/0417/20130417032106442.png" />
 </contact>
 <contact id="11">
  <name>Roco_11</name>
  <image src=http://up.2cto.com/2013/0417/20130417032108933.png" />
 </contact>
 <contact id="12">
  <name>Roco_12</name>
  <image src=http://up.2cto.com/2013/0417/20130417032108268.png" />
 </contact>
 <contact id="13">
  <name>Roco_13</name>
  <image src=http://up.2cto.com/2013/0417/20130417032108395.png" />
 </contact>
 <contact id="14">
  <name>Roco_14</name>
  <image src=http://up.2cto.com/2013/0417/20130417032110808.png" />
 </contact>
 <contact id="15">
  <name>Roco_15</name>
  <image src=http://up.2cto.com/2013/0417/20130417032110349.png" />
 </contact>
 <contact id="16">
  <name>Roco_16</name>
  <image src=http://up.2cto.com/2013/0417/20130417032111248.png" />
 </contact>
 <contact id="17">
  <name>Roco_17</name>
  <image src=http://up.2cto.com/2013/0417/20130417032112162.png" />
 </contact>
 <contact id="18">
  <name>Roco_18</name>
  <image src=http://up.2cto.com/2013/0417/20130417032112322.png" />
 </contact>
 <contact id="19">
  <name>Roco_19</name>
  <image src=http://up.2cto.com/2013/0417/20130417032112787.png" />
 </contact>
 <contact id="20">
  <name>Roco_20</name>
  <image src=http://up.2cto.com/2013/0417/20130417032112445.png" />
 </contact>
</contacts>
以及在images目录下放置了一些图片

 

 \
 

 


step10:将项目部署到模拟器上运行效果如下图:

       \         \
 


在SD卡中会生成缓存文件

 

\
当应用退出的时候,会将缓存文件删除

 

 \

 

有了缓存文件,只要应用没有退出,即使联网不成功,也可以读取缓存中的图片文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值