zoukankan      html  css  js  c++  java
  • Android异步加载访问网络图片-解析json

    来自:http://www.imooc.com/video/7871 
    推荐大家去学习这个视频,讲解的很不错。 
    慕课网提供了一个json网址可以用来学习:http://www.imooc.com/api/teacher?type=4&num=30。我们的任务就是建立一个listview,将json提供的一些参数,主要是name,picSmall,description显示出来,效果图如下: 

    主要思路如下:listview中图片的加载,程序中使用了两种方式,一种是使用Thread类,一种是使用AsyncTask,为了提高listview滑动的效率,并节省流量,使用了LruCache类,更改加载图片的处理逻辑为:当滑动listview时不加载图片,停止滑动listview时加载界面可视范围内的图片。具体程序如下: 
    1 NewsBean.Java listview每一项的封装类

     1 package com.example.imoocnews;
     2 
     3 public class NewsBean {
     4     private String newsIconUrl;//图片的网址即picSmall
     5     private String newsTitle;//图片的标题即json中的name属性
     6     private String newsContent;//图片的内容即json中的description
     7 
     8     public NewsBean(String newsIconUrl, String newsTitle, String newsContent)
     9     {
    10         this.newsIconUrl = newsIconUrl;
    11         this.newsTitle = newsTitle;
    12         this.newsContent = newsContent;
    13     }
    14     public String getNewsIconUrl() {
    15         return newsIconUrl;
    16     }
    17     public void setNewsIconUrl(String newsIconUrl) {
    18         this.newsIconUrl = newsIconUrl;
    19     }
    20     public String getNewsTitle() {
    21         return newsTitle;
    22     }
    23     public void setNewsTitle(String newsTitle) {
    24         this.newsTitle = newsTitle;
    25     }
    26     public String getNewsContent() {
    27         return newsContent;
    28     }
    29     public void setNewsContent(String newsContent) {
    30         this.newsContent = newsContent;
    31     }
    32 
    33 
    34 }

    2 适配器NewsAdapter.java

      1 package com.example.imoocnews;
      2 
      3 import java.util.List;
      4 
      5 import android.content.Context;
      6 import android.view.LayoutInflater;
      7 import android.view.View;
      8 import android.view.ViewGroup;
      9 import android.widget.BaseAdapter;
     10 import android.widget.ImageView;
     11 import android.widget.ListView;
     12 import android.widget.TextView;
     13 import android.widget.AbsListView;
     14 
     15 /**
     16  * listview的适配器,包括上下文对象和数据源
     17  * 提高listview的效率:当listview滚动时不去加载可见项图片,停止滚动后再开始加载
     18  */
     19 public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener{
     20 
     21     private LayoutInflater mInflater;
     22     private List<NewsBean> mList;
     23     private ImageLoader mImageLoader;
     24     private int mStart, mEnd;//listview屏幕可视范围内的第一条item和最后一个item
     25     public static String URLS[];//设置一个数组,用来保存所有图片的URL
     26     private boolean mFirstIn;//判断是否是第一次启动程序
     27 
     28     public NewsAdapter(Context context, List<NewsBean> data, ListView listView) {
     29         mInflater = LayoutInflater.from(context);
     30         this.mList = data;
     31         mImageLoader = new ImageLoader(listView);//在这里初始化,能够保证只有一个imageloader的实例,即只有一个LruCache的实例
     32         URLS = new String[data.size()];
     33         for (int i = 0; i < data.size(); i++) {
     34             URLS[i] = data.get(i).getNewsIconUrl();//将data中的每一个URL赋值给数组
     35         }
     36         listView.setOnScrollListener(this);
     37         mFirstIn = true;//写在构造函数中,第一次调用newsAdapter时表示第一次启动程序,显示listview
     38     }
     39 
     40     @Override
     41     public int getCount() {     
     42         return mList.size();
     43     }
     44 
     45     @Override
     46     public Object getItem(int position) {
     47         // TODO Auto-generated method stub
     48         return mList.get(position);
     49     }
     50 
     51     @Override
     52     public long getItemId(int position) {
     53         // TODO Auto-generated method stub
     54         return position;
     55     }
     56 
     57     @Override
     58     public View getView(int position, View convertView, ViewGroup parent) {
     59         ViewHolder holder = null;
     60         if (convertView == null) {
     61             convertView = mInflater.inflate(R.layout.item, null);
     62             holder = new ViewHolder();
     63             holder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
     64             holder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
     65             holder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
     66             convertView.setTag(holder);
     67         }else {
     68             holder = (ViewHolder) convertView.getTag();
     69         }
     70         //holder.ivIcon.setImageResource(R.drawable.ic_launcher);
     71         String url = mList.get(position).getNewsIconUrl();
     72         holder.ivIcon.setTag(url);//给ImageView设置标志,即对应的图片网址 
     73         //利用thread类实现异步加载图片,我们这里将其注释,使用AsyncTask的方式
     74         //new ImageLoader().showImageByThread(holder.ivIcon, mList.get(position).getNewsIconUrl());
     75         mImageLoader.showImages(holder.ivIcon, url);
     76 
     77         holder.tvTitle.setText(mList.get(position).getNewsTitle());
     78         holder.tvContent.setText(mList.get(position).getNewsContent());
     79         return convertView;
     80     }
     81     class ViewHolder
     82     {
     83         public ImageView ivIcon;
     84         public TextView tvTitle, tvContent;
     85     }
     86     /* 
     87      * 当listview滑动的时候调用
     88      */
     89     @Override
     90     public void onScroll(AbsListView view, int firstVisibleItem,
     91             int visibleItemCount, int totalItemCount) {
     92         mStart = firstVisibleItem;
     93         mEnd = mStart + visibleItemCount;
     94         //只在第一次加载的时候调用
     95         if (mFirstIn && visibleItemCount >0) {//表示第一次加载listview并且已经绘制了可见范围内的item
     96             mImageLoader.loadImages(mStart, mEnd);
     97             mFirstIn = false;//加载图片后即设为false
     98         }
     99     }
    100 
    101     /* 
    102      * 当listview滑动状态变化时调用
    103      */
    104     @Override
    105     public void onScrollStateChanged(AbsListView view, int scrollState) {
    106         if (scrollState == SCROLL_STATE_IDLE) {//listview停止滚动
    107             //加载可见项
    108             mImageLoader.loadImages(mStart, mEnd);
    109 
    110         }else {
    111             //停止加载任务
    112             mImageLoader.cancelAllTasks();
    113         }
    114 
    115     }
    116 
    117 }

    3 访问图片的实现ImageLoader.java

      1 package com.example.imoocnews;
      2 
      3 import java.io.BufferedInputStream;
      4 import java.io.IOException;
      5 import java.io.InputStream;
      6 import java.net.HttpURLConnection;
      7 import java.net.MalformedURLException;
      8 import java.net.URL;
      9 import java.util.HashSet;
     10 import java.util.Set;
     11 
     12 import android.graphics.Bitmap;
     13 import android.graphics.BitmapFactory;
     14 import android.os.AsyncTask;
     15 import android.os.Handler;
     16 import android.os.Message;
     17 import android.util.LruCache;
     18 import android.widget.ImageView;
     19 import android.widget.ListView;
     20 
     21 public class ImageLoader {
     22     private ImageView mImageView;
     23     private String url;
     24     //当图片加载过后就将图片缓存到本地,下次便不用重新联网获取,直接从本地缓存获取即可,一个图片即string url --> bitmap
     25     private LruCache<String, Bitmap> mCache;
     26     private ListView mListView;
     27     private Set<NewsAsyncTask> mTasks;//从start到end范围每次执行加载图片任务的集合
     28 
     29     public ImageLoader(ListView listView)
     30     {
     31         mListView = listView;
     32         mTasks = new HashSet<ImageLoader.NewsAsyncTask>();
     33         int maxMemory = (int) Runtime.getRuntime().maxMemory();//获取最大可用内存
     34         int cacheSize = maxMemory/4;//设置缓存的大小
     35         mCache = new LruCache<String, Bitmap>(cacheSize){
     36             @Override
     37             protected int sizeOf(String key, Bitmap value) {
     38                 // 每次将图片存入缓存时返回图片的大小
     39                 return value.getByteCount();
     40             }
     41         };
     42     }
     43     /**
     44      * 将已联网获取成功的图片加入到缓存中
     45      * @param bitmap
     46      */
     47     public void addBitmapToCache(String url, Bitmap bitmap)
     48     {
     49         //在将图片缓存到本地之前要判断这个图片是否已经缓存过了
     50         if (getBitmapFromCache(url) == null) {
     51             mCache.put(url, bitmap);
     52         }
     53     }
     54     /**
     55      * 通过URL从缓存中取出相应的图片
     56      */
     57     public Bitmap getBitmapFromCache(String url)
     58     {
     59         return mCache.get(url);
     60     }
     61 
     62     private Handler mHandler = new Handler(){
     63         public void handleMessage(Message msg) {
     64             super.handleMessage(msg);
     65             //通过tag使得ImageView和它对应的URL绑定,这样在上下滑动listview时ImageView显示的图片就始终是正确的
     66             //否则,由于listview的缓存机制,ImageView会先显示出上次加载成功时的图片,然后再显示正确的图片
     67             if (mImageView.getTag().equals(url)) {
     68                 mImageView.setImageBitmap((Bitmap) msg.obj);//使用handler在主线程中更新UI,并将URL对应的图片设置给控件imageview
     69             }
     70 
     71         }
     72     };
     73 
     74     /**
     75      * 通过使用Thread的方式从网络上获取图片
     76      */
     77     public void showImageByThread(ImageView imageView, final String iconUrl)
     78     {
     79         mImageView = imageView;
     80         url = iconUrl;
     81         new Thread(){
     82             @Override
     83             public void run() {
     84                 // 在新的进程中实现图片的加载
     85                 super.run();
     86                 //从url中获得bitmap,将bitmap发送给主线程
     87                 Bitmap bitmap = getBitmapFromUrl(iconUrl);
     88                 Message message = Message.obtain();
     89                 message.obj = bitmap;
     90                 mHandler.sendMessage(message);
     91             }
     92         }.start();
     93     }
     94     public Bitmap getBitmapFromUrl(String urlString)
     95     {
     96         InputStream is = null;
     97         Bitmap bitmap;
     98         try {
     99             URL url = new URL(urlString);
    100             HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    101             is = new BufferedInputStream(connection.getInputStream());
    102             bitmap = BitmapFactory.decodeStream(is);
    103             connection.disconnect();
    104             //Thread.sleep(1000);
    105             return bitmap;
    106         } catch (MalformedURLException e) {
    107             // TODO Auto-generated catch block
    108             e.printStackTrace();
    109         } catch (IOException e) {
    110             // TODO Auto-generated catch block
    111             e.printStackTrace();
    112         } finally
    113         {
    114             try {
    115                 is.close();
    116             } catch (IOException e) {
    117                 // TODO Auto-generated catch block
    118                 e.printStackTrace();
    119             }
    120         }
    121         return null;
    122     }
    123 
    124     /**
    125      * 加载listview可见范围内的所有图片
    126      * 
    127      */
    128     public void loadImages(int start, int end)
    129     {
    130         for (int i = start; i < end; i++) {
    131             String url = NewsAdapter.URLS[i];
    132             //看是否能从缓存中取出对应的图片
    133             Bitmap bitmap = getBitmapFromCache(url);
    134             //如果缓存中没有,就要对每个url执行异步加载任务去获取图片
    135             if (bitmap == null) {
    136                 NewsAsyncTask task = new NewsAsyncTask(url);
    137                 task.execute(url);
    138                 mTasks.add(task);
    139 
    140             }else {
    141                 //如果缓存中存在此图片,直接将其设置给对应的imageview即可
    142                 //因为我们之前给imageview设置的tag就是URL,可以利用findViewWithTag直接在这里获取到
    143                 ImageView imageView = (ImageView) mListView.findViewWithTag(url);
    144                 imageView.setImageBitmap(bitmap);
    145             }
    146         }
    147     }
    148     /**
    149      * 取消所有正在进行的图片加载任务
    150      */
    151     public void cancelAllTasks()
    152     {
    153         if (mTasks != null) {
    154             for(NewsAsyncTask task : mTasks)
    155             {
    156                 task.cancel(false);
    157             }
    158         }
    159     }
    160 
    161     public void showImages(ImageView imageView, String iconUrl)
    162     {
    163         //是否能从缓存中取出对应的图片
    164         Bitmap bitmap = getBitmapFromCache(iconUrl);
    165         if (bitmap == null) {
    166             imageView.setImageResource(R.drawable.ic_launcher);//显示默认图片
    167         }else {
    168             //如果缓存中存在此图片,直接将其设置给对应的imageview即可
    169             imageView.setImageBitmap(bitmap);
    170         }
    171 
    172     }
    173     /**
    174      * 使用AsyncTask实现图片的异步加载
    175      */
    176     class NewsAsyncTask extends AsyncTask<String, Void, Bitmap>
    177     {
    178         //private ImageView mImageView;
    179         private String mUrl;
    180         public NewsAsyncTask(String url) {
    181         //  mImageView = image;
    182             mUrl = url;
    183         }
    184         @Override
    185         protected Bitmap doInBackground(String... params) {
    186             String url = params[0];
    187             Bitmap bitmap = getBitmapFromUrl(url);//从网络上得到图片
    188             if (bitmap != null) {
    189                 addBitmapToCache(url, bitmap);//获取图片成功将图片存入缓存中
    190             }
    191             return bitmap;
    192         }
    193         @Override
    194         protected void onPostExecute(Bitmap bitmap) {
    195             // 后台获取图片的任务完成时调用此方法
    196             super.onPostExecute(bitmap);
    197             //给imageview设置图片
    198             ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl);
    199             if (imageView != null && bitmap != null) {
    200                 imageView.setImageBitmap(bitmap);
    201             }
    202             mTasks.remove(this);
    203         }
    204     }
    205 
    206 }

    4. MainActivity.java

      1 package com.example.imoocnews;
      2 
      3 import java.io.BufferedReader;
      4 import java.net.MalformedURLException;
      5 import java.net.URL;
      6 import java.io.IOException;
      7 import java.io.InputStream;
      8 import java.io.InputStreamReader;
      9 import java.io.UnsupportedEncodingException;
     10 import java.util.ArrayList;
     11 import java.util.List;
     12 
     13 import org.json.JSONArray;
     14 import org.json.JSONException;
     15 import org.json.JSONObject;
     16 
     17 import android.app.Activity;
     18 import android.os.AsyncTask;
     19 import android.os.Bundle;
     20 import android.util.Log;
     21 import android.view.Menu;
     22 import android.view.MenuItem;
     23 import android.widget.ListView;
     24 
     25 public class MainActivity extends Activity {
     26 
     27     private ListView mListView;
     28     private static String jsonURL = "http://www.imooc.com/api/teacher?type=4&num=30";//json数据网址
     29 
     30     @Override
     31     protected void onCreate(Bundle savedInstanceState) {
     32         super.onCreate(savedInstanceState);
     33         setContentView(R.layout.activity_main);
     34         mListView = (ListView) findViewById(R.id.lv_main);
     35         new NewsAsyncTask().execute(jsonURL);
     36     }
     37     /**
     38      * 将URL网址上的json数据转化为我们所需的newsbean对象
     39      * @return
     40      */
     41     private List<NewsBean> getJsonData(String url)
     42     {
     43         List<NewsBean> newsBeanList = new ArrayList<NewsBean>();//保存解析出来的所有的数据
     44         try {
     45             //获取到json字符串
     46             String jsonString = readStream(new URL(url).openStream());//和url.openConnection().getInputStream()一样
     47             //Log.d("MainActivity", jsonString);
     48             //将获取到的json字符串变为jsonObject对象,打开网址可以看出data节点是一个jsonArray,array里面存放了一个个的jsonObject
     49             NewsBean newsBean;
     50             JSONObject jsonObject;
     51             String newsUrl = null;
     52             String newsTitle = null;
     53             String newsContent = null;
     54             jsonObject = new JSONObject(jsonString);
     55             JSONArray jsonArray = jsonObject.getJSONArray("data");
     56             for (int i = 0; i < jsonArray.length(); i++) {
     57                 jsonObject = jsonArray.getJSONObject(i);
     58                 newsUrl = jsonObject.getString("picSmall");//图片网址
     59                 newsTitle = jsonObject.getString("name");//title
     60                 newsContent = jsonObject.getString("description");//content
     61                 newsBean = new NewsBean(newsUrl, newsTitle, newsContent);
     62                 newsBeanList.add(newsBean);
     63             }
     64         } catch (MalformedURLException e) {         
     65             e.printStackTrace();
     66         } catch (IOException e) {
     67             e.printStackTrace();
     68         } catch (JSONException e) {
     69             // TODO Auto-generated catch block
     70             e.printStackTrace();
     71         }
     72         return newsBeanList;
     73     }
     74 
     75     /**
     76      * 解析网络返回的数据
     77      */
     78     private String readStream(InputStream is)
     79     {
     80         InputStreamReader isReader;
     81         String result = "";
     82         String line = "";
     83         try {
     84             isReader = new InputStreamReader(is, "utf-8");//将字节流转化为字符流
     85             BufferedReader buffReader = new BufferedReader(isReader);//从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取
     86             while ((line = buffReader.readLine()) != null) {
     87                 result += line;
     88             }
     89         } catch (UnsupportedEncodingException e) {
     90             e.printStackTrace();
     91         } catch (IOException e) {
     92             // TODO Auto-generated catch block
     93             e.printStackTrace();
     94         }
     95 
     96         return result;
     97     }
     98     /**
     99      * 构造一个AsyncTask,传入String类型的URL,返回一个NewsBean对象,每一个对象就是
    100      * listview中的每一行数据,包括一个icon,title,content
    101      */
    102     class NewsAsyncTask extends AsyncTask<String, Void, List<NewsBean>>
    103     {
    104 
    105         @Override
    106         protected List<NewsBean> doInBackground(String... params) {         
    107             return getJsonData(params[0]);
    108         }
    109 
    110         @Override
    111         protected void onPostExecute(List<NewsBean> result) {
    112             super.onPostExecute(result);
    113             // 访问网络并解析json成功后返回结果,即我们设置的List<NewsBean>
    114             NewsAdapter adapter = new NewsAdapter(MainActivity.this, result, mListView);
    115             mListView.setAdapter(adapter);
    116         }
    117 
    118     }
    119 
    120 }

    源码在这里:http://download.csdn.net/detail/hnyzwtf/9418993

  • 相关阅读:
    雅虎35条优化黄金守则
    安装入门
    NPOI 2.0 Excel读取显示
    STL算法
    MVVM框架avalon在兼容旧式IE
    Asp.Net MVC3.0网站统计登录认证的在线人数
    Windows Server 服务器安全配置
    SignalR的服务器广播
    angularjs + seajs构建Web Form3
    MVC应用程序显示上传的图片
  • 原文地址:https://www.cnblogs.com/huolongluo/p/5541816.html
Copyright © 2011-2022 走看看