异步任务及其Listview优化的种种

activity_main.xml

<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="com.example.asynctask.MainActivity" >

    <ListView
        android:id="@+id/listview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    </ListView>

</RelativeLayout>

item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="4dp" >

    <ImageView
        android:id="@+id/imageview"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:src="@drawable/ic_launcher" />

    <LinearLayout
        android:gravity="center"
        android:paddingLeft="4dp"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <TextView
            android:id="@+id/tv_title"
            android:layout_gravity="center"
            android:text="title"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/tv_content"
            android:layout_gravity="center"
            android:text="content"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

NewsBean

package com.example.asynctask;

import android.widget.ImageView;

public class NewsBean {
	public String title;
	public String content;
	public String imageViewUrl;
	public NewsBean() {
		super();
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getImageViewUrl() {
		return imageViewUrl;
	}
	public void setImageViewUrl(String imageViewUrl) {
		this.imageViewUrl = imageViewUrl;
	}

}

MainActivity

package com.example.asynctask;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
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.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ListView;

public class MainActivity extends Activity {
	private ListView listView;
	private static String httpUrl = "网址";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		listView = (ListView) findViewById(R.id.listview);
		//开始异步任务进行异步加载
		new NewAsyncTask().execute(httpUrl);
	}

	/**
	 * 异步任务--参数为url地址、没有进度、返回对象NewsBean集合
	 */
	class NewAsyncTask extends AsyncTask<String, Void, List<NewsBean>> {

		private List<NewsBean> newBeanlist;

		@Override
		protected List<NewsBean> doInBackground(String... params) {
			//通过http网址,进行获取json字符串获取的操作
			return getJsonData(httpUrl);
		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
		}

		@Override
		protected void onPostExecute(List<NewsBean> result) {
			super.onPostExecute(result);
		}

		@Override
		protected void onProgressUpdate(Void... values) {
			super.onProgressUpdate(values);
			//获取完毕后,进行listview的数据适配操作,进行填充数据操作
			NewAdapter adapter = new NewAdapter(newBeanlist, MainActivity.this,listView);
			listView.setAdapter(adapter);
		}

		/**************************************************************
		 * 通过url地址信息,进行json字符串的获取
		 */
		private List<NewsBean> getJsonData(String url) {
			//最终返回的json数据,解析,分装一个对象集合
			newBeanlist = new ArrayList<NewsBean>();

			/**
			 * 跟这个一样new URL(url).openConnection().getInputStream()
			 */
			try {
				// 返回一个json字符串
				String jsonString = readStream(new URL(url).openStream());
				JSONObject jsonObject = null;
				NewsBean newsBean;
				try {
					// 整体是一个jsonObject
					jsonObject = new JSONObject(jsonString);
					// 键是jsonArray数组
					JSONArray jsonArray = jsonObject.getJSONArray("data");
					// 从jsonArray中循环获取jsonObject
					for (int i = 0; i < jsonArray.length(); i++) {
						jsonObject = jsonArray.getJSONObject(i);
						//创建本地的newsBean对象
						newsBean = new NewsBean();
						//为该对象进行属性值的设置操作
						newsBean.imageViewUrl = jsonObject
								.getString("picSmall");
						newsBean.title = jsonObject.getString("name");
						newsBean.content = jsonObject.getString("description");
						//添加对象,组建集合
						newBeanlist.add(newsBean);

					}
				} catch (JSONException e) {
					e.printStackTrace();
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return newBeanlist;

		}

		/**
		 * 通过流的方式,读取的网络json字符串
		 */
		private String readStream(InputStream inStream) {
			InputStreamReader isr;
			String result = "";
			try {
				String line = "";
				isr = new InputStreamReader(inStream, "utf-8");
				BufferedReader br = new BufferedReader(isr);
				while ((line = br.readLine()) != null) {
					result += line;

				}
			} catch (Exception e) {
			}
			return result;
		}

	}
}

NewAdapter

package com.example.asynctask;
import java.util.List;

import android.R.bool;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class NewAdapter extends BaseAdapter implements OnScrollListener{
	/**
	 * list是数据集合进行设置数据的操作
	 * layoutInflater进行加载itme布局
	 *
	 */
	private List<NewsBean> mList;
	private LayoutInflater layoutInflater;

	private ImageLoader mImageLoader;
	//代表可见的条目的起始位置
	private int mStart;
	private int mEnd;
	//将所有数据的url放到一个数组中,进行管理
	public static String[] urls;
	//代表是不是第一次启动程序--需要进行预加载图片
	private boolean mFirst;
	public NewAdapter(List<NewsBean> mList, Context context,ListView listView) {
		super();
		this.mList = mList;
		this.layoutInflater = layoutInflater.from(context);
		//将数据集合的url单独放到数组中
		urls = new String[mList.size()];
		mImageLoader = new ImageLoader(listView);
		for (int i = 0; i < mList.size(); i++) {
			//遍历获取每个条目的图片url地址信息
			urls[i] = mList.get(i).imageViewUrl;
		}
		//默认是第一次加载
		mFirst = true;
		//注册监听
		listView.setOnScrollListener(this);
	}

	@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 = layoutInflater.inflate(R.layout.item, null);
			viewHolder.title = (TextView) convertView
					.findViewById(R.id.tv_title);
			viewHolder.content = (TextView) convertView
					.findViewById(R.id.tv_content);
			viewHolder.imageView = (ImageView) convertView
					.findViewById(R.id.imageview);
			convertView.setTag(viewHolder);
		} else {
			viewHolder = (ViewHolder) convertView.getTag();
		}
		String imageViewUrl = mList.get(position).imageViewUrl;
		//进行绑定--不会出现图片错位现象
		viewHolder.imageView.setTag(imageViewUrl);
		/**
		 * 进行图片加载的2种方式
		 */
		new ImageLoader().showImageByThread(viewHolder.imageView, mList.get(position).imageViewUrl);
		mImageLoader.showImageByAsyncTask(viewHolder.imageView, imageViewUrl);
		viewHolder.title.setText(mList.get(position).title);
		viewHolder.content.setText(mList.get(position).content);

		return convertView;
	}

	class ViewHolder {
		public TextView title;
		public TextView content;
		public ImageView imageView;
	}

	/**
	 * 状态改变,进行调用,初始化不会被调用
	 */
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		if (scrollState == SCROLL_STATE_IDLE) {
			//停止状态,进行加载图片
			mImageLoader.loadImages(mStart, mEnd);
		}else {
			//停止所有的下载任务
			mImageLoader.cancelAllTasks();
		}
	}

	/**
	 * 滑动过程中调用---第一次加载就可以调用
	 */
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		//获取listview可见的起始项目
		mStart = firstVisibleItem;
		mEnd = firstVisibleItem + visibleItemCount;
		if (mFirst && visibleItemCount>0) {
			//手动加载第一屏
			mImageLoader.loadImages(mStart, mEnd);
			mFirst = false;
		}
	}

}

ImageLoader

package com.example.asynctask;

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;

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.widget.ImageView;
import android.widget.ListView;

public class ImageLoader {
	private ImageView mImageView;
	private String mUrl;
	// 图片缓存算法
	private LruCache<String, Bitmap> mCache;
	private ListView mListView;
	private Set<NewsAsyncTask> mTasks;// ??

	/**
	 * @param listView
	 */
	public ImageLoader(ListView listView) {
		this.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 imageView
	 * @param url
	 */
	public void showImageByAsyncTask(ImageView imageView, String url) {
		// 获取图片时候,先从缓存取出对应的图片
		Bitmap bitmap = getBitmapFromCache(url);
		// 如果缓存中没有,就显示一个默认图片即可
		if (bitmap == null) {
			imageView.setImageResource(R.drawable.ic_launcher);
		} else {
			// 如果有的话,直接设置图片就可以了
			imageView.setImageBitmap(bitmap);
		}
	}

	/**
	 * 添加到缓存中
	 */
	public void addBitmapToCache(String url, Bitmap bitmap) {
		// 如果某个url对应的图片不存在,为null,就直接存放即可
		if (getBitmapFromCache(url) == null) {
			mCache.put(url, bitmap);
		}
	}

	/**
	 * 从缓存中取出图片--通过url获取图片
	 */
	public Bitmap getBitmapFromCache(String url) {
		return mCache.get(url);
	}

	/**
	 * 加载了从start到end的图片的url
	 */
	public void loadImages(int start, int end) {
		for (int i = start; i < end; i++) {
			String url = NewAdapter.urls[i];

			// 获取图片时候,先从缓存取出对应的图片
			Bitmap bitmap = getBitmapFromCache(url);
			// 如果缓存中没有,那么必须去下载
			if (bitmap == null) {
				NewsAsyncTask task = new NewsAsyncTask(url);
				task.execute(url);
				mTasks.add(task);

			} else {
				ImageView imageView = (ImageView) mListView
						.findViewWithTag(url);
				imageView.setImageBitmap(bitmap);
			}
		}
	}

	private class NewsAsyncTask extends AsyncTask<String, Void, Bitmap> {

		private String url;

		public NewsAsyncTask(String url) {
			this.url = url;
		}

		@Override
		protected Bitmap doInBackground(String... params) {
			// 获取图片的url地址
			String url = params[0];
			// 从网络上获取图片
			Bitmap bitmap = getBitmapFromUrl(url);
			// 如果图片不为null
			if (bitmap != null) {
				// 加入到缓存中
				addBitmapToCache(url, bitmap);

			}
			return bitmap;
			// return getBitmapFromUrl(params[0]);
		}

		@Override
		protected void onPostExecute(Bitmap result) {
			super.onPostExecute(result);
			ImageView imageView = (ImageView) mListView.findViewWithTag(url);
			if (imageView != null && result != null) {
				imageView.setImageBitmap(result);

			}
		}
	}

	/**
	 * 取消运行的任务
	 */
	public void cancelAllTasks() {
		if (mTasks != null) {
			for (NewsAsyncTask task : mTasks) {
				task.cancel(false);

			}

		}
	}

	/****************************************************************
	 * 处理handler发送过来的消息--携带bitmap
	 */
	private Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			if (mImageView.getTag().equals(mUrl)) {
				// 处理消息
				mImageView.setImageBitmap((Bitmap) msg.obj);

			}
		};
	};

	public ImageLoader() {
		super();
	}

	/**
	 * @param imageView
	 *            图片视图
	 * @param url
	 *            图片的url地址
	 */
	public void showImageByThread(ImageView imageView, final String url) {
		this.mImageView = imageView;
		this.mUrl = url;
		// 另开线程进行服务器的图片下载
		new Thread() {
			public void run() {
				// 通过url获取图片
				Bitmap bitmap = getBitmapFromUrl(url);
				Message message = Message.obtain();
				message.obj = bitmap;
				// 通过handler发送消息
				handler.sendMessage(message);
			};
		}.start();
	}

	/**
	 * 通过url获取网络图片
	 *
	 * @param urlString
	 * @return
	 */
	public Bitmap getBitmapFromUrl(String urlString) {
		Bitmap bitmap = null;
		InputStream inputStream = null;
		try {
			URL httpUrl = new URL(urlString);
			HttpURLConnection connection = (HttpURLConnection) httpUrl
					.openConnection();
			inputStream = new BufferedInputStream(connection.getInputStream());
			bitmap = BitmapFactory.decodeStream(inputStream);
			connection.disconnect();
			return bitmap;

		} catch (Exception e) {
		} finally {
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return bitmap;

	}

	/**********************************************************
	 *
	 * @param imageView
	 * @param url
	 */

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2025-01-19 22:03:16

异步任务及其Listview优化的种种的相关文章

Android之ListView异步加载网络图片(优化缓存机制)【转】

网上关于这个方面的文章也不少,基本的思路是线程+缓存来解决.下面提出一些优化: 1.采用线程池 2.内存缓存+文件缓存 3.内存缓存中网上很多是采用SoftReference来防止堆溢出,这儿严格限制只能使用最大JVM内存的1/4 4.对下载的图片进行按比例缩放,以减少内存的消耗 具体的代码里面说明.先放上内存缓存类的代码MemoryCache.java: public class MemoryCache { private static final String TAG = "MemoryCa

10熟练掌握listview优化

熟练掌握listview优化,获取网络图片异步加载,分批加载,分页显示,图片缓存等优化方式 ListView的工作原理 首先来了解一下ListView的工作原理(可参见http://mobile.51cto.com/abased-410889.htm),如图: ListView 针对每个item,要求 adapter "返回一个视图" (getView),也就是说ListView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到ListView的长度,然后根据这

listView优化以及内存泄露问题

最经开发app使出现了由于ListView产生的内存泄露问题.我们知道内存泄露时很不好的.意味着,代码写的有点失败,需要做些优化改动. 经过这次的教训,以及在网上找了些资料,总结了一下,关于ListView的优化: listview优化问题: 首先,listview必须严格按照convertView及viewHolder格式书写,这样可以基本保证数据最优. 其次,如果自定义Item中有涉及到图片等等的,一定要做图片优化.bitmap释放可以不做. 第三,尽量避免在BaseAdapter中使用st

listview优化2

ListView优化2: 如果一个listView不做任何的优化,而且有很多的条目,当我们快速的拖动listView的界面的时候,就不断的GCGC(Garbage Collection )垃圾回收,当GC到某个时候就会(OOM)outofmemory内存溢出,应用程序也就会随之挂掉,产生这个问题的原因是什么呢?我们知道listView的特点是每产生一个条目就会调用一次getView方法,如果我们不进行优化,每一次调用都要执行getView方法中的所有语句,而且会在最上面的条目移出界面的时候回收掉

Adaptert Listview 优化

这次是关于Listview的优化的,之前一直采用愚蠢的方式来使用listview,出现的情况就是数据多的话下拉的时候会出现卡顿的情况,内存占用多.所以学习了关于listview的优化,并且这也是普遍使用的方法.我们一般来说创建listview的话更常用的是继承BaseAdapter的方式进行实现,因为这样可以自定义list没一个item的布局,根据程序的需求进行定制,一般来说listview所展示的数据都是比较多的,一般也有比较少的.所以,不对adapter进行优化的话,那么每一次拖动listv

ListView优化-ViewHolder缓存

安卓开发中ListView控件是一个使用频率相当的高级控件,通常用于展示一系列相似度极高的数据,当数据量极大或布局相当复杂时,ListView的性能优化就显得非常重要.所以在开发中不但功能上要满足,而且在性能上也不能马虎.        使用ListView是一个标准的适配器设计模式,ListView把数据.XML布局和Adapter有极地结合在一起完成一系列的展示功能.在ListView的数据展示中,每次滑动ListView都会触发getView()方法的调用,并且XML定义的布局是在也是在适

Android 常驻与很驻型广播的差别,及ListView优化,Android新手基本知识巩固

1.常驻型广播 常驻型广播,当你的应用程序关闭了,假设有广播信息来,你写的广播接收器相同的能接受到. 他的注冊方式就是在你的应用程序中的AndroidManifast.xml进行注冊. 通常说这样的方式是静态注冊 以下是配置样例 2<receiver android:name=".widget.DeskWidgeWeather"> 3<meta-data android:name="android.appwidget.provider" andro

Android MaoZhuaWeiBo Adapter ListView优化及发送微博 - 4

这一篇主要给大家说说Adapter ListView优化及发送微博,我们都知道Android在一些比较耗内存的类里,为了尽量避免浪费内 存,我们需要对我们的组件之类的进行优化,使其节约不必要的资源浪费 自定义适配器: package com.neweriweibo.adapter; /** * 适配器 * @author Engineer-Jsp * @date 2014.10.28 * */ import java.util.ArrayList; import com.neweriweibo.

内存泄露--contentView缓存使用与ListView优化

引起Android内存泄露有很多种原因,下面罗列了一些问题,以后会一一解决 1.构造Adapter时没有使用缓存convertView(衍生出ListView优化问题) 2.查询数据库游标没有关闭 3.Activity中生命周期对象大于Activity生命周期(关于Application Context与Activity Context) 4.Bitmap对象不使用时没有recycle掉(这里还有其他解决方案) 今天说的是第一种:如何使用缓存来优化ListView 因为如果不使用缓存conver