0

How do I refresh my cursor from another activity?

In my main activity I start a cursor to query phone contacts and display in a listview.

In this main activity I also have a menu, 'Add new Contact', which starts the add new contact activity. A new contact gets added correctly (I can see it in other Contacts apps on my phone), but it is not visible in my listview when the user goes back to main activity.

Is there a way to refresh the cursor from 'add new contact' activity, so the user can see it in the listview when they go back to main activity?

I use AsyncTask in my main activity, if that's any useful info. I read about swapcursor and changecursor but it didn't work when I tried to use them. Here's my 'add new contact' code :

(I call changecursor before the "Contact Saved" toast, but I'm sure it's not done correctly.

package com.example.chris.contactlistcustomlistview;

import android.content.ContentProviderOperation;
import android.content.OperationApplicationException;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import java.util.ArrayList;

/**
 * Created by Chris on 06/05/2016.
 */
public class AddContact extends AppCompatActivity {

    EditText nameofcontact;
    EditText numberofcontact;
    public String contactname;
    public String contactnumber;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.addcontact);


        nameofcontact = (EditText) findViewById(R.id.edittextname);
        numberofcontact = (EditText) findViewById(R.id.edittextnumber);


    }

    public void createButton(View view) {
        contactname = nameofcontact.getText().toString();
        contactnumber = numberofcontact.getText().toString();

        if (contactname.length() == 0) {

            Toast.makeText(this, "Please enter a name",
                    Toast.LENGTH_LONG).show();
            return;
        }

        ArrayList<ContentProviderOperation> contentProviderOperations = new ArrayList<ContentProviderOperation>();
        //insert raw contact using RawContacts.CONTENT_URI
        contentProviderOperations.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null).withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null).build());
        //insert contact display name using Data.CONTENT_URI
        Log.d("ffff","wwww");
        contentProviderOperations.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0).withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,contactname ).build());
        //insert mobile number using Data.CONTENT_URI
        contentProviderOperations.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0).withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, contactnumber).withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE).build());
        try {
            //apply the changes
            getApplicationContext().getContentResolver().
                    applyBatch(ContactsContract.AUTHORITY, contentProviderOperations);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }

//        SelectContactAdapter.changeCursor(cursor);

        Toast.makeText(this, "Contact saved",
                Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        return true;
    }

    //This clears the edittext next time user starts the application, rather than
//    having the same numbers there, which the user probably doesn't want anymore
    protected void onResume() {
        final EditText editText = (EditText) findViewById(R.id.edittextname);
        super.onResume();
        editText.setText("");
    }


}

And here's my MainActivity code :

package com.example.chris.contactlistcustomlistview;

        import android.app.Activity;
        import android.content.ContentResolver;
        import android.content.ContentUris;
        import android.content.Intent;
        import android.database.Cursor;
        import android.database.DatabaseUtils;
        import android.graphics.Bitmap;
        import android.net.Uri;
        import android.os.AsyncTask;
        import android.os.Bundle;
        import android.provider.BaseColumns;
        import android.provider.ContactsContract;
        import android.provider.MediaStore;
        import android.util.Log;
        import android.view.MenuInflater;
        import android.view.MenuItem;
        import android.view.View;
        import android.widget.AdapterView;
        import android.widget.ImageView;
        import android.widget.ListView;
        import android.widget.PopupMenu;
        import android.widget.SearchView;
        import android.widget.TextView;
        import android.widget.Toast;

        import java.io.IOException;
        import java.util.ArrayList;
        import java.util.HashMap;
        import java.util.HashSet;
        import java.util.List;
        import java.util.Set;

public class MainActivity extends Activity implements PopupMenu.OnMenuItemClickListener {


    // ArrayList
    ArrayList<SelectContact> selectContacts;
    List<SelectContact> temp;
    // Contact List
    ListView listView;
    // Cursor to load contacts list
//    Cursor phones, email;
    Cursor pCur;

    // Pop up
//    ContentResolver resolver;
    SearchView search;
    SelectContactAdapter adapter;
    String phoneContactId;
    String name;
    String phoneNumber;
    CharSequence nameofcontact;
//    String phoneNumber;

    //    *****18-04-2016***
    Cursor cursor;
    ListView mainListView;
    ArrayList hashMapsArrayList;
//    String contactid;
//    *****


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        selectContacts = new ArrayList<SelectContact>();
//        resolver = this.getContentResolver();
        listView = (ListView) findViewById(R.id.contacts_list);



        LoadContact loadContact = new LoadContact();
        loadContact.execute();

        search = (SearchView) findViewById(R.id.searchView);


        //*** setOnQueryTextListener ***
        search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {

            @Override
            public boolean onQueryTextSubmit(String query) {
                // TODO Auto-generated method stub

                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                // TODO Auto-generated method stub
                adapter.filter(newText);
                return false;
            }
        });


    }

    // Load data on background
    class LoadContact extends AsyncTask<Void, Void, Void> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();

        }


        @Override
        protected Void doInBackground(Void... voids) {

            if (cursor != null) {
                cursor.moveToFirst();

            }
            try {

//                get a handle on the Content Resolver, so we can query the provider,
                cursor = getApplicationContext().getContentResolver()
//                the table to query
                        .query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
//               Null. This means that we are not making any conditional query into the contacts table.
//               Hence, all data is returned into the cursor.
//                                Projection - the columns you want to query
                                null,
//                                Selection - with this you are extracting records with assigned (by you) conditions and rules
                                null,
//                                SelectionArgs - This replaces any question marks (?) in the selection string
//                               if you have something like String[] args = { "first string", "second@string.com" };
                                null,
//                                display in ascending order
                                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " COLLATE LOCALIZED ASC");

//                get the column number of the Contact_ID column, make it an integer.
//                I think having it stored as a number makes for faster operations later on.
                int Idx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID);
//                get the column number of the DISPLAY_NAME column
                int nameIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
//                 get the column number of the NUMBER column
                int phoneNumberIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);

//                int photoIdIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI);


                cursor.moveToFirst();

//              We make a new Hashset to hold all our contact_ids, including duplicates, if they come up
                Set<String> ids = new HashSet<>();
                do {
                    System.out.println("=====>in while");
//                  get a handle on the contactid, which is a string. Loop through all the contact_ids
                    String contactid = cursor.getString(Idx);
//                  if our Hashset doesn't already contain the contactid string,
//                    then add it to the hashset
                    if (!ids.contains(contactid)) {
                        ids.add(contactid);

                        HashMap<String, String> hashMap = new HashMap<String, String>();
//                        get a handle on the display name, which is a string
                        name = cursor.getString(nameIdx);
//                        get a handle on the phone number, which is a string
                         phoneNumber = cursor.getString(phoneNumberIdx);
//                        String image = cursor.getString(photoIdIdx);
//                    System.out.println("Id--->"+contactid+"Name--->"+name);
                        System.out.println("Id--->" + contactid + " Name--->" + name);
                        System.out.println("Id--->" + contactid + " Number--->" + phoneNumber);




                        SelectContact selectContact = new SelectContact();
//                    selectContact.setThumb(bit_thumb);
                        selectContact.setName(name);
                        selectContact.setPhone(phoneNumber);
//                    selectContact.setEmail(id);
//                    selectContact.setCheckedBox(false);
                        selectContacts.add(selectContact);
                    }


                } while (cursor.moveToNext());


            } catch (Exception e) {
                e.printStackTrace();
            } finally {
//                if (cursor != null) {

//                }
            }
            cursor.close();
            return null;

        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
//into each inflate_listview, put a name and phone number, which are the details making
//            our SelectContact, above. And SelectContacts is all these inflate_listviews together
//            This is the first property of our SelectContactAdapter, a list
//            The next part, MainActivity.this, is our context, which is where we want the list to appear
            adapter = new SelectContactAdapter(selectContacts, MainActivity.this);
            listView.setAdapter(adapter);


            // Select item on listclick
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {



                         nameofcontact = ((TextView)view.findViewById(R.id.name)).getText();
//                    }
                    // Creates a new Intent to edit a contact
                        Intent intent = new Intent(Intent.ACTION_EDIT);



                    startActivity(intent);



                        listView.setFastScrollEnabled(true);
                    }



            });
        }}

        //the is the arrow image, it opens the activity for edit or new contact
        public void EditorCreateContact(View v) {


        }


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

        }

    //    this is for the settings menu
    public void settingsPopUp(View view) {

        PopupMenu popup = new PopupMenu(this,view);
        popup.setOnMenuItemClickListener(MainActivity.this);
        MenuInflater inflater = popup.getMenuInflater();
        inflater.inflate(R.menu.popup_actions, popup.getMenu());
        popup.show();
    }



    @Override
    public boolean onMenuItemClick(MenuItem item) {
        switch (item.getItemId()) {
//            from the popup_actions.xml, identify the New_contact id and make it
//            open the AddContact class
            case R.id.New_contact:{
                Intent intent = new Intent(this, AddContact.class);
                startActivity(intent);
//                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//                startActivity(intent);
//                finish(); // Call once you redirect to another activity
            }

//                Toast.makeText(getBaseContext(), "You slected New Contact",Toast.LENGTH_SHORT).show();
//
            return true;


        }
        return false;
    }


    }
CHarris
  • 2,693
  • 8
  • 45
  • 71
  • 1
    you can requery contacts in `onResume()` of your `MainActivity`. – Satyen Udeshi May 07 '16 at 09:48
  • @SatyenUdeshi You mean something like : protected void onResume() { changeCursor(cursor); } ?? – CHarris May 07 '16 at 09:56
  • Can you add your `MainActivity` code and also it is good to use `startActivityForResult` as suggested in one of the answers below.. – Satyen Udeshi May 07 '16 at 09:58
  • 1
    use `android.content.Loader` framework – pskink May 07 '16 at 10:01
  • @SatyenUdeshi Sure, just added my MainActivity. – CHarris May 07 '16 at 10:05
  • @SatyenUdeshi thanks for your answer and the additional info, and to the others who answered too. Not in front of my work machine at the moment, but will be working on it as soon as I'm back this evening. Cheers. – CHarris May 07 '16 at 10:16
  • @Satyen Udeshi Works now, thanks. At first I was getting errors and thought I might ask if you could suggest something but looked closer and the error in logcat was like – can't query as the cursor is closed. So I took out cursor.close() and now it works. MainActivity is updated with latest contact added. Any ideas on cursor.close() ? Where to put it ? I believe it is important to always close a cursor. I tried it on onResume, after loadContact.execute, but it was giving me an error. I'm getting contacts listed twice and thrice etc, even with selectContacts.clear(). Any idea how to stop this? – CHarris May 08 '16 at 08:56

3 Answers3

2

First of all declare the line

final EditText editText = (EditText) findViewById(R.id.edittextname);

in OnCreate() ... as it is a bad practice to initialize the view every time at on resume of activity.

and query the data in OnResume of your activity. Thats a better way to refresh the data as you come back to your activity.

SRB Bans
  • 3,096
  • 1
  • 10
  • 21
1

You could use startActivityForResult() instead of startActivity and override onActivityResult() to requery your cursor on success. After the toasting, setResult() to RESULT_OK and finish the AddContact activity.

setResult(RESULT_OK);
finish();
tynn
  • 38,113
  • 8
  • 108
  • 143
1

You can refresh your contacts in onResume() method as i mentioned in comments, for that you can do the following in onResume() itself

      LoadContact loadContact = new LoadContact();
      loadContact.execute();

you can remove the above from onCreate() as it would be redundant to call as onResume() will be called every time as the Activity LifeCycle.

If you use this approach just clear ArrayList selectContacts by doing selectContacts.clear() in doInBackground() at the first line, other wise it will list contacts twice and thrice and so onn...

Also apart from these, as mentioned in another answer in same thread you can use, startActivityForResult() and in onActivityResult() method you can update contact list.

Satyen Udeshi
  • 3,223
  • 1
  • 19
  • 26
  • The above solution significantly solved my problem, but the `selectContacts.clear()` was making my app crash. This post was helpful: http://stackoverflow.com/questions/3132021/android-listview-illegalstateexception-the-content-of-the-adapter-has-changed/37105387#37105387 Basically, I added `adapter.notifyDataSetChanged();` at the bottom of my onPostExecute method and it solved the problem. – CHarris May 08 '16 at 22:21
  • 1
    @ChristopheHarris Great that it helped, and `selectContacts.clear()` was meant to clear the contact list before you again query the results else it would have shown you multiple same contacts each time you query the contacts, regarding the crash, it may be because it might not have been initialized and yes definitely you to use `notifyDataSetChanged()` to update the data in the adapter – Satyen Udeshi May 09 '16 at 04:06