Search code examples
androidandroid-layoutandroid-listviewsimplecursoradapter

Android's simple cursor adapter and multiple row layouts


I've been dabbling with android here and there for the past few months (mostly just tutorials). I've been working on a texting app (for myself) in my free time to learn, and I've succeeded in getting a different layout for each row, but it doesn't work as I'd intended.

Each row is either going to be left or right (left by default), depending on if the number that's in the cursor's position is my phone number or not.

The problem is that my test data looks like this (where the green is my text):

enter image description here

Here's the code for my custom adapter:

public class ConversationMessageListAdapter extends SimpleCursorAdapter {
    private LayoutInflater inflater;
    private String myPhoneNumber;

    public ConversationMessageListAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to, int flags) {
        super(context, layout, cursor, from, to, flags);
        myPhoneNumber = getMyPhoneNumber(context);
        inflater = LayoutInflater.from(context);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        String number = cursor.getString(2);

        System.out.println("phone#: "+number);
        System.out.println("my#: "+myPhoneNumber);

        if(number.equals(myPhoneNumber)){
            View view = inflater.inflate(R.layout.single_message_layout_right, null);
            return view;
        }

        return super.newView(context, cursor, parent);

    }

    public String getMyPhoneNumber(Context context){
        TelephonyManager tMgr = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        return tMgr.getLine1Number();
    }


}

You can see my attempt at debugging the issue by printing out the values of myPhoneNumber and number. It looks like they aren't always matching up correctly with the rows. It'll show the friend's number on the row where it should be mine, yet if I leave the default layout (keep them all to the left) it shows my number on that same row in the textview. Like:

555-555-FRND
Have you played Dynasty Warriors?
555-555-MINE
Not yet. Maybe soon.

But at that point, what get's printed is:

phone#: 555-555-FRND
my# 555-555-MINE
phone#: 555-555-FRND
my# 555-555-MINE

When it should look like:

phone#: 555-555-FRND
my# 555-555-MINE
phone#: 555-555-MINE
my# 555-555-MINE

I'm at a loss for what's causing this.

If it helps, here's my setViewBinder:

textsDbAdapter.setViewBinder(new ConversationMessageListAdapter.ViewBinder() {
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public boolean setViewValue(View view, Cursor cursor, int columnIndex) {

        if(columnIndex == 2){
            String number = cursor.getString(columnIndex);
            String sentBy = getContactName(contentResolver, number);

            if(number.equals(myPhoneNumber)){
                return false;
            }

            TextView sender = (TextView) view;
            sender.setText(sentBy);
            return true;
        }

        //datetime
        if(columnIndex == 5){
            Long messageDatetime = Long.valueOf(cursor.getString(columnIndex));
            String receivedOn;

            if(startOfToday > messageDatetime){
                receivedOn = getDateFromDatetime(messageDatetime);
            } else {
                receivedOn = getTimeFromDatetime(messageDatetime);
            }

            TextView datetime = (TextView) view;
            datetime.setText(receivedOn);
            return true;
        }

        return false;
    }
});

Edit: I've also found out that when I scroll up and then back down, the rows will align randomly.

EDIT2: XML added

single_message_layout_right.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"
    android:paddingLeft="0dp"
    android:paddingRight="5dp"
    android:paddingTop="0dp"
    android:paddingBottom="0dp"
    android:layout_gravity="right"
    tools:context=".ConversationActivity">

    <!--Datetime Received-->
    <TextView
        android:id="@+id/datetime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="bottom"
        android:layout_below="@+id/messageContent"
        android:layout_toLeftOf="@+id/displayPicContainer"
        android:textSize="14sp"
        android:textColor="#9110828f" />

    <!--Message-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/messageContent"
        android:textSize="15sp"
        android:layout_marginTop="5dp"
        android:layout_toLeftOf="@+id/displayPicContainer"/>

    <!--Display picture layout-->
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:padding="3dp"
        android:layout_marginLeft="5dp"
        android:id="@+id/displayPicContainer">

        <!--Display picture-->
        <ImageView
            android:layout_width="45dp"
            android:layout_height="45dp"
            android:src="@drawable/bigboss150x150"
            android:id="@+id/displayPic"/>
    </LinearLayout>

</RelativeLayout>

single_message_layout_left.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"
    android:paddingLeft="0dp"
    android:paddingRight="5dp"
    android:paddingTop="0dp"
    android:paddingBottom="0dp"
    tools:context=".ConversationActivity">

    <!--Display picture layout-->
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="3dp"
        android:layout_marginRight="5dp"
        android:id="@+id/displayPicContainer">

        <!--Display picture-->
        <ImageView
            android:layout_width="45dp"
            android:layout_height="45dp"
            android:src="@drawable/bigboss150x150"
            android:id="@+id/displayPic"/>
    </LinearLayout>

    <!-- sender -->
    <TextView
        android:id="@+id/sender"
        android:textSize="14sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="5dp"
        android:text="NAME"
        android:textColor="#ff9b9aa0"
        android:layout_toRightOf="@+id/displayPicContainer"/>

    <!--Datetime Received-->
    <TextView
        android:id="@+id/datetime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="bottom"
        android:layout_below="@+id/messageContent"
        android:layout_toRightOf="@+id/displayPicContainer"
        android:textSize="14sp"
        android:textColor="#9110828f" />

    <!--Message-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/messageContent"
        android:textSize="15sp"
        android:layout_below="@+id/sender"
        android:layout_toRightOf="@+id/displayPicContainer"/>

</RelativeLayout>

conversation_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/conversationListView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="43dp"
        android:stackFromBottom="true"
        android:transcriptMode="normal">
    </ListView>

    <RelativeLayout
        android:id="@+id/form"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:orientation="vertical"
        android:background="#ffffff">

        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="30dp"
            android:inputType="textCapSentences|textMultiLine"
            android:ems="10"
            android:lines="5"
            android:minLines="1"
            android:hint="Enter message"
            android:id="@+id/newMessageText"
            android:scrollHorizontally="true"
            android:scrollbars="vertical"
            android:layout_alignParentTop="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_toLeftOf="@+id/sendButton"/>

        <Button
            android:layout_width="60dp"
            android:layout_height="wrap_content"
            android:text="Send"
            android:id="@+id/sendButton"
            android:layout_alignBottom="@+id/newMessageText"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true" />
    </RelativeLayout>

</RelativeLayout>

Solution

  • I switched from doing newView to getView and this is working for me.

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    
        View row;
    
        Log.d("RowID", messages.getString(messages.getColumnIndex("_id")));
    
        LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        String fromNumber = messages.getString(messages.getColumnIndex("fromNumber"));
    
        if(fromNumber.equals(myPhoneNumber)){
            row = inflater.inflate(R.layout.single_message_layout_right, parent, false);
        } else {
            row = inflater.inflate(R.layout.single_message_layout_left, parent, false);
            TextView sender = (TextView) row.findViewById(R.id.sender);
            String name = getContactName(fromNumber);
            sender.setText(name);
        }
    
        TextView datetime = (TextView) row.findViewById(R.id.datetime);
        Long messageDatetime = messages.getLong(messages.getColumnIndex("datetime"));
        String receivedOn;
        if(startOfToday > messageDatetime){
            receivedOn = getDateFromDatetime(messageDatetime);
        } else {
            receivedOn = getTimeFromDatetime(messageDatetime);
        }
        datetime.setText(receivedOn);
    
        String message = messages.getString(messages.getColumnIndex("message"));
        TextView messageContent = (TextView) row.findViewById(R.id.messageContent);
        messageContent.setText(message);
    
        return row;
    }