Search code examples
javaandroidlistviewsmsandroid-contentresolver

How to Fetch a List of SMS Conversation/Thread? And Display Name Of Contact in ListView?


I'm Developing an SMS app, I was able to fetch list of SMS but I want to show them as a Conversation, How can I achieve It easily since I'm a beginner.

MyChatFragment.java ;

    public class AwayFragment extends Fragment {
    public AwayFragment() {
    // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                           Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.MyChatFragment, container, false);

    // Inflate the layout for this fragment

    int permissioncheck = ContextCompat.checkSelfPermission(getActivity(), 
    Manifest.permission.READ_SMS);
    ListView lv = (ListView) view.findViewById(R.id.listView2);
    final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;

    ArrayList<String> smsList;
    smsList = new ArrayList<>();


    Uri inboxUri = Uri.parse("content://sms/sent/");
    final String[] projection = new String[]{"*"};
    ContentResolver contentResolver = getActivity().getContentResolver();

    Cursor cursor = contentResolver.query(inboxUri, projection, null, null, null);

    if(permissioncheck == PackageManager.PERMISSION_GRANTED){
        ArrayAdapter<String> lva = new ArrayAdapter<String>(
                getActivity(), android.R.layout.simple_list_item_1, smsList);
        lv.setAdapter(lva);
    } else{
        ActivityCompat.requestPermissions(getActivity(), new String[]{ Manifest.permission.READ_SMS}, 
    PERMISSIONS_REQUEST_READ_CONTACTS);
    }
     final String TAG = FetchingInboxActivity.class.getSimpleName();

     while (cursor.moveToNext()) {

        String number = cursor.getString(cursor.getColumnIndexOrThrow("address")).toString();
        String thread_id = cursor.getString(cursor.getColumnIndexOrThrow("thread_id")).toString();
        String body = cursor.getString(cursor.getColumnIndexOrThrow("body")).toString();
        smsList.add("Number: " + number + "\n" + "Body: " + body + "\n" + "Thread_ID: " + thread_id);
        Log.d(TAG, "showcontacts: ");

        final SwipeRefreshLayout mSwipeRefreshLayout = (SwipeRefreshLayout) 
     view.findViewById(R.id.fragment_away);

        mSwipeRefreshLayout.setOnRefreshListener(
                () -> {
                    ((MainActivity) getActivity()).refreshNow();
                    Toast.makeText(getContext(), "Refresh Layout working", Toast.LENGTH_LONG).show();
                }
        );

    }
    return view;
       }
    }

Also, When I'm trying 'content://sms/conversations/' instead of 'content://sms/' I'm showing errors

    java.lang.IllegalArgumentException: Invalid column *

Solution

  • As I mention in my comment, you should move cursor to the first row, before you'll start to read it. Below code works for me in android 10. I'm using this inside if statement, because cursor may be empty, so method will return false.

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.MyChatFragment, container, false);
    
        // Inflate the layout for this fragment
    
        int permissioncheck = ContextCompat.checkSelfPermission(getActivity(),
                Manifest.permission.READ_SMS);
        ListView lv = (ListView) view.findViewById(R.id.listView2);
        final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;
    
        ArrayList<String> smsList;
        smsList = new ArrayList<>();
    
    
        Uri inboxUri = Uri.parse("content://sms/sent/");
        final String[] projection = new String[]{"*"};
        ContentResolver contentResolver = getActivity().getContentResolver();
    
        Cursor cursor = contentResolver.query(inboxUri, projection, null, null, null);
    
        if(permissioncheck == PackageManager.PERMISSION_GRANTED){
            ArrayAdapter<String> lva = new ArrayAdapter<String>(
                    getActivity(), android.R.layout.simple_list_item_1, smsList);
            lv.setAdapter(lva);
        } else{
            ActivityCompat.requestPermissions(getActivity(), new String[]{ Manifest.permission.READ_SMS},
                    PERMISSIONS_REQUEST_READ_CONTACTS);
        }
        final String TAG = FetchingInboxActivity.class.getSimpleName();
    
        if (cursor.moveToFirst()) {
            while (cursor.moveToNext()) {
    
                String number = cursor.getString(cursor.getColumnIndexOrThrow("address"));
                String thread_id = cursor.getString(cursor.getColumnIndexOrThrow("thread_id"));
                String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
                smsList.add("Number: " + number + "\n" + "Body: " + body + "\n" + "Thread_ID: " + thread_id);
                Log.d(TAG, "showcontacts: ");
    
                final SwipeRefreshLayout mSwipeRefreshLayout = (SwipeRefreshLayout)
                        view.findViewById(R.id.fragment_away);
    
                mSwipeRefreshLayout.setOnRefreshListener(
                        () -> {
                            ((MainActivity) getActivity()).refreshNow();
                            Toast.makeText(getContext(), "Refresh Layout working", Toast.LENGTH_LONG).show();
                        }
                );
    
            }
        }
        return view;
    }
    

    Be carefur, when you use toString() on some data from database, because sometime it may be null, so null to string throw an exception.