Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android get sms from inbox, optimized way to read all messages and group them

Hi am implementing a SMS App, now am able to retrieve all messages with their respective contact info like display name, photo uri.. and am displaying them in a custom list where on item click takes you to respective discussion. Here my issues is the time taking to sync all these messages,

  1. I need to optimize this time.
  2. Each time i send a new message in the discussion view and go back to recent chats i need to only update the particular item, not the whole list.

Here's my code:

ReadSMS.java:

public class ReadSMS {

    ArrayList<HashMap<Contact, ArrayList<OneComment>>> recentChats;

    Application _context;

    public ReadSMS(Application context) {
        this._context = context;
        this.recentChats = ((ChatApplication) _context).getChats();
    }

    public ArrayList<HashMap<Contact, ArrayList<OneComment>>> getSMS() {

        // Init
        ArrayList<SmsMsg> smsMsgs = new ArrayList<SmsMsg>();
        TreeSet<Integer> threadIds = new TreeSet<Integer>();

        Uri mSmsinboxQueryUri = Uri.parse("content://sms");
        Cursor cursor = _context.getContentResolver().query(
                mSmsinboxQueryUri,
                new String[] { "_id", "thread_id", "address", "date", "body",
                        "type" }, null, null, null);

        String[] columns = new String[] { "address", "thread_id", "date",
                "body", "type" };
        if (cursor.getCount() > 0) {

            while (cursor.moveToNext()) {

                SmsMsg smsMsg = new SmsMsg();

                String address = null, displayName = null, date = null, msg = null, type = null, threadId = null;
                Uri photoUri = null;

                threadId = cursor.getString(cursor.getColumnIndex(columns[1]));

                type = cursor.getString(cursor.getColumnIndex(columns[4]));

                if (Integer.parseInt(type) == 1 || Integer.parseInt(type) == 2) {

                    address = cursor.getString(cursor
                            .getColumnIndex(columns[0]));

                    if (address.length() > 0) {

                        String[] contactData = getContactByNumber(address);
                        if (contactData != null) {
                            displayName = contactData[0];
                            if (contactData[1] != null)
                                photoUri = Uri.parse(contactData[1]);
                        }
                    } else
                        address = null;

                    date = cursor.getString(cursor.getColumnIndex(columns[2]));
                    msg = cursor.getString(cursor.getColumnIndex(columns[3]));

                    smsMsg.setDisplayName(displayName);
                    smsMsg.setThreadId(threadId);
                    smsMsg.setAddress(address);
                    smsMsg.setPhotoUri(photoUri);
                    smsMsg.setDate(date);
                    smsMsg.setMsg(msg);
                    smsMsg.setType(type);

                    // Log.e("SMS-inbox", "\n\nNAME: " + displayName
                    // + "\nTHREAD_ID: " + threadId + "\nNUMBER: "
                    // + address + "\nPHOTO_URI: " + photoUri + "\nTIME: "
                    // + date + "\nMESSAGE: " + msg + "\nTYPE: " + type);

                    smsMsgs.add(smsMsg);

                    // Add threadId to Tree
                    threadIds.add(Integer.parseInt(threadId));
                }

            }

            for (int threadId : threadIds) {

                HashMap<Contact, ArrayList<OneComment>> oneChat = new HashMap<Contact, ArrayList<OneComment>>();
                Contact con = new Contact();
                ArrayList<OneComment> oneDisc = new ArrayList<OneComment>();

                for (SmsMsg smsMsg : smsMsgs) {

                    if (Integer.parseInt(smsMsg.getThreadId()) == threadId) {

                        con.setContactName(smsMsg.getDisplayName());
                        con.setContactNumber(smsMsg.getAddress());
                        con.setContactPhotoUri(smsMsg.getPhotoUri());

                        if (Integer.parseInt(smsMsg.getType()) == 1)
                            oneDisc.add(0, new OneComment(true,
                                    smsMsg.getMsg(), smsMsg.getDisplayName(),
                                    smsMsg.getDate(), false));
                        else if (Integer.parseInt(smsMsg.getType()) == 2)
                            oneDisc.add(0,
                                    new OneComment(false, smsMsg.getMsg(),
                                            "Me", smsMsg.getDate(), false));

                    }

                }

                oneChat.put(con, oneDisc);
                // add at pos 0
                recentChats.add(0, oneChat);

            }

        }

        return recentChats;
    }

    public String[] getContactByNumber(final String number) {
        String[] data = new String[2];

        try {

            Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
                    Uri.encode(number));

            Cursor cur = _context.getContentResolver().query(uri,
                    new String[] { PhoneLookup.DISPLAY_NAME, PhoneLookup._ID },
                    null, null, null);

            if (cur.moveToFirst()) {
                int nameIdx = cur.getColumnIndex(PhoneLookup.DISPLAY_NAME);
                data[0] = cur.getString(nameIdx);

                String contactId = cur.getString(cur
                        .getColumnIndex(PhoneLookup._ID));

                Uri photoUri = getContactPhotoUri(Long.parseLong(contactId));

                if (photoUri != null)
                    data[1] = photoUri.toString();
                else
                    data[1] = null;

                cur.close();
                return data;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

    public Uri getContactPhotoUri(long contactId) {

        Uri photoUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
                contactId);
        photoUri = Uri.withAppendedPath(photoUri,
                Contacts.Photo.CONTENT_DIRECTORY);
        return photoUri;

    }

}

SmsMsg.java POJO:

public class SmsMsg {

    private String address = null;
    private String displayName = null;
    private String threadId = null;
    private String date = null;
    private String msg = null;
    private String type = null;
    Uri photoUri = null;

    public Uri getPhotoUri() {
        return photoUri;
    }

    public void setPhotoUri(Uri photoUri) {
        this.photoUri = photoUri;
    }

    public String getDisplayName() {
        return displayName;
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getThreadId() {
        return threadId;
    }

    public void setThreadId(String threadId) {
        this.threadId = threadId;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}
like image 969
sukarno Avatar asked Jan 27 '13 08:01

sukarno


2 Answers

POJO storage is not a great approach since those are required to stay in memory all the time, or else be reloaded causing pain and slowness.

In this case, you should create a Service that updates a sqlite database, and present it as a ContentProvider. The sqlite db should only contain the structure that is not provided by Android, i.e. your Contact/Threads hierarchy, and any data you might be displaying in your list, such as the text of the most recent message.

This thread has a discussion of how to detect new SMS Message arrival/sends, whether from your app or another, which is probably what you really want rather than simply detecting that the user posted a message from your own app. The Service should perform this task, the UI Activity only needs to observe the ContentProvider.

Aside: I wonder how the user will send a message to a contact to whom they have not yet sent a message, since your list only contains contacts who they have sent messages to.

like image 157
Brane Avatar answered Nov 15 '22 19:11

Brane


You might need to provide more detail as to how are you actually approaching towards the direction, in particular how many activities you are having (it seems like there are two).

Assuming there are two of them, in First Activity don't try to catch every single message just get all the thread_Ids and addresses.

Then as the user clicks any of the list items then execute other thread to read all the messages belongs to that thread.

use the following:

Uri uriSMSURI = Uri.parse("content://sms/inbox");
Cursor cur = getContentResolver().query(uriSMSURI, null, null, null, null);

for reading inbox and getting thread_Ids and address and store them to some java modal class i.e. DTO

and populate list and as user clicks any of the items pass on the thread_id and then query like this to get all the conversation i.e. thread.

Uri uriSMSURI = Uri.parse(Uri.parse("content://sms/conversations/")+ thread_id);
cursor = getContentResolver().query(uriSMSURI, null,"thread_id=?", new String[] { tid }, null);
like image 26
The VOYOU Avatar answered Nov 15 '22 17:11

The VOYOU