标签:
异步加载最常用的两种方式: 多线程,线程池 AsyncTask
实例操作:
从一个网站上获取Json数据,然后将数据在ListView上显示。
1.创建item_layout布局 , 修改主界面布局
item_layout.xml
<?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="wrap_content" android:padding="4dp" android:orientation="horizontal" > <ImageView android:id="@+id/iv_icon" android:layout_width="64dp" android:layout_height="64dp" android:src="@drawable/ic_launcher" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" android:paddingLeft="4dp"> <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="15sp" android:text="Title" android:maxLines="1" /> <TextView android:id="@+id/tv_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="10sp" android:maxLines="3" android:text="Content"/> </LinearLayout> </LinearLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <ListView android:id="@+id/lv_main" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </RelativeLayout>
NewsBean.java
package com.example.newsimooc; public class NewsBean { public String newsIconUrl;//图片 public String newsTitle; public String newsContent; }
NewsAdapter.java
package com.example.newsimooc; import java.util.ArrayList; 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.TextView; public class NewsAdapter extends BaseAdapter { private List<NewsBean> mList; private LayoutInflater mInflater; public NewsAdapter(Context context, List<NewsBean> data){ mList = data; mInflater = LayoutInflater.from(context); } @Override public int getCount() { // TODO Auto-generated method stub 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 converView, ViewGroup arg2) { // TODO Auto-generated method stub ViewHolder viewHolder = null; if(converView == null){ viewHolder = new ViewHolder(); converView = mInflater.inflate(R.layout.item_layout, null); viewHolder.ivIcon =(ImageView) converView.findViewById(R.id.iv_icon); viewHolder.tvTitle = (TextView)converView.findViewById(R.id.tv_title); viewHolder.tvContent = (TextView)converView.findViewById(R.id.tv_content); converView.setTag(viewHolder); }else{ viewHolder = (ViewHolder) converView.getTag(); } viewHolder.ivIcon.setImageResource(R.drawable.ic_launcher); viewHolder.tvTitle.setText(mList.get(position).newsTitle); viewHolder.tvContent.setText(mList.get(position).newsContent); return converView; } class ViewHolder{ public TextView tvTitle, tvContent; public ImageView ivIcon; } }
MainActivity.java
package com.example.newsimooc; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.os.AsyncTask; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.widget.ListView; public class MainActivity extends Activity { private ListView mListView; private static String URL = "http://www.imooc.com/api/teacher?type=4&num=34"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (ListView) findViewById(R.id.lv_main); new NewsAsyncTask().execute(URL); } //获取Jason数据并解析到newsbean中,将url对应的Jsong格式数据转化为我们封装的NewsBean对象 private List<NewsBean> getJsonData(String url){ List<NewsBean> newsBeansList = new ArrayList<NewsBean>(); try { String jsonString = readStream(new URL(url).openStream()); //new URL(url).openStream()此句与url.openConnection().getInputStream()相同 //可根据URL直接联网获取网络数据,简单粗暴,返回值类型为InputStream JSONObject jsonObject; NewsBean newsBean; try { jsonObject = new JSONObject(jsonString); //获取数据集中的每个对象,把每个对象都封装到一个NewsBean中 JSONArray jsonArray = jsonObject.getJSONArray("data");//data是数据集的名字,查看捕获到的JSONSTRING字符串的内容就可以看到 for(int i = 0; i <jsonArray.length(); i++){ jsonObject = jsonArray.getJSONObject(i); newsBean = new NewsBean(); newsBean.newsIconUrl = jsonObject.getString("picSmall"); newsBean.newsTitle = jsonObject.getString("name"); newsBean.newsContent = jsonObject.getString("description"); newsBeansList.add(newsBean); } } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return newsBeansList; } private String readStream(InputStream is){ //通过is解析网页返回的数据 InputStreamReader isr; String result = ""; try { String line = ""; isr = new InputStreamReader(is, "utf-8");//字节流转化为字符流 BufferedReader br = new BufferedReader(isr); try { while((line = br.readLine()) != null){ result += line; } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result;//网页数据组成的字符串 } //实现网络的异步访问 class NewsAsyncTask extends AsyncTask<String, Void, List<NewsBean>>{ //返回的是NewsBean的集合 @Override protected List<NewsBean> doInBackground(String... params) { // TODO Auto-generated method stub return getJsonData(params[0]); //传入的参数只有一个,就是URL那个网址 } //将数据设置到listView上 @Override protected void onPostExecute(List<NewsBean> newsBeans) { //doInBackground返回的是一个List // TODO Auto-generated method stub super.onPostExecute(newsBeans); NewsAdapter adapter = new NewsAdapter(MainActivity.this, newsBeans); mListView.setAdapter(adapter); } } }
至此,已经实现了抓取数据,并在listView上显示,如图:
注意到这里图片是默认的,并没有访问网络,接下来就是采用异步处理加载网络图片。
此时的源代码:还未实现图片的异步加载
然后增加缓存机制,已经下载的图片就不用再下载了。
如何提高用户体验:使用缓存
LRU算法:Least Recently Used 近期最少使用算法 Android提供了LruCache类来实现这个缓存算法
ImageLoader.java 用来异步加载图片
package com.example.newsimooc; 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 android.R.integer; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Handler; import android.os.Message; import android.support.v4.util.LruCache; import android.webkit.URLUtil; import android.widget.ImageView; //专门用来加载图片 public class ImageLoader { private ImageView mImageView; private String mUrl; //创建Cache private LruCache<String, Bitmap>mCaches;//第一个是K,关键字,第二个是V,值,需要缓存的对象 //实际上是一个map public ImageLoader(){ //获取最大可用内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 4; mCaches = new LruCache<String, Bitmap>(cacheSize){ //必须重写 @Override protected int sizeOf(String key, Bitmap value) { //在每次存入缓存的时候调用 return value.getByteCount(); } }; } //增加到缓存 public void addBitmapToCache(String url, Bitmap bitmap){ if(getBitmapFromCache(url)== null ){ mCaches.put(url, bitmap); } } //从缓存中获取数据 public Bitmap getBitmapFromCache(String url){ return mCaches.get(url); } private Handler mhandler = new Handler(){ //多线程方法中使用的 public void handleMessage(android.os.Message msg) { super.handleMessage(msg); if (mImageView.getTag().equals(mUrl)) { mImageView.setImageBitmap((Bitmap) msg.obj); } }; }; //使用多线程的方式显示图片 public void showImageByThread(ImageView imageView, final String url){ mImageView = imageView; mUrl = url; new Thread(){ @Override public void run() { // TODO Auto-generated method stub super.run(); Bitmap bitmap = getBitmapFromURL(url); //此时bitmap不能直接装载在imageView上,要以消息的形式发送给主线程 //由handler装载图片 Message message =Message.obtain(); message.obj = bitmap; mhandler.sendMessage(message); } }.start(); } //将url解析为bitmap public Bitmap getBitmapFromURL(String urlString){ Bitmap bitmap; InputStream is = null; try { URL url = new URL(urlString); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); is = new BufferedInputStream(connection.getInputStream()); bitmap = BitmapFactory.decodeStream(is); connection.disconnect(); return bitmap; } 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; } public void showImageByAsyncTask(ImageView imageView, String url){ //从缓存中取出对应的图片 Bitmap bitmap = getBitmapFromCache(url); //从内存中找到图片 if(bitmap == null){//如果没有,必须去网络下载 new NewsAsyncTask(imageView, url).execute(url); }else { imageView.setImageBitmap(bitmap); } } private class NewsAsyncTask extends AsyncTask<String, Void, Bitmap>{ private ImageView mImageView; private String mUrl; public NewsAsyncTask(ImageView imageView ,String urlString){ mImageView = imageView; mUrl = urlString; } @Override protected Bitmap doInBackground(String... params) { // TODO Auto-generated method stub String url = params[0]; //从网络获取图片 Bitmap bitmap = getBitmapFromURL(params[0]); if(bitmap != null){ //下载到了图片 就保存到Cache中去 addBitmapToCache(url, bitmap); } return bitmap; } @Override protected void onPostExecute(Bitmap bitmap) { // TODO Auto-generated method stub super.onPostExecute(bitmap); if(mImageView.getTag().equals(mUrl)) mImageView.setImageBitmap(bitmap); } } }NewsAdapter.java
package com.example.newsimooc; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; public class NewsAdapter extends BaseAdapter{ private List<NewsBean> mList; private LayoutInflater mInflater; private ImageLoader mImageLoader; public NewsAdapter(Context context, List<NewsBean> data){ mList = data; mInflater = LayoutInflater.from(context); mImageLoader = new ImageLoader();//保证了只有一个LRUCache } @Override public int getCount() { // TODO Auto-generated method stub 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 converView, ViewGroup arg2) { // TODO Auto-generated method stub ViewHolder viewHolder = null; if(converView == null){ viewHolder = new ViewHolder(); converView = mInflater.inflate(R.layout.item_layout, null); viewHolder.ivIcon =(ImageView) converView.findViewById(R.id.iv_icon); viewHolder.tvTitle = (TextView)converView.findViewById(R.id.tv_title); viewHolder.tvContent = (TextView)converView.findViewById(R.id.tv_content); converView.setTag(viewHolder); }else{ viewHolder = (ViewHolder) converView.getTag(); } viewHolder.ivIcon.setImageResource(R.drawable.ic_launcher); String urlString = mList.get(position).newsIconUrl; viewHolder.ivIcon.setTag(urlString);//身份和URL绑定,是为了解决加载新图片时由于 //缓存机制,先加载旧图片再加载新图片 //new ImageLoader().showImageByThread(viewHolder.ivIcon, //urlString);//使用多线程的方式加载图片 mImageLoader.showImageByAsyncTask(viewHolder.ivIcon, urlString); viewHolder.tvTitle.setText(mList.get(position).newsTitle); viewHolder.tvContent.setText(mList.get(position).newsContent); return converView; } class ViewHolder{ public TextView tvTitle, tvContent; public ImageView ivIcon; } }
package com.example.newsimooc; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.os.AsyncTask; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.widget.ListView; public class MainActivity extends Activity { private ListView mListView; private static String URL = "http://www.imooc.com/api/teacher?type=4&num=34"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (ListView) findViewById(R.id.lv_main); new NewsAsyncTask().execute(URL); } //获取Jason数据并解析到newsbean中,将url对应的Jsong格式数据转化为我们封装的NewsBean对象 private List<NewsBean> getJsonData(String url){ List<NewsBean> newsBeansList = new ArrayList<NewsBean>(); try { String jsonString = readStream(new URL(url).openStream()); //new URL(url).openStream()此句与url.openConnection().getInputStream()相同 //可根据URL直接联网获取网络数据,简单粗暴,返回值类型为InputStream JSONObject jsonObject; NewsBean newsBean; try { jsonObject = new JSONObject(jsonString); //获取数据集中的每个对象,把每个对象都封装到一个NewsBean中 JSONArray jsonArray = jsonObject.getJSONArray("data");//data是数据集的名字,查看捕获到的JSONSTRING字符串的内容就可以看到 for(int i = 0; i <jsonArray.length(); i++){ jsonObject = jsonArray.getJSONObject(i); newsBean = new NewsBean(); newsBean.newsIconUrl = jsonObject.getString("picSmall"); newsBean.newsTitle = jsonObject.getString("name"); newsBean.newsContent = jsonObject.getString("description"); newsBeansList.add(newsBean); } } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return newsBeansList; } private String readStream(InputStream is){ //通过is解析网页返回的数据 InputStreamReader isr; String result = ""; try { String line = ""; isr = new InputStreamReader(is, "utf-8");//字节流转化为字符流 BufferedReader br = new BufferedReader(isr); try { while((line = br.readLine()) != null){ result += line; } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result;//网页数据组成的字符串 } //实现网络的异步访问 class NewsAsyncTask extends AsyncTask<String, Void, List<NewsBean>>{ //返回的是NewsBean的集合 @Override protected List<NewsBean> doInBackground(String... params) { // TODO Auto-generated method stub return getJsonData(params[0]); //传入的参数只有一个,就是URL那个网址 } //将数据设置到listView上 @Override protected void onPostExecute(List<NewsBean> newsBeans) { //doInBackground返回的是一个List // TODO Auto-generated method stub super.onPostExecute(newsBeans); NewsAdapter adapter = new NewsAdapter(MainActivity.this, newsBeans); mListView.setAdapter(adapter); } } }
如何提高效率:
进一步优化:
ListView滑动停止后才加载可见项
ListView滑动时,取消所有加载项也就是滑动时不进行UI绘制
代码有些地方不太懂,这里只贴出源代码:
ListView的异步加载(笔记,多线程和AsyncTask)
标签:
原文地址:http://blog.csdn.net/sr_19930829/article/details/51141172