Thursday 22 September 2011

Smooth List View

Listview is very common in android, and easy to make. But main issue is how can we make it smooth and maintain it's performance. when data may be collection of images and text. Now here is a quite good technique to represent our data in list view.

for example we have to display :



Here we need to display images and text . And data should be downloaded from internet. Now we will create a getter and setter class for image and text. The name should be: DataValues



public  class DataValues{

private String imgURL, text;

public void setData(String imgURL, String text){
this.imgURL = imgURL;
this.text = text;
}

public String getImgURL()
{
return imgURL;
}
public String getText()
{
return text;
}
}


Now, let's create xml layout. row_data_image.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon"/>
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>



Now we will create AsyncImageLoader; This functionality can be done "AsyncTask" but here we are going to use thread and handler.

Note: in the given code we are using "SoftReference" for caching images.

public class AsyncImageLoader {
private HashMap<String, SoftReference<Drawable>> imgCache;
public AsyncImageLoader() {
imgCache = new HashMap<String, SoftReference<Drawable>>();
}
public Drawable loadDrawable(final String imgURL, final ImageCallback imageCallback) {
if (drawableMap.containsKey(imgURL)) {
SoftReference<Drawable> softReference = imgCache.get(imgURL);
Drawable drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}
final Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
imageCallback.imageLoaded((Drawable) message.obj, imgURL);
}
};
new Thread() {
@Override
public void run() {
Drawable drawableImg = loadImageFromUrl(imgURL);
imgCache.put(imgURL, new SoftReference<Drawable>(drawableImg ));
Message message = handler.obtainMessage(0, drawableImg );
handler.sendMessage(message);
}
}.start();
return null;
}

// Download image from internet
public static Drawable loadImageFromUrl(String url) {
InputStream inputStream;
try {
inputStream = new URL(url).openStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
return Drawable.createFromStream(inputStream, "src");
}

public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable, String imgURL);
}



Create ViewWrap class for get ids of views:

public class ViewWrap{
private View mainView;
private TextView textView;
private ImageView imgView;
public ViewCache(View mainView) {
this.mainView = mainView;
}
public TextView getTextView() {
if (textView == null) {
textView = (TextView) mainView.findViewById(R.id.text);
}
return titleView;
}
public ImageView getImageView() {
if (imgView == null) {
imgView = (ImageView) mainView.findViewById(R.id.image);
}
return imgView;
}



Now we will create our Adapter class, MainDataAdapter:
public class MainDataAdapter extends ArrayAdapter<DataValues> {
private ListView lstView;
private AsyncImageLoader asyncImageLoader;
public MainDataAdapter(Activity activity, List<DataValues> dataValues, ListView lstView) {
super(activity, 0, dataValues);
this.lstView = lstView;
asyncImageLoader = new AsyncImageLoader();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Activity activity = (Activity) getContext();
// Inflate the views from XML
View rowView = convertView;
ViewWrap viewWrap;
if (rowView == null) {
LayoutInflater inflater = activity.getLayoutInflater();
rowView = inflater.inflate(R.layout.row_data_image, null);
viewWrap = new ViewWrap(rowView);
rowView.setTag(viewWrap);
} else {
viewWrap = (ViewWrap) rowView.getTag();
}
DataValues dataValues = getItem(position);
// Load the image and set it on the ImageView
String imgURL = dataValues.getImgURL();
ImageView imageView = viewWrap.getImageView();
imageView.setTag(imgURL);
Drawable cacheImages= asyncImageLoader.loadDrawable(imgURL, new ImageCallback() {
public void imageLoaded(Drawable imageDrawable, String imgURL) {
ImageView imageViewByTag = (ImageView) lstView.findViewWithTag(imgURL);
if (imageViewByTag != null) {
imageViewByTag.setImageDrawable(imageDrawable);
}
}
});
imageView.setImageDrawable(cacheImages);
// Set the text on the TextView
TextView textView = viewWrap.getTextView();
textView.setText(dataValues.getText());
return rowView;
}


In this code we tried to reuse rows in list and also caching.
Always keep some points when you are going to any operation that is related to internet first you have to check internet connection before doing this type of opertaion.

there are also many ways for such type of list operation in android. we need to perform according to our requirement.

No comments:

Post a Comment