Search code examples
androidsqliteandroid-cursoradapterandroid-cursorloader

Android - CursorAdapter doesn't work


I have a ChatActivity, which loads its data via a CursorLoader. The CursorLoader return a cursor with two registers, but the newView and bindView methods in adapter is never called.

My activity

public class ChatActivity extends BaseActivity implements LoaderManager.LoaderCallbacks<Cursor> {

    public static final String EXTRA_AMANTEID = "amanteId";

    private EditText messageET;
    private ListView messagesContainer;
    private Button sendBtn;
    private ChatAdapter adapter;
    private Long amanteId;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);

        amanteId = getIntent().getLongExtra(ChatActivity.EXTRA_AMANTEID, 0L);

        messagesContainer = (ListView) findViewById(R.id.messagesContainer);
        messageET = (EditText) findViewById(R.id.messageEdit);
        sendBtn = (Button) findViewById(R.id.chatSendButton);

        RelativeLayout container = (RelativeLayout) findViewById(R.id.container);

        adapter = new ChatAdapter(this);
        getLoaderManager().initLoader(0, null, this);
        messagesContainer.setAdapter(adapter);
    }

    private void scroll() {
        messagesContainer.setSelection(messagesContainer.getCount() - 1);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
        return new CursorLoader(ChatActivity.this, MensagemProvider.CONTENT_URI_CONVERSA, null, null, new String[]{Long.toString(amanteId), Long.toString(amanteId)}, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        adapter.swapCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        adapter.swapCursor(null);
    }
}

My adapter

public class ChatAdapter extends CursorAdapter {

    private Cursor cursor;
    private int dataEnvioColumnIndex;
    private int idMensagemColumnIndex;
    private int idRemetenteColumnIndex;
    private int idDestinatarioColumnIndex;
    private int apelidoRemetenteColumnIndex;
    private int apelidoDestinatarioColumnIndex;
    private int textoMensagemColumnIndex;
    private long idColaboradorLogado;

    public ChatAdapter(Context context) {
        super(context, null, false);
    }

    public ChatMessage getItem() {
        ChatMessage message = new ChatMessage();
        SimpleDateFormat dt = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        Date dataEnvio = new Date(cursor.getLong(dataEnvioColumnIndex));
        message.setDate(dt.format(dataEnvio));
        message.setId(cursor.getLong(idMensagemColumnIndex));
        Long de = cursor.getLong(idRemetenteColumnIndex);
        Long logado = BaseApp.getCredentials().getId();
        message.setMe(de.equals(logado));
        message.setMessage(cursor.getString(textoMensagemColumnIndex));
        return message;
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View retView = vi.inflate(R.layout.list_item_chat_message, null);
        return retView;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        ViewHolder holder = createViewHolder(view);;
        view.setTag(holder);
        ChatMessage chatMessage = getItem();
        boolean myMsg = chatMessage.getIsme() ;//Just a dummy check
        holder.txtMessage.setText(chatMessage.getMessage());
        holder.txtInfo.setText(chatMessage.getDate());
    }

    private ViewHolder createViewHolder(View v) {
        ViewHolder holder = new ViewHolder();
        holder.txtMessage = (TextView) v.findViewById(R.id.txtMessage);
        holder.content = (LinearLayout) v.findViewById(R.id.content);
        holder.contentWithBG = (LinearLayout) v.findViewById(R.id.contentWithBackground);
        holder.txtInfo = (TextView) v.findViewById(R.id.txtInfo);
        return holder;
    }


    private static class ViewHolder {
        public TextView txtMessage;
        public TextView txtInfo;
        public LinearLayout content;
        public LinearLayout contentWithBG;
    }

    @Override
    public Cursor swapCursor(Cursor cursor) {
        if(cursor!=null) {
            cursor.moveToFirst();
            idMensagemColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_MENSAGEMID);
            idRemetenteColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_DE);
            idDestinatarioColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_PARA);
            apelidoRemetenteColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_APELIDO_REMETENTE);
            apelidoDestinatarioColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_APELIDO_DESTINATARIO);
            textoMensagemColumnIndex = cursor.getColumnIndex(MensagemProvider.COLUMN_MENSAGEM);
        }
        notifyDataSetChanged();

        return cursor;
    }
}

what I'm doing wrong ? Can anybody help me ? Thanks!


Solution

  • Overriding swapCursor() is asking for trouble. The cursor won't be positioned where the adapter expects it to be positioned (before first). And you don't call super.swapCursor() so the adapter never really hears about the new cursor.

    I bet you're trying to "optimize" by getting the column indexes only once each time a new cursor is swapped.

    First just try getting rid of the swapCursor() override and making the getColumnIndex() calls in your getItem() method. If that works and you still really want to have getColumnIndex() called only once per cursor, you could try something like setting all your cursor indexes to -1 when you swap the cursor, then calling getColumnIndex() inside getItem() only when the index is -1.

    But don't mess with swapCursor(), especially without calling super.swapCursor() and returning its result.