0

I am using a ListView with CursorAdapter to display some information. Depending on the information type the row is different but in reality some items are right and some left.

Here is my Activity

package ;

import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.provider.ContactsContract.PhoneLookup;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.telephony.PhoneNumberUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.QuickContactBadge;

public class ConversationActivity extends BaseActivity implements
        OnClickListener, LoaderManager.LoaderCallbacks<Cursor> {
    private static final String TAG = ConversationActivity.class
            .getSimpleName();
    Cursor cursor; // 1
    ListView conversationList; // 2
    Button sendButton;
    EditText newMessageText;
    QuickContactBadge badge;
    static String ID;


    ConversationReceiver conversationReceiver = new ConversationReceiver();

    private static final int LOADER_ID = 0x02;
    private ConversationAdapter adapter;

    @SuppressLint("NewApi")
    @Override
    protected void onStart() {
        super.onStart();
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
            ActionBar actionBar = getActionBar();
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

    }

    @SuppressLint("NewApi")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.conversation);

        getSupportLoaderManager().initLoader(LOADER_ID, null, this);

        // Die Views suchen
        conversationList = (ListView) findViewById(R.id.ConversationList);
        sendButton = (Button) findViewById(R.id.Conv_buttonSendMessage);
        newMessageText = (EditText) findViewById(R.id.Conv_newMessageText);

        Intent intent = getIntent();
        ID = intent.getStringExtra("ID");

        sendButton.setOnClickListener(this);



        try {
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
                Log.d(TAG, "Erstelle ActionBar fuer ID: " + ID);

                String[] projection = new String[] {
                        ContactsContract.PhoneLookup.DISPLAY_NAME,
                        ContactsContract.PhoneLookup.PHOTO_THUMBNAIL_URI };

                ContentResolver resolver = getContentResolver();
                String[] br_projection = new String[] { BaseColumns._ID,
                        "conv_type", "address", "Profile_ID" };
                Cursor ConvCursor = resolver
                        .query(Uri
                                .parse("content://.../conversations"),
                                br_projection, BaseColumns._ID + " = ?",
                                new String[] { ID }, null);
                ActionBar actionBar = getActionBar();

                if (ConvCursor.moveToFirst()) {
                    String number = "";

                    number = ConvCursor.getString(ConvCursor
                            .getColumnIndexOrThrow("address"));

                    Log.v(TAG, "Nummer: " + number);
                    Uri contactUri = Uri.withAppendedPath(
                            PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

                    Cursor contactCursor = getContentResolver().query(
                            contactUri, projection, null, null, null);
                    Log.v(TAG, "contactCursor.moveToFirst");
                    if (contactCursor.moveToFirst()) {

                        // Get values from contacts database:
                        String ContactName = contactCursor
                                .getString(contactCursor
                                        .getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));

                        String ContactThumbnailString = contactCursor
                                .getString(contactCursor
                                        .getColumnIndex(ContactsContract.PhoneLookup.PHOTO_THUMBNAIL_URI));

                        ImageView logo = (ImageView) findViewById(android.R.id.home);

                        if (ContactThumbnailString != null) {
                            Uri ContactThumbnailURI = Uri
                                    .parse(ContactThumbnailString);
                            logo.setImageURI(ContactThumbnailURI);
                        }

                        actionBar.setTitle(ContactName);

                    } else {

                        actionBar.setTitle(R.string.ContactNoName);
                    }
                    actionBar
                            .setSubtitle(PhoneNumberUtils.formatNumber(number));
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "ConvAct Header Info ", e);
        }

        adapter = new ConversationAdapter(this, cursor);
        conversationList.setAdapter(adapter);

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume");


    }

    @Override
    protected void onPause() {
        super.onPause();

        unregisterReceiver(conversationReceiver);
    }

    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
        String[] projection = new String[] { BaseColumns._ID, "item_type",
                "send", "serverid", "direction", "date", "content", "sender",
                "Conv_ID" };
        Intent intent = getIntent();

        return new CursorLoader(
                this,
                Uri.parse("content://.../items"),
                projection, "Conv_ID = ?", new String[] { intent
                        .getStringExtra("ID") }, "date ASC");
    }

    @SuppressLint("NewApi")
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        adapter.swapCursor(cursor);
    }

    @SuppressLint("NewApi")
    public void onLoaderReset(Loader<Cursor> cursorLoader) {
        adapter.swapCursor(null);
    }

    // Wird bei Klicks auf den Button aufgerufen //
    public void onClick(View v) {
        Log.d(TAG, "Neues Item fuer ID: "+ID);


        ContentResolver resolver = getContentResolver();
        Cursor convCursor = resolver
                .query(Uri
                        .parse("content://.../conversations/"
                                + ID), new String[] { "address" }, null, null,
                        null);

        convCursor.moveToFirst();

        ContentValues values = new ContentValues();
        values.clear();
        values.put("item_type", "tm");
        values.put("direction", "out");
        values.put("send", "0");
        values.put("date", String.valueOf(System.currentTimeMillis()));
        values.put("content", newMessageText.getText().toString());
        values.put("sender",
                convCursor.getString(convCursor.getColumnIndex("address")));
        values.put("Conv_ID", ID);
        resolver.insert(Uri
                .parse("content://.../items"),
                values);




        newMessageText.setText("");

    }

}

Here is a part of my CursorAdapter

package ;

import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.ContactsContract;
import android.provider.ContactsContract.PhoneLookup;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.QuickContactBadge;
import android.widget.TextView;

public class ConversationAdapter extends CursorAdapter {
    private static final String TAG = ConversationAdapter.class.getSimpleName();

    @SuppressWarnings("deprecation")
    public ConversationAdapter(Context context, Cursor c) {
        super(context, c);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        LayoutInflater inflater = LayoutInflater.from(context);
        String item_direction = cursor.getString(cursor
                .getColumnIndexOrThrow("direction"));
        View v = null;

        if (item_direction.equals("out")) {
            v = inflater.inflate(R.layout.conversationrow_out, parent, false);

        } else if (item_direction.equals("in")) {
            v = inflater.inflate(R.layout.conversationrow_in, parent, false);

        }

        bindView(v, context, cursor);

        return v;

    }

    @SuppressLint({ "InlinedApi", "NewApi" })
    @Override
    public void bindView(View row, Context context, Cursor cursor) {
        String item_type = cursor.getString(cursor
                .getColumnIndexOrThrow("item_type"));
        Log.v(TAG, item_type);
        Cursor contactCursor = null;

        try {
            TextView ConversationText = (TextView) row
                    .findViewById(R.id.ConversationText);

            Log.v(TAG, "message selected");
            // Definition
            String[] projection;
            String number, textContent = "";
            Uri ThumbnailURI = null;
            String ThumbnailString;

            QuickContactBadge ConversationBadge = null;

            Log.d(TAG,
                    "Nachricht mit Inhalt: "
                            + cursor.getString(cursor
                                    .getColumnIndexOrThrow("content"))
                            + " in Richtung: "
                            + cursor.getString(cursor
                                    .getColumnIndexOrThrow("direction")));

            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
                projection = new String[] {
                        ContactsContract.PhoneLookup.DISPLAY_NAME,
                        ContactsContract.PhoneLookup.PHOTO_THUMBNAIL_URI };

                ConversationBadge = (QuickContactBadge) row
                        .findViewById(R.id.ConversationBadge);
            } else {
                projection = new String[] { ContactsContract.PhoneLookup.DISPLAY_NAME };
            }

            Log.v(TAG, "Lese nun Nutzerdaten");
            number = cursor.getString(cursor.getColumnIndexOrThrow("sender"));
            Uri contactUri = Uri.withAppendedPath(
                    PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

            Log.v(TAG, "Nutzerdaten-Query");

            contactCursor = context.getContentResolver().query(contactUri,
                    projection, null, null, null);

            if (contactCursor.moveToFirst()) {

                String name = contactCursor
                        .getString(contactCursor
                                .getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));

                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
                    ConversationBadge.assignContactFromPhone(number, true);

                    ThumbnailString = contactCursor
                            .getString(contactCursor
                                    .getColumnIndex(ContactsContract.PhoneLookup.PHOTO_THUMBNAIL_URI));

                    if (cursor.getString(
                            cursor.getColumnIndexOrThrow("direction")).equals(
                            "in")
                            && ThumbnailString != null) {
                        ThumbnailURI = Uri.parse(ThumbnailString);
                        ConversationBadge.setImageURI(ThumbnailURI);
                    } else {
                        ConversationBadge.setImageToDefault();
                    }
                }

                // textContent = name+": ";

            } else {
                // textContent = number+": ";

                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {

                    ConversationBadge.setImageToDefault();
                }

            }

            if (item_type.equals("tm")) {
                textContent += (cursor.getString(cursor
                        .getColumnIndexOrThrow("content")));

            }

            ConversationText.setText(textContent);

            TextView ConversationTime = (TextView) row
                    .findViewById(R.id.ConversationTime);

            long timestamp = cursor.getLong(cursor.getColumnIndex("date"));

            ConversationTime.setText(DateUtils
                    .getRelativeTimeSpanString(timestamp));

        } catch (Exception e) {
            Log.e(TAG, "bindView ", e);
        } finally {
            contactCursor.close();
        }
    }

}

When I open the Activity everything looks fine. Incomming messages appear left-adjusted and outgoing ones are right-adjusted (basicly). When I have a new message i call the above code to requery and update the list. The Content of the new item now appears on the bvottom as I like it but the layout of this last item seems to be the one of the intitial last. The layout for this new item appears on the top.

I would like to post images but I don't have enought reputation points. :(

Thanks

k.j.
  • 39
  • 1
  • 8
  • please show your adapter's code – Rotem May 20 '13 at 12:36
  • I hope I have added the interesting code – k.j. May 20 '13 at 13:56
  • is the problem with the layout of the items or their order? – Rotem May 20 '13 at 13:59
  • The data arrives to the adapter in the order you fetch it from the db. Maybe your SQL query sets a certain "order by"? btw your "else if" and "else" are the same so you can delete the "else if" – Rotem May 20 '13 at 17:26
  • I could imagine that notifyDataSetChanged() says that the amount of rows are the same but the content has been changed. But I want to say that there is a new row. – k.j. May 20 '13 at 18:19
  • notifyDataSetChanged() doesn't say that the amount of rows is the same. do you override the getCount function of the adapter? – Rotem May 20 '13 at 22:46
  • I now have rewritten my code to use an `ContentProvider` and an `CursorLoader` but the Problem is still there. I have changed my Post and added the full source. First I thougt it might be too much but maybe its better to find the bug. – k.j. May 22 '13 at 19:55
  • Remove the `bindView()` call from `newView()`. What you see it's normal as you're assuming that `newView()` is called for the new row but the ListView could allready have a recycled row to give you(and it doesn't know about your two types). Implement the `getViewTypeCount()` and `getItemViewType()` methods. – user May 22 '13 at 20:58
  • Thank you very mutch Luksprog for your answer. It helped me finding the right way. At the end I did what was talked about in http://stackoverflow.com/questions/8479833/cursoradapter-with-different-row-layouts – k.j. May 22 '13 at 22:59

0 Answers0