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

  • 相关阅读:
    HDU 2955 Robberies(01背包)
    HDU 2602 Bone Collector(01背包)
    HUST 1352 Repetitions of Substrings(字符串)
    HUST 1358 Uiwurerirexb jeqvad(模拟解密)
    HUST 1404 Hamming Distance(字符串)
    HDU 4520 小Q系列故事――最佳裁判(STL)
    HDU 2058 The sum problem(枚举)
    【破解】修改程序版权、添加弹窗
    HDU 1407 测试你是否和LTC水平一样高(枚举)
    HDU 1050 Moving Tables(贪心)
  • 原文地址:https://www.cnblogs.com/huolongluo/p/5541816.html
Copyright © 2011-2022 走看看