今天刚学了异步加载,说实话懂了还是不少的,也是为了让自己以后复习,就写了这篇,为了让自己以后好找资料哈。
MainActivity类:主要实现获取json数据
package com.example.asynctaskphoto; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.widget.ListView; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.ArrayList; import java.util.List; public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private ListView mListView; private static String URL = "http://www.imooc.com/api/teacher?type=4&num=30"; @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); } /** * 将url对应的JSON数据转化为我们所封装的对象 * * @param url * @return */ private List<NewsBean> getJsonData(String url) { List<NewsBean> newsBeanList = new ArrayList<>(); try { //下面的此语句功能与url.openConnection().getInputStream()相同, // 可根据URL直接联网获取网络数据,返回的类型是InputStream //new URL(url).openStream()通过这个方法来获取到JSON数据 String jsonString = readStream(new URL(url).openStream()); // Log.d(TAG,jsonString); NewsBean newsBean; JSONObject jsonObject = new JSONObject(jsonString); //把获取到的jsonString数据用JSONObject存数 JSONArray jsonArray = jsonObject.getJSONArray("data"); //利用JSONArray数组来存储JSON数据 for (int i = 0; i < jsonArray.length(); i++) { //遍历JSONArry数组中的内容 jsonObject = jsonArray.getJSONObject(i); newsBean = new NewsBean(); newsBean.newsIconUrl = jsonObject.getString("picSmall"); newsBean.newsTitle = jsonObject.getString("name"); newsBean.newsContent = jsonObject.getString("description"); newsBeanList.add(newsBean);//把获取到的newsBean对象添加到newsBeanList中 } } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } return newsBeanList; } /** * 通过InputStream解析网页返回的信息 * * @param is * @return */ private String readStream(InputStream is) { InputStreamReader isr; String result = ""; try { String line; isr = new InputStreamReader(is, "utf-8"); BufferedReader br = new BufferedReader(isr); while ((line = br.readLine()) != null) { result += line; } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return result; } /** * 实现网络的异步访问 */ class NewsAsyncTask extends AsyncTask<String, Void, List<NewsBean>> { //String... params 是一个可变的数组 @Override protected List<NewsBean> doInBackground(String... params) { return getJsonData(params[0]); //因为这个数组中只有一个,取出下标为0的那个数据 } //这个是在后台操作完成后,计算结果将作为参数传递到此方法当中 @Override protected void onPostExecute(List<NewsBean> newsBeans) { super.onPostExecute(newsBeans); NewsAdapter adapter = new NewsAdapter(MainActivity.this, newsBeans, mListView); //为列表项添加获得到的数据 mListView.setAdapter(adapter); } } }NewsBean类
package com.example.asynctaskphoto; /** * Created by ruolan on 2015/10/16. */ public class NewsBean { public String newsIconUrl; public String newsTitle; public String newsContent; }
NewsAdapter类
package com.example.asynctaskphoto; 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.ListView; import android.widget.TextView; import java.util.List; /** * Created by ruolan on 2015/10/16. */ public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener { private List<NewsBean> mList; private LayoutInflater mInflater; private ImageLoader mImageLoader; private boolean mFirstIn; //定义的一个变量,用来在第一次加载的时候,预处理的操作 private int mStart, mEnd; //定义的一个开始和结束的操作 public static String[] URLS; //保存所有图片的地址 public NewsAdapter(Context context, List<NewsBean> data, ListView listView) { mList = data; mInflater = LayoutInflater.from(context); mImageLoader = new ImageLoader(listView); URLS = new String[data.size()]; for (int i = 0; i < data.size(); i++) { URLS[i] = data.get(i).newsIconUrl; //把图片的地址传递给URLS[i] } mFirstIn = true; listView.setOnScrollListener(this);//要绑定,注册这样的一个事件,把listView绑定setOnScrollListener, // 如果不绑定,下面的那两个方法不能执行的onScrollStateChanged(AbsListView view, int scrollState),和onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) } @Override public int getCount() { return mList.size(); } @Override public Object getItem(int position) { return mList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null) { viewHolder = new ViewHolder(); convertView = mInflater.inflate(R.layout.item_layout, null); viewHolder.tvIcon = (ImageView) convertView.findViewById(R.id.tv_icon); viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title); viewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.tvIcon.setImageResource(R.mipmap.ic_launcher); String url = mList.get(position).newsIconUrl; viewHolder.tvIcon.setTag(url); // new ImageLoader().showImageByThread(viewHolder.tvIcon,mList.get(position).newsIconUrl); mImageLoader.showImageByAsyncTask(viewHolder.tvIcon, url); viewHolder.tvTitle.setText(mList.get(position).newsTitle); viewHolder.tvContent.setText(mList.get(position).newsContent); return convertView; } /** * 滑动状态改变的时候调用的 * @param view * @param scrollState */ @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState == SCROLL_STATE_IDLE) { //滑动是否 //加载可见项 mImageLoader.loadImages(mStart, mEnd); } else { //停止任务 mImageLoader.cancelAllTasks(); } } /** * 不滑动的时候调用的 * @param view * @param firstVisibleItem 开始的项 * @param visibleItemCount 结束的项 * @param totalItemCount 列表项的总数 */ @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { mStart = firstVisibleItem; mEnd = firstVisibleItem + visibleItemCount; //当前listview可见的起始项 //为了第一次显示的时候去掉用的 if (mFirstIn && visibleItemCount > 0) { mImageLoader.loadImages(mStart, mEnd); mFirstIn = false; } } class ViewHolder { public TextView tvTitle; public TextView tvContent; public ImageView tvIcon; } }ImageLoader类
package com.example.asynctaskphoto; 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; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashSet; import java.util.Set; /** * Created by ruolan on 2015/10/16. */ public class ImageLoader { private ImageView mImageView; private String mUrl; private ListView mListView; private Set<NewAsyncTask> mTask; //定义一个Set<>集合存放异步操作的集合 //创建Cache private LruCache<String, Bitmap> mCaches; //缓存方法 public ImageLoader(ListView listview) { mListView = listview; mTask = new HashSet<>(); //获取最大可用内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 4; //定义缓存大小是最大可用内存的0.25倍 mCaches = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { //在每次存入缓存的时候调用,获取每张图片的大小。 return value.getByteCount(); } }; } //用来加载从start到end的所有图片 public void loadImages(int start, int end) { for (int i = start; i < end; i++) { String url = NewsAdapter.URLS[i]; //从缓存中取出相应的缓存图片 Bitmap bitmap = getBitmapFromCache(url); if (bitmap == null) { //如果缓存中没有缓存这张图片就会从新加载 NewAsyncTask task = new NewAsyncTask(url); task.execute(url); mTask.add(task); } else { //如果已经缓存了,就直接阿灾 ImageView imageView = (ImageView) mListView.findViewWithTag(url); imageView.setImageBitmap(bitmap); } } } /** * 增加到缓存 * @param url * @param bitmap */ public void addBitmapToCache(String url, Bitmap bitmap) { if (getBitmapFromCache(url) == null) { //判断缓存中否已经缓存过了 mCaches.put(url, bitmap); //如果没有存储过,就通过put(key,value)方法缓存需要存储的数据 } } /** * 从缓存中获取数据 * @param url * @return */ public Bitmap getBitmapFromCache(String url) { return mCaches.get(url); } /** * 以下注释掉的代码,是通过子线程更新UI的操作的原理,异步操作加载图片的。 */ /* private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (mImageView.getTag().equals(mUrl)) { mImageView.setImageBitmap((Bitmap) msg.obj); } } }; *//** * 通过异步线程来实现异步操作 * @param imageView * @param url *//* public void showImageByThread(ImageView imageView, final String url) { mImageView = imageView; mUrl = url; new Thread() { @Override public void run() { super.run(); Bitmap bitmap = getBitmapFromURL(url); Message msg = Message.obtain(); msg.obj = bitmap; mHandler.sendMessage(msg); } }.start(); } */ /** * 获取到Bitmap的url * @param urlString * @return */ 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 (java.io.IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } /** * 通过AsyncTask异步获取图片 * @param imageView * @param url */ public void showImageByAsyncTask(ImageView imageView, String url) { //从缓存中取出相应的缓存图片 Bitmap bitmap = getBitmapFromCache(url); if (bitmap == null) { //如果缓存中没有缓存这张图片就会从新加载 imageView.setImageResource(R.mipmap.ic_launcher); } else { //如果已经缓存了,就直接阿灾 imageView.setImageBitmap(bitmap); } } /** * AsyncTask方法,在这里面实现耗时的下载操作 */ private class NewAsyncTask extends AsyncTask<String, Void, Bitmap> { // private ImageView mImageView; private String mUrl; //身份的判断 //构造方法,传入url public NewAsyncTask(String url) { //mImageView = imageView; mUrl = url; } @Override protected Bitmap doInBackground(String... params) {//下载的任务 //从网络中获取图片 Bitmap bitmap = getBitmapFromURL(params[0]); String url = params[0]; if (bitmap != null) { //下载完毕之后,将不再缓存中的图片加入缓存,从而实现缓存鲜果 addBitmapToCache(url, bitmap); } return bitmap; } //在下载任务完成后,把获取到的bitmap传给imageView @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl); if (imageView != null && bitmap != null) { imageView.setImageBitmap(bitmap); } mTask.remove(this); /*if (mImageView.getTag().equals(mUrl)) { mImageView.setImageBitmap(bitmap); }*/ } } //取消操作 public void cancelAllTasks() { if (mTask != null) { for (NewAsyncTask task : mTask) { task.cancel(false); } } } }
最后就是xml文档:
activity_main:
<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"
tools:context=".MainActivity">
<ListView
android:id="@+id/lv_main"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</RelativeLayout>
item_layout:
<?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:orientation="horizontal"
android:padding="4dp">
<ImageView
android:id="@+id/tv_icon"
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@mipmap/ic_launcher"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:textSize="15sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:maxLines="1"
android:text="Title"/>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:maxLines="3"
android:textSize="10sp"
android:text="Content"/>
</LinearLayout>
</LinearLayout>
上述的这个,是刚开始运行的时候显示的,因为在onScroll()方法中实现了加载图片。
这个图片显示的还是有之前的图片,这也是说明了在第一次滑动的时候,滑动时加载的,不过后面再次运行的时候就不用加载了额,因为有了存储机制。