来自: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每一项的封装类

 package com.example.imoocnews;

 public class NewsBean {
private String newsIconUrl;//图片的网址即picSmall
private String newsTitle;//图片的标题即json中的name属性
private String newsContent;//图片的内容即json中的description public NewsBean(String newsIconUrl, String newsTitle, String newsContent)
{
this.newsIconUrl = newsIconUrl;
this.newsTitle = newsTitle;
this.newsContent = newsContent;
}
public String getNewsIconUrl() {
return newsIconUrl;
}
public void setNewsIconUrl(String newsIconUrl) {
this.newsIconUrl = newsIconUrl;
}
public String getNewsTitle() {
return newsTitle;
}
public void setNewsTitle(String newsTitle) {
this.newsTitle = newsTitle;
}
public String getNewsContent() {
return newsContent;
}
public void setNewsContent(String newsContent) {
this.newsContent = newsContent;
} }

2 适配器NewsAdapter.java

 package com.example.imoocnews;

 import java.util.List;

 import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AbsListView; /**
* listview的适配器,包括上下文对象和数据源
* 提高listview的效率:当listview滚动时不去加载可见项图片,停止滚动后再开始加载
*/
public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener{ private LayoutInflater mInflater;
private List<NewsBean> mList;
private ImageLoader mImageLoader;
private int mStart, mEnd;//listview屏幕可视范围内的第一条item和最后一个item
public static String URLS[];//设置一个数组,用来保存所有图片的URL
private boolean mFirstIn;//判断是否是第一次启动程序 public NewsAdapter(Context context, List<NewsBean> data, ListView listView) {
mInflater = LayoutInflater.from(context);
this.mList = data;
mImageLoader = new ImageLoader(listView);//在这里初始化,能够保证只有一个imageloader的实例,即只有一个LruCache的实例
URLS = new String[data.size()];
for (int i = 0; i < data.size(); i++) {
URLS[i] = data.get(i).getNewsIconUrl();//将data中的每一个URL赋值给数组
}
listView.setOnScrollListener(this);
mFirstIn = true;//写在构造函数中,第一次调用newsAdapter时表示第一次启动程序,显示listview
} @Override
public int getCount() {
return mList.size();
} @Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mList.get(position);
} @Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item, null);
holder = new ViewHolder();
holder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
holder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
holder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
//holder.ivIcon.setImageResource(R.drawable.ic_launcher);
String url = mList.get(position).getNewsIconUrl();
holder.ivIcon.setTag(url);//给ImageView设置标志,即对应的图片网址
//利用thread类实现异步加载图片,我们这里将其注释,使用AsyncTask的方式
//new ImageLoader().showImageByThread(holder.ivIcon, mList.get(position).getNewsIconUrl());
mImageLoader.showImages(holder.ivIcon, url); holder.tvTitle.setText(mList.get(position).getNewsTitle());
holder.tvContent.setText(mList.get(position).getNewsContent());
return convertView;
}
class ViewHolder
{
public ImageView ivIcon;
public TextView tvTitle, tvContent;
}
/*
* 当listview滑动的时候调用
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
mStart = firstVisibleItem;
mEnd = mStart + visibleItemCount;
//只在第一次加载的时候调用
if (mFirstIn && visibleItemCount >0) {//表示第一次加载listview并且已经绘制了可见范围内的item
mImageLoader.loadImages(mStart, mEnd);
mFirstIn = false;//加载图片后即设为false
}
} /*
* 当listview滑动状态变化时调用
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {//listview停止滚动
//加载可见项
mImageLoader.loadImages(mStart, mEnd); }else {
//停止加载任务
mImageLoader.cancelAllTasks();
} } }

3 访问图片的实现ImageLoader.java

 package com.example.imoocnews;

 import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set; import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.LruCache;
import android.widget.ImageView;
import android.widget.ListView; public class ImageLoader {
private ImageView mImageView;
private String url;
//当图片加载过后就将图片缓存到本地,下次便不用重新联网获取,直接从本地缓存获取即可,一个图片即string url --> bitmap
private LruCache<String, Bitmap> mCache;
private ListView mListView;
private Set<NewsAsyncTask> mTasks;//从start到end范围每次执行加载图片任务的集合 public ImageLoader(ListView listView)
{
mListView = listView;
mTasks = new HashSet<ImageLoader.NewsAsyncTask>();
int maxMemory = (int) Runtime.getRuntime().maxMemory();//获取最大可用内存
int cacheSize = maxMemory/4;//设置缓存的大小
mCache = new LruCache<String, Bitmap>(cacheSize){
@Override
protected int sizeOf(String key, Bitmap value) {
// 每次将图片存入缓存时返回图片的大小
return value.getByteCount();
}
};
}
/**
* 将已联网获取成功的图片加入到缓存中
* @param bitmap
*/
public void addBitmapToCache(String url, Bitmap bitmap)
{
//在将图片缓存到本地之前要判断这个图片是否已经缓存过了
if (getBitmapFromCache(url) == null) {
mCache.put(url, bitmap);
}
}
/**
* 通过URL从缓存中取出相应的图片
*/
public Bitmap getBitmapFromCache(String url)
{
return mCache.get(url);
} private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
super.handleMessage(msg);
//通过tag使得ImageView和它对应的URL绑定,这样在上下滑动listview时ImageView显示的图片就始终是正确的
//否则,由于listview的缓存机制,ImageView会先显示出上次加载成功时的图片,然后再显示正确的图片
if (mImageView.getTag().equals(url)) {
mImageView.setImageBitmap((Bitmap) msg.obj);//使用handler在主线程中更新UI,并将URL对应的图片设置给控件imageview
} }
}; /**
* 通过使用Thread的方式从网络上获取图片
*/
public void showImageByThread(ImageView imageView, final String iconUrl)
{
mImageView = imageView;
url = iconUrl;
new Thread(){
@Override
public void run() {
// 在新的进程中实现图片的加载
super.run();
//从url中获得bitmap,将bitmap发送给主线程
Bitmap bitmap = getBitmapFromUrl(iconUrl);
Message message = Message.obtain();
message.obj = bitmap;
mHandler.sendMessage(message);
}
}.start();
}
public Bitmap getBitmapFromUrl(String urlString)
{
InputStream is = null;
Bitmap bitmap;
try {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
is = new BufferedInputStream(connection.getInputStream());
bitmap = BitmapFactory.decodeStream(is);
connection.disconnect();
//Thread.sleep(1000);
return bitmap;
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally
{
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
} /**
* 加载listview可见范围内的所有图片
*
*/
public void loadImages(int start, int end)
{
for (int i = start; i < end; i++) {
String url = NewsAdapter.URLS[i];
//看是否能从缓存中取出对应的图片
Bitmap bitmap = getBitmapFromCache(url);
//如果缓存中没有,就要对每个url执行异步加载任务去获取图片
if (bitmap == null) {
NewsAsyncTask task = new NewsAsyncTask(url);
task.execute(url);
mTasks.add(task); }else {
//如果缓存中存在此图片,直接将其设置给对应的imageview即可
//因为我们之前给imageview设置的tag就是URL,可以利用findViewWithTag直接在这里获取到
ImageView imageView = (ImageView) mListView.findViewWithTag(url);
imageView.setImageBitmap(bitmap);
}
}
}
/**
* 取消所有正在进行的图片加载任务
*/
public void cancelAllTasks()
{
if (mTasks != null) {
for(NewsAsyncTask task : mTasks)
{
task.cancel(false);
}
}
} public void showImages(ImageView imageView, String iconUrl)
{
//是否能从缓存中取出对应的图片
Bitmap bitmap = getBitmapFromCache(iconUrl);
if (bitmap == null) {
imageView.setImageResource(R.drawable.ic_launcher);//显示默认图片
}else {
//如果缓存中存在此图片,直接将其设置给对应的imageview即可
imageView.setImageBitmap(bitmap);
} }
/**
* 使用AsyncTask实现图片的异步加载
*/
class NewsAsyncTask extends AsyncTask<String, Void, Bitmap>
{
//private ImageView mImageView;
private String mUrl;
public NewsAsyncTask(String url) {
// mImageView = image;
mUrl = url;
}
@Override
protected Bitmap doInBackground(String... params) {
String url = params[0];
Bitmap bitmap = getBitmapFromUrl(url);//从网络上得到图片
if (bitmap != null) {
addBitmapToCache(url, bitmap);//获取图片成功将图片存入缓存中
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
// 后台获取图片的任务完成时调用此方法
super.onPostExecute(bitmap);
//给imageview设置图片
ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
mTasks.remove(this);
}
} }

4. MainActivity.java

 package com.example.imoocnews;

 import java.io.BufferedReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List; import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject; import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView; public class MainActivity extends Activity { private ListView mListView;
private static String jsonURL = "http://www.imooc.com/api/teacher?type=4&num=30";//json数据网址 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.lv_main);
new NewsAsyncTask().execute(jsonURL);
}
/**
* 将URL网址上的json数据转化为我们所需的newsbean对象
* @return
*/
private List<NewsBean> getJsonData(String url)
{
List<NewsBean> newsBeanList = new ArrayList<NewsBean>();//保存解析出来的所有的数据
try {
//获取到json字符串
String jsonString = readStream(new URL(url).openStream());//和url.openConnection().getInputStream()一样
//Log.d("MainActivity", jsonString);
//将获取到的json字符串变为jsonObject对象,打开网址可以看出data节点是一个jsonArray,array里面存放了一个个的jsonObject
NewsBean newsBean;
JSONObject jsonObject;
String newsUrl = null;
String newsTitle = null;
String newsContent = null;
jsonObject = new JSONObject(jsonString);
JSONArray jsonArray = jsonObject.getJSONArray("data");
for (int i = 0; i < jsonArray.length(); i++) {
jsonObject = jsonArray.getJSONObject(i);
newsUrl = jsonObject.getString("picSmall");//图片网址
newsTitle = jsonObject.getString("name");//title
newsContent = jsonObject.getString("description");//content
newsBean = new NewsBean(newsUrl, newsTitle, newsContent);
newsBeanList.add(newsBean);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newsBeanList;
} /**
* 解析网络返回的数据
*/
private String readStream(InputStream is)
{
InputStreamReader isReader;
String result = "";
String line = "";
try {
isReader = new InputStreamReader(is, "utf-8");//将字节流转化为字符流
BufferedReader buffReader = new BufferedReader(isReader);//从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取
while ((line = buffReader.readLine()) != null) {
result += line;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} return result;
}
/**
* 构造一个AsyncTask,传入String类型的URL,返回一个NewsBean对象,每一个对象就是
* listview中的每一行数据,包括一个icon,title,content
*/
class NewsAsyncTask extends AsyncTask<String, Void, List<NewsBean>>
{ @Override
protected List<NewsBean> doInBackground(String... params) {
return getJsonData(params[0]);
} @Override
protected void onPostExecute(List<NewsBean> result) {
super.onPostExecute(result);
// 访问网络并解析json成功后返回结果,即我们设置的List<NewsBean>
NewsAdapter adapter = new NewsAdapter(MainActivity.this, result, mListView);
mListView.setAdapter(adapter);
} } }

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

Android异步加载访问网络图片-解析json的更多相关文章

  1. 演化理解 Android 异步加载图片

    原文:http://www.cnblogs.com/ghj1976/archive/2011/05/06/2038738.html#3018499 在学习"Android异步加载图像小结&q ...

  2. [转载]Android 异步加载解决方案

    2013-12-25 11:15:47 Android 异步加载解决方案,转载自: http://www.open-open.com/lib/view/open1345017746897.html 请 ...

  3. 演化理解 Android 异步加载图片(转)

    演化理解 Android 异步加载图片(转)http://www.cnblogs.com/CJzhang/archive/2011/10/20/2218474.html

  4. android 异步加载框架 原理完全解析

    一.手写异步加载框架MyAsycnTask(核心原理) 1.我为大家手写了一个异步加载框架,涵盖了异步加载框架核心原理. MyAsycnTask.java import android.os.Hand ...

  5. Android异步加载

    一.为什么要使用异步加载? 1.Android是单线程模型 2.耗时操作阻碍UI线程 二.异步加载最常用的两种方式 1.多线程.线程池 2.AsyncTask 三.实现ListView图文混排 3-1 ...

  6. android异步加载图片并缓存到本地实现方法

    图片过多造成内存溢出,这个是最不容易解决的,要想一些好的缓存策略,比如大图片使用LRU缓存策略或懒加载缓存策略.今天首先介绍一下本地缓存图片     在android项目中访问网络图片是非常普遍性的事 ...

  7. Android 异步加载解决方案

    Android的Lazy Load主要体现在网络数据(图片)异步加载.数据库查询.复杂业务逻辑处理以及费时任务操作导致的异步处理等方面.在介绍Android开发过程中,异步处理这个常见的技术问题之前, ...

  8. 实例演示Android异步加载图片

    本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...

  9. 实例演示Android异步加载图片(转)

    本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...

随机推荐

  1. WCF自定义扩展,以实现aop!

    引用地址:https://msdn.microsoft.com/zh-cn/magazine/cc163302.aspx  使用自定义行为扩展 WCF Aaron Skonnard 代码下载位置: S ...

  2. hdu4751 Divide Groups

    This year is the 60th anniversary of NJUST, and to make the celebration more colorful, Tom200 is goi ...

  3. WPF:自定义路由事件的实现

    路由事件通过EventManager,RegisterRoutedEvent方法注册,通过AddHandler和RemoveHandler来关联和解除关联的事件处理函数:通过RaiseEvent方法来 ...

  4. CHAP算法C++实现

    CHAP是一种挑战响应式协议. CHAP全称为:Challenge Handshake Authentication Protocol. CHAP密码 = 一个字节的标识符 + MD5(一个字节的标识 ...

  5. C和指针 第一章 字符串处理程序

    #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_COL 20 #def ...

  6. 题目1373:整数中1出现的次数(从1到n整数中1出现的次数)

    题目1373:整数中1出现的次数(从1到n整数中1出现的次数) 题目描述: 亲们!!我们的外国友人YZ这几天总是睡不好,初中奥数里有一个题目一直困扰着他,特此他向JOBDU发来求助信,希望亲们能帮帮他 ...

  7. nginx命令

    window  cmd 到nginx的文件夹 start nginx    启动命令 nginx -s reload 重新启动 nginx -s stop   关闭   linux   到 sbin ...

  8. BZOJ1798——[Ahoi2009]Seq维护序列seq

    1.题目大意:区间修改乘法操作和加法操作,求区间和 2.分析:为了填补bzoj2631的坑还是写一发题解吧,首先呢,既然想要双标记,但是这两个标记之间又有着制约作用,所以要定义优先级,这个优先级就定义 ...

  9. Bootstrap IIFE

    在Bootstrap源码(具体请看<Bootstrap源码解析>)和其他jQuery插件经常看到如下的写法: +function ($) { }(window.jQuery); 这种写法称 ...

  10. BZOJ 1019: [SHOI2008]汉诺塔

    Description 一个汉诺塔,给出了移动的优先顺序,问从A移到按照规则移到另一个柱子上的最少步数. 规则:小的在大的上面,每次不能移动上一次移动的,选择可行的优先级最高的. Sol DP. 倒着 ...