Search code examples
androidlistactivity

Android - Opening ListActivity from MainActivity causes app to crash


This is a sample code given in List View in Android Developers. I am trying to launch this from a main activity. But it seems to have some problems, because it crashes when I click the button in the main activity.

package com.hsenidmobile.romeosierra.robotiumex;

import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.widget.SimpleCursorAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.ProgressBar;

public class ContactListActivity extends ListActivity
        implements LoaderManager.LoaderCallbacks<Cursor> {

    // This is the Adapter being used to display the list's data
    SimpleCursorAdapter mAdapter;

    // These are the Contacts rows that we will retrieve
    static final String[] PROJECTION = new String[] {ContactsContract.Data._ID,
            ContactsContract.Data.DISPLAY_NAME};

    // This is the select criteria
    static final String SELECTION = "((" +
            ContactsContract.Data.DISPLAY_NAME + " NOTNULL) AND (" +
            ContactsContract.Data.DISPLAY_NAME + " != '' ))";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a progress bar to display while the list loads
        ProgressBar progressBar = new ProgressBar(this);
        //progressBar.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER));
        progressBar.setIndeterminate(true);
        getListView().setEmptyView(progressBar);

        // Must add the progress bar to the root of the layout
        ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
        root.addView(progressBar);

        // For the cursor adapter, specify which columns go into which views
        String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME};
        int[] toViews = {android.R.id.text1}; // The TextView in simple_list_item_1

        // Create an empty adapter we will use to display the loaded data.
        // We pass null for the cursor, then update it in onLoadFinished()
        mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, null, fromColumns, toViews, 0);
        setListAdapter(mAdapter);

        // Prepare the loader.  Either re-connect with an existing one,
        // or start a new one.
        getLoaderManager().initLoader(0, null, this);
    }

    // Called when a new Loader needs to be created
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // Now create and return a CursorLoader that will take care of
        // creating a Cursor for the data being displayed.
        CursorLoader cursorLoader = null;
        return new CursorLoader(this, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, null, null);
    }

    // Called when a previously created loader has finished loading
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // Swap the new cursor in.  (The framework will take care of closing the
        // old cursor once we return.)
        mAdapter.swapCursor(data);
    }

    // Called when a previously created loader is reset, making the data unavailable
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // This is called when the last Cursor provided to onLoadFinished()
        // above is about to be closed.  We need to make sure we are no
        // longer using it.
        mAdapter.swapCursor(null);
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Do something when a list item is clicked
    }
}

Anyone who wouldn't mind having a look at this and tell me what the problem is?

EDIT :: Logcat

05-19 16:28:56.990  2467  2487 W PlatformStatsUtil: Could not retrieve Usage & Diagnostics setting. Giving up.
05-19 16:28:57.041  1632  1827 I ActivityManager: START u0 {cmp=com.hsenidmobile.romeosierra.robotiumex/.ContactListActivity} from uid 10072 on display 0
05-19 16:28:57.041  1632  1703 W AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by client; transfer 4, track 48000 Hz, output 44100 Hz
05-19 16:28:57.074  1632  2093 W ActivityManager: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{d1211dc 2416:com.hsenidmobile.romeosierra.robotiumex/u0a72} (pid=2416, uid=10072) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS
05-19 16:28:57.074  2416  3107 E AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
05-19 16:28:57.074  2416  3107 E AndroidRuntime: Process: com.hsenidmobile.romeosierra.robotiumex, PID: 2416
05-19 16:28:57.074  2416  3107 E AndroidRuntime: java.lang.RuntimeException: An error occurred while executing doInBackground()
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.os.AsyncTask$3.done(AsyncTask.java:325)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at java.util.concurrent.FutureTask.run(FutureTask.java:242)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at java.lang.Thread.run(Thread.java:761)
05-19 16:28:57.074  2416  3107 E AndroidRuntime: Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{d1211dc 2416:com.hsenidmobile.romeosierra.robotiumex/u0a72} (pid=2416, uid=10072) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.os.Parcel.readException(Parcel.java:1684)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.os.Parcel.readException(Parcel.java:1637)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:4199)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.app.ActivityThread.acquireProvider(ActivityThread.java:5476)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2239)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1517)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.content.ContentResolver.query(ContentResolver.java:516)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.content.CursorLoader.loadInBackground(CursorLoader.java:64)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.content.CursorLoader.loadInBackground(CursorLoader.java:56)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:312)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:69)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:66)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at android.os.AsyncTask$2.call(AsyncTask.java:305)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
05-19 16:28:57.074  2416  3107 E AndroidRuntime:    ... 3 more
05-19 16:28:57.075  1632  1827 W ActivityManager:   Force finishing activity com.hsenidmobile.romeosierra.robotiumex/.ContactListActivity
05-19 16:28:57.076  1632  1827 W ActivityManager:   Force finishing activity com.hsenidmobile.romeosierra.robotiumex/.MainActivity

As the logcat indicates it's a permission problem with android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS. But I already have the necessary permission set in the android manifest. Still I am getting the problem.


Solution

  • You need android.permission.READ_CONTACTS permission for this.

    So in the Manifest of your project you need to add below line

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    

    Also if you are targeting android 23 and above then you need to take run time permission as well.

    To get the runtime permission from user,

    Add this code in your onCreate of activity

     int result= ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS);
             if (result != PackageManager.PERMISSION_GRANTED) {   
    //we don't have permission to read contacts...so ask user to grant permission    
                 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 7);
                }
             else{
    // we already got the permission from user...now read contacts
                 readContacts();
                }
    

    You have onRequestPermissionsResult method to catch this event

    @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            if (requestCode == 7) {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    readContacts();
                } else {
                    Toast.makeText(this, "Can't read contacts as you have declined the permission.", Toast.LENGTH_SHORT).show();
                }
            }
    
        }
    

    and finally your code to read contacts

    //This is your method to read contacts
    
        private void readContacts()
        {
        //your code here
        }