0

I want to create a listview with image and text that is sortable. I'm done creating the custom listview with image and text. Note that the values of the texts come from my database. Also I'm done with sorting the text but I can't sort the position of image.

Can you give me some considerations to achieve the sorting of both text and image? So far this is what I have tried:

 static int[] imgs = {
        R.drawable.dinaretreat, // 0
        R.drawable.cobterrace, // 1
        R.drawable.ventassostreet, // 2
        R.drawable.summerhillblvddrouin, // 3
        R.drawable.todmanstreetdrouin
};
String[] text, loc, price;

private DBHelper dbHelper;

MyCustomAdapter adapter;

 // TODO displayRecords
private void displayRecords() {

    checkDatabaseConnection();

    text = dbHelper.getAll();
    price = dbHelper.getAllPrices();
    loc = dbHelper.getAllLocations();

    adapter = new MyCustomAdapter(imgs, text, loc, price);

    lv.setAdapter(adapter);

}

class MyCustomAdapter extends BaseAdapter
{
    String[] data_tvName;
    String[] data_tvLocation;
    String[] data_tvPrice;
    int[] data_image;

MyCustomAdapter() {
    data_tvName = null;
    data_tvLocation = null;
    data_tvPrice = null;
    data_image = null;
}

MyCustomAdapter(int[] image, String[] house, String[] location, String[] price) {
    data_tvName = house;
    data_tvLocation = location;
    data_tvPrice = price;
    data_image = image;
}

public int getCount() {
    return data_tvName.length;
}

public String getItem(int position) {
    return null;
}

public long getItemId(int position) {
    return position;
}

public View getView(int position, View convertView, ViewGroup parent) {

    LayoutInflater inflater = getLayoutInflater();
    View row;

    row = inflater.inflate(R.layout.listrow, null);

    textview1 = (TextView) row.findViewById(R.id.tvName);
    textview2 = (TextView) row.findViewById(R.id.tvLocation);
    textview3 = (TextView) row.findViewById(R.id.tvPrice);
    ImageView imageview = (ImageView) row.findViewById(R.id.image);

    imageview.setScaleType(ImageView.ScaleType.FIT_XY);
    textview1.setText(data_tvName[position]);
    Spanned strFormattedLocation = Html.fromHtml("<b>Location: </b>");
    Spanned strFormattedPrice = Html.fromHtml("<b>Price: </b>");
    textview2.setText(strFormattedLocation + data_tvLocation[position]);
    String strPrice = strFormattedPrice + "$" + (new DecimalFormat("#,###.00")).format(Integer.parseInt(data_tvPrice[position])) ;
    textview3.setText(strPrice);
    imageview.setImageResource(data_image[position]);

    return (row);

    }
}

DBHelper.class

 public String[] sortLocationAsc(){
            Cursor localCursor =  
                   this.myDataBase.query(DB_TABLE, new String[] { 
                       KEY_ID, KEY_HOUSE, KEY_PRICE, KEY_LOCATION }, 
                       null, null, null, null, 
                      KEY_LOCATION + " ASC");
            String[] array = new String[localCursor.getCount()];
            int i = 0;
            while(localCursor.moveToNext()){
                String uname = localCursor.getString(localCursor.getColumnIndex(DBHelper.KEY_LOCATION));
                array[i] = uname;
                i++;
            }
            return array;
        }

I don't know what's wrong with this or have I forgotten something. Your help is much appreciated. Thanks a lot.

4
  • What do you mean exactly? What are you trying to achieve? Do you want to be able to sort a list, by either text or image (text) or both, or? It's a bit unclear... Commented Jan 3, 2014 at 12:38
  • Yes I want both text and image to be sorted. But what I have so far done successfully is the text being sorted excluded the image. Commented Jan 3, 2014 at 12:40
  • Ok, I suppose you should create a custom object to hold the different items for each row. So your custom object should hold an int image, String house, String location, String price. I'll try to write an answer a little later today, to illustrate how you can do it. Commented Jan 3, 2014 at 13:45
  • Added an answer now... hope it helps :-) Commented Jan 3, 2014 at 14:51

1 Answer 1

1

Ok, here are an example of how to achieve your goal.

The best way is to create a custom object to hold the different strings and the image for each row.

This object could look like this:

public class MyCustomObject {
    private int image;
    private String house;
    private String location;
    private String price;

    public MyCustomObject(int image, String house, String location, String price) {
        this.image = image;
        this.house = house;
        this.location = location;
        this.price = price;
    }

    public int getImage() {
        return image;
    }

    public String getHouse() {
        return house;
    }

    public String getLocation() {
        return location;
    }

    public String getPrice() {
        return price;
    }
}

Now to the DBHelper class. Instead of fetching one String[] for each type, you should fetch a List of MyCustomObjects. I choose List instead of arrays because these are easier to handle and should (in most cases) be used instead of the more primitive array. :-)

The DBHelper.sortLocationAsc() is renamed to getAllMyCustomObjects() instead and could look something like this:

public List<MyCustomObject> getAllMyCustomObjects() {
    Cursor localCursor = this.myDataBase.query(DB_TABLE, new String[] {
            KEY_ID, KEY_HOUSE, KEY_PRICE, KEY_LOCATION }, null, null,
            null, null, KEY_LOCATION + " ASC");

    String house = "";
    String price = "";
    String location = "";
    int image = 0;

    List<MyCustomObject> listOfObjects = new ArrayList<MyCustomObject>();
    while (localCursor.moveToNext()) {
        house = localCursor.getString(localCursor.getColumnIndex(DBHelper.KEY_HOUSAE));
        price = localCursor.getString(localCursor.getColumnIndex(DBHelper.KEY_PRICE));
        location = localCursor.getString(localCursor.getColumnIndex(DBHelper.KEY_LOCATION));
        image = localCursor.getInt(localCursor.getColumnIndex(DBHelper.KEY_IMAGE));

        listOfObjects.add(new MyCustomObject(image, house, location, price));
    }
    return listOfObjects;
}

Now when creating your custom Adapter I've changed it a bit, so it only takes a List of MyCustomObjects instead of the arrays.

You'll notice in the getView method that I fetch one item from the List of MyCustomObjects instead of fetching from each different array. This way it's much easier to control what elements belong together and you won't get weird behaviours like you could get if the different arrays aren't the same length.

The new MyCustomAdapter could look something like this:

class MyCustomAdapter extends BaseAdapter {
    List<MyCustomObject> myListOfCustomObjects;

    MyCustomAdapter(List<MyCustomObject> customObjects) {
        this.myListOfCustomObjects = customObjects;
    }

    public int getCount() {
        return myListOfCustomObjects.size();
    }

    public String getItem(int position) {
        return null;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = getLayoutInflater();
        View row;

        row = inflater.inflate(R.layout.listrow, null);

        textview1 = (TextView) row.findViewById(R.id.tvName);
        textview2 = (TextView) row.findViewById(R.id.tvLocation);
        textview3 = (TextView) row.findViewById(R.id.tvPrice);
        ImageView imageview = (ImageView) row.findViewById(R.id.image);

        imageview.setScaleType(ImageView.ScaleType.FIT_XY);
        textview1.setText(myListOfCustomObjects.get(position).getHouse());
        Spanned strFormattedLocation = Html.fromHtml("<b>Location: </b>");
        Spanned strFormattedPrice = Html.fromHtml("<b>Price: </b>");
        textview2.setText(strFormattedLocation + myListOfCustomObjects.get(position).getLocation());
        String strPrice = strFormattedPrice
            + "$"
            + (new DecimalFormat("#,###.00")).format(Integer.parseInt(myListOfCustomObjects.get(position).getPrice()));
        textview3.setText(strPrice);
        imageview.setImageResource(myListOfCustomObjects.get(position).getImage());

        return row;
    }
}

And then you'll set the adapter in your displayRecords() like this:

private void displayRecords() {
    checkDatabaseConnection();
    List<MyCustomObject> list = dbHelper.getAllMyCustomObjects();
    adapter = new MyCustomAdapter(list);
    lv.setAdapter(adapter);
}

So the key is to create a custom object to hold the data.

The above code might not run/compile - I've just written it inside a text-editor and didn't test it at all, but now you hopefully have a clear view of how the issue can be solved :-)

Also: if you have a lot of data in your database, I'd recommend you looked into populating the ListView inside a background thread - for instance you could use an [AsycnTask][1] to do this.

Also have a look at the ViewHolder pattern when calling the getView of the Adapter.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.