ListView中图片的加载问题十分突出,因为程序读取图片资源十分耗时,而如果把设置图片放到主线程中的话,在下滑时会感觉到明显的卡顿,用户体验非常之差。
于是我想到设置图片这一步肯定不能不再主线程中进行。必须使用异步加载图片来实现。
PS:程序中所有耗时的工作绝对不能再主线程进行,必须异步。
以下是部分核心代码:
package jiaoml.com.music.adapter;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import jiaoml.com.music.R;
import jiaoml.com.music.music.Mp3Info;
import jiaoml.com.music.utils.MediaUtils;
/**
* Created by 91905 on 2016/8/17 0017.
*/
public class FragmentMusicAdapter extends BaseAdapter {
private Context context;
private ArrayList mp3Infos;
private static final int LOAD_IMAGE = 1;
public FragmentMusicAdapter(Context context) {
this.context = context;
mp3Infos = MediaUtils.getMp3Infos(context);
}
@Override
public int getCount() {
return mp3Infos.size();
}
@Override
public Object getItem(int i) {
return mp3Infos.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder vh;
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.fragment_music_music_item, null);
vh = new ViewHolder();
vh.ablum = (ImageView) view.findViewById(R.id.music_ablum);
vh.title = (TextView) view.findViewById(R.id.music_title);
vh.artist = (TextView) view.findViewById(R.id.music_artist);
view.setTag(vh);
} else {
vh = (ViewHolder) view.getTag();
}
Mp3Info mp3Info = mp3Infos.get(i);
vh.ablum.setImageResource(R.mipmap.music_default);
new ImageLoader().showImageByThread(vh.ablum, mp3Info);
vh.title.setText(mp3Info.getTitle());
vh.artist.setText(mp3Info.getArtist());
return view;
}
class ViewHolder {
ImageView ablum;
TextView title;
TextView artist;
}
/**
* 异步加载图片
*/
class ImageLoader {
private ImageView imageView;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
imageView.setImageBitmap((Bitmap) msg.obj);
}
};
/**
* 使用多线程实现异步加载
* @param imageView
* @param mp3Info
*/
public void showImageByThread(ImageView imageView, final Mp3Info mp3Info) {
this.imageView = imageView;
new Thread() {
@Override
public void run() {
super.run();
Message message = Message.obtain();
Bitmap bitmap = getBitmap(mp3Info);
message.obj = bitmap;
handler.sendMessage(message);
}
}.start();
}
public Bitmap getBitmap(Mp3Info mp3Info) {
return MediaUtils.getArtwork(context, mp3Info.getId(), mp3Info.getAlbumId(), true, true);
}
}
}
这样虽然完成了异步加载,但同时出现了一个十分严重的问题,我将getBitmap方法改为如下形式,以模拟加载延迟:
package jiaoml.com.music.adapter;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import jiaoml.com.music.R;
import jiaoml.com.music.music.Mp3Info;
import jiaoml.com.music.utils.MediaUtils;
/**
* Created by 91905 on 2016/8/17 0017.
*/
public class FragmentMusicAdapter extends BaseAdapter {
private Context context;
private ArrayList mp3Infos;
private static final int LOAD_IMAGE = 1;
public FragmentMusicAdapter(Context context) {
this.context = context;
mp3Infos = MediaUtils.getMp3Infos(context);
}
@Override
public int getCount() {
return mp3Infos.size();
}
@Override
public Object getItem(int i) {
return mp3Infos.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder vh;
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.fragment_music_music_item, null);
vh = new ViewHolder();
vh.ablum = (ImageView) view.findViewById(R.id.music_ablum);
vh.title = (TextView) view.findViewById(R.id.music_title);
vh.artist = (TextView) view.findViewById(R.id.music_artist);
view.setTag(vh);
} else {
vh = (ViewHolder) view.getTag();
}
Mp3Info mp3Info = mp3Infos.get(i);
vh.ablum.setImageResource(R.mipmap.music_default);
vh.ablum.setTag(mp3Info);
new ImageLoader().showImageByThread(vh.ablum, mp3Info);
vh.title.setText(mp3Info.getTitle());
vh.artist.setText(mp3Info.getArtist());
return view;
}
class ViewHolder {
ImageView ablum;
TextView title;
TextView artist;
}
/**
* 异步加载图片
*/
class ImageLoader {
private ImageView imageView;
private Mp3Info mp3Info;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (imageView.getTag() == mp3Info) {
imageView.setImageBitmap((Bitmap) msg.obj);
}
}
};
/**
* 使用多线程实现异步加载
* @param imageView
* @param mp3Info
*/
public void showImageByThread(ImageView imageView, final Mp3Info mp3Info) {
this.imageView = imageView;
this.mp3Info = mp3Info;
new Thread() {
@Override
public void run() {
super.run();
Message message = Message.obtain();
Bitmap bitmap = getBitmap(mp3Info);
message.obj = bitmap;
handler.sendMessage(message);
}
}.start();
}
public Bitmap getBitmap(Mp3Info mp3Info) {
return MediaUtils.getArtwork(context, mp3Info.getId(), mp3Info.getAlbumId(), true, true);
}
}
}
以上我通过给ImageView设置Tag为mp3Info,并传递给加载图片的函数,当设置图片时判断mp3Info和ImageView标记的是否相同,相同则设置,不相同则不设置.
这样一来就完美的解决了ListView加载图片卡顿的问题,同时也解决了图片异步加载错乱的问题。