Question

I'm having a listview that shows my model items that I filled with the contentprovider (inbox). Now when I'm in my broadcastreceiver and I get an update I would like to let the listview know that he must update his List off models and show it.

I've seen that you can do this with notifyChanged but I can't find a good example.

Can someone help me out on this?

EDIT:

SMSBroadcastReceiver:

            Object[] pdus = (Object[]) bundle.get("pdus");
            final SmsMessage[] messages = new SmsMessage[pdus.length];
            for (int i = 0; i < pdus.length; i++) {
                messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
            }

            if (messages.length < 0) {
                return;
            }

            SmsMessage sms = messages[0];
            String body = "";
            String sender = sms.getOriginatingAddress().toString();
            Long time_rcv = sms.getTimestampMillis();

            try {
                if (messages.length == 1 || sms.isReplace()) {
                    body = sms.getDisplayMessageBody();
                } else {
                    StringBuilder bodyText = new StringBuilder();
                    for (int i = 0; i < messages.length; i++) {
                        bodyText.append(messages[i].getMessageBody());
                    }
                    body = bodyText.toString();
                }
            } catch (Exception e) {

            }

            ContentValues smsValues = new ContentValues();
            smsValues.put("address", sender);
            smsValues.put("body", body);
            smsValues.put("date_sent", time_rcv);
            context.getContentResolver().insert(BlacklistConstants.smsInboxUri, smsValues);

From here I want to the let my fragment know that there is a new sms added. Thats the .insert gives me back.

This is the fragment this function fills my smsList that contains my models.

private void fetchBox(Conversations smsConversation, String thread_id, Uri threadUri) {
    //Cursor smsInThreads = getActivity().getContentResolver().query(threadUri, null, "thread_id = ?", new String[]{thread_id}, null);

    CursorLoader cursorLoader = new CursorLoader(getActivity(), threadUri,
            null, // the columns to retrieve (all)
            "thread_id = ?", // the selection criteria (none)
            new String[]{thread_id}, // the selection args (none)
            null // the sort order (default)
    );

    Cursor smsInThreads = cursorLoader.loadInBackground();

    if (smsInThreads.moveToFirst()) {
        smsConversation.setNumber(smsInThreads.getString(smsInThreads.getColumnIndexOrThrow("address")));
        for (int x = 0; x < smsInThreads.getCount(); x++) {
            smsObjects msg = new smsObjects();
            msg.setBody(smsInThreads.getString(smsInThreads.getColumnIndexOrThrow("body")));
            msg.setNumber(smsInThreads.getString(smsInThreads.getColumnIndexOrThrow("address")));
            msg.setId(smsInThreads.getString(smsInThreads.getColumnIndexOrThrow("_id")));
            msg.setTimeStampReceived(smsInThreads.getString(smsInThreads.getColumnIndexOrThrow("date_sent")));
            smsConversation.addTextMessage(msg);
            smsInThreads.moveToNext();
        }
    }
    //smsList.add(smsConversation);
    smsInThreads.close();
}

And finally this is my custom adapter:

public class ListAdapter extends ArrayAdapter<Conversations> {

private String TAG = ListAdapter.class.getName();

private final Context context;
private final List<Conversations> smsList;

public ListAdapter(Context context, List<Conversations> smsList) {
    super(context, R.layout.sms_inbox, smsList);
    this.context = context;
    this.smsList = smsList;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;

    if(convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.sms_inbox, parent, false);

        holder = new ViewHolder();
        holder.senderNumber = (TextView) convertView.findViewById(R.id.smsNumberText);

        convertView.setTag(holder);
    }
    else
        holder = (ViewHolder) convertView.getTag();

    holder.senderNumber.setText(smsList.get(position).getNumber());

    return convertView;
}

private static class ViewHolder
{
    public TextView senderNumber;
}

@Override
public int getCount() {
    return smsList != null ? smsList.size() : 0;
}

}

Now I don't know how to easy let the fragment know that there is a new insert and that the listview needs to update his model and show it.

I did this in the past like this:

  Uri newSms = context.getContentResolver().insert(BlacklistConstants.smsInboxUri, smsValues);
            Log.d(TAG,newSms.toString());

            Intent smsReceiveIntent = new Intent(BlacklistConstants.smsFilter);
            smsReceiveIntent.putExtra("newSMS",newSms);
            context.sendBroadcast(smsReceiveIntent);

And then on my fragment I listened to that intent and added it to the smsList and then did notifyDataChanged. But I think there is a better way not?

Was it helpful?

Solution

I solved this by starting an intent in the onreceive and then in the main listen to that intent and update the list.

In the onreceive:

          Intent smsReceiveIntent = new Intent(BlacklistConstants.smsFilter);
            smsReceiveIntent.putExtra("newSMS",newSms.toString());
            context.sendBroadcast(smsReceiveIntent);

and in the activity where you can update the listview:

    // Sets up the smsreceiver broadcastreceiver
private void setupSmsReceiver() {
    smsReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, final Intent intent) {

            Log.d(TAG, "onReceive smsReceiver");

            if (getActivity() != null) {
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.d(TAG, "runOnUiThread");
                        String uri = intent.getStringExtra("newSMS");
                        addToList(uri);
                        smsAdapter.notifyDataSetChanged();
                    }
                });
            }
        }
    };
    getActivity().registerReceiver(smsReceiver, new IntentFilter(BlacklistConstants.smsFilter));
}

OTHER TIPS

What I do is to use a ContentObserver in the class that hosts the list, like this (NOTE: this code goes inside a fragment)

    private static final int REFRESH_PAGES = 1;
    private static final int CHANGE_CURRENT_SET = 2;
    private myCustomObserver mContentObserver;


 //utility function to set de observer
// register a un content observer to know that the content has changed
private void registerContentObserver(int myId) {
    Log.v(DEBUG_TAG, "registerContentObserver, myId=" + myId);
    if (mContentObserver != null) {
        getActivity().getContentResolver().unregisterContentObserver(
                mContentObserver);
    }
    mContentObserver = new MyCustomObserver (mHandler);
    getActivity().getContentResolver().registerContentObserver(
            yourUri, true,
            mContentObserver);
}

...... this is the content observer

class MyCustomObserver extends ContentObserver {
    public MyCustomObserver(Handler handler) {
        super(handler);
        Log.v(DEBUG_TAG, "MyCustomObserver");
    }

    @Override
    public void onChange(boolean selfChange) {
        Log.i(DEBUG_TAG, "onChange, selfChange==" + selfChange);
        super.onChange(selfChange);
        Message msg = mHandler.obtainMessage(REFRESH_PAGES);
        mHandler.sendMessage(msg);
    };

    @SuppressLint("NewApi")
    @Override
    public void onChange(boolean selfChange, Uri uri) {
        Log.v(DEBUG_TAG, "onChange, selfChange==" + selfChange + ", uri=="
                + uri.toString());
        final Message msg = mHandler.obtainMessage(REFRESH_PAGES);
        mHandler.sendMessage(msg);
        super.onChange(selfChange, uri);
    }

    @Override
    public boolean deliverSelfNotifications() {
        return true;
    }
}

I also need a handler :

public Handler mHandler = new Handler() {
    @Override
    public void handleMessage(android.os.Message msg) {
        Log.v(DEBUG_TAG, "mHandler");
        if (isAdded()) {//IMPORTANT if you are in a fragment
            switch (msg.what) {
                case REFRESH_PAGES:
                    getLoaderManager().getLoader(0).forceLoad();
                    break;
                case CHANGE_CURRENT_SET:
                    firstTime = true;
                    doYourStaff();
                    break;
            }
        }
    };
};

in the Content Provider you need something like :

                getContext().getContentResolver()
                    .notifyChange(yourUri, null);

e voilà ...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top