0

I have a problem starting an activity to pick an image from the gallery when I start it from the 3rd level of FragmentActivity/Fragment combinations. If I start it from the 1st or 2nd level, it works. In the app, there are up to 5 levels of FramentActivity/Fragment combinations running without a problem, but I don't start the activity to pick an image from them.

Is there a maximum level of FramentActivity/Fragment combinations that I can start? Or what am I doing wrong?

The FragmentActivity starts the Fragment like this:

public class MyActivity extends FragmentActivity
{
private MyFragment _fragment;
...

@Override
public void onCreate( Bundle savedInstanceState )
{
    super.onCreate( savedInstanceState );
    setContentView( R.layout.simple_fragment_container_activity );

    // create the fragment to show
    FragmentManager fm = getSupportFragmentManager();
    _fragment = (MyFragment)fm.findFragmentById( R.id.fragment_container );

    // If the Fragment is non-null, then it is currently being retained across a configuration change.
    if( _fragment == null )
    {
        _fragment = new MyFragment();

        // start the new fragment
        FragmentTransaction ft = fm.beginTransaction();
        ft.add( R.id.fragment_container, _fragment );
        ft.commit();
    }
}

The Fragment code is:

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

    // retain this fragment across configuration changes
    setRetainInstance( true );
}
@Override
public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState )
{
    View v = inflater.inflate( R.layout.my_fragment, container, false );
    ...
    return v;
}

In the OnClickListener of a button, I start the image picker like this:

Intent intent = new Intent( Intent.ACTION_GET_CONTENT );
intent.setType( "image/*" );
startActivityForResult( intent, 20 );           

As soon as I close the image picker (no matter if selecting an image or not), my app crashes before resuming it. The onActivityResult method is sometimes called fully, sometimes partly. It does nothing than log the image path for the moment:

if( resultCode != Activity.RESULT_OK ) return;
if( requestCode == 20 )
{
    Uri selectedImage = intent.getData();
    Log.w( null, "image picked: " + selectedImage.toString() );
}

The crash writes this to the LogCat and does not happen in my code IMO:

05-19 08:18:19.210: D/AndroidRuntime(24592): Shutting down VM
05-19 08:18:19.210: W/dalvikvm(24592): threadid=1: thread exiting with uncaught exception (group=0x41826da0)
05-19 08:18:19.220: E/AndroidRuntime(24592): FATAL EXCEPTION: main
05-19 08:18:19.220: E/AndroidRuntime(24592): Process: ch.infero.testapp, PID: 24592
05-19 08:18:19.220: E/AndroidRuntime(24592): java.lang.RuntimeException: Unable to resume activity {ch.infero.testapp/ch.infero.testapp.settings.MyActivity}: android.database.StaleDataException: Attempted to access a cursor after it has been closed.
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2946)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2975)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1307)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.os.Handler.dispatchMessage(Handler.java:102)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.os.Looper.loop(Looper.java:157)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.app.ActivityThread.main(ActivityThread.java:5356)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at java.lang.reflect.Method.invokeNative(Native Method)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at java.lang.reflect.Method.invoke(Method.java:515)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at dalvik.system.NativeStart.main(Native Method)
05-19 08:18:19.220: E/AndroidRuntime(24592): Caused by: android.database.StaleDataException: Attempted to access a cursor after it has been closed.
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.database.BulkCursorToCursorAdaptor.throwIfCursorIsClosed(BulkCursorToCursorAdaptor.java:64)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.database.BulkCursorToCursorAdaptor.requery(BulkCursorToCursorAdaptor.java:133)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.database.CursorWrapper.requery(CursorWrapper.java:186)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.app.Activity.performRestart(Activity.java:5471)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.app.Activity.performResume(Activity.java:5497)
05-19 08:18:19.220: E/AndroidRuntime(24592):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2936)
05-19 08:18:19.220: E/AndroidRuntime(24592):    ... 10 more
infero
  • 843
  • 2
  • 11
  • 22
  • 1
    There is no maximum. But the error is explained perfectly right there in the stack trace: `android.database.StaleDataException: Attempted to access a cursor after it has been closed.` – Xaver Kapeller May 19 '15 at 06:30

2 Answers2

0

No, there is no such explicit limit. The problem you have is a database cursor being reused when one of your activities comes back to front (in MyActivity.onResume() it seems) although it was already closed before.

FD_
  • 12,947
  • 4
  • 35
  • 62
  • I'm not using a cursor in the 3rd activity that calls the image picker. Does the 1st or 2nd level matter at that time? – infero May 19 '15 at 06:35
  • Do you have a database cursor somewhere else in your code? – FD_ May 19 '15 at 06:38
  • Yes, but not in the 2nd or 3rd level activities/fragments. Only the 3rd level is coming back in front. Each level fully covers the activity that starts it. So a starting activity should not be resumed before the on it calls closes – infero May 19 '15 at 06:39
  • The crash is definitely related to that cursor. It's hard to tell any more details without the full code. – FD_ May 19 '15 at 06:41
0

I found the cause... Hopefully it helps others coming across the same problem.

In the onCreate method of the fragment that starts the image picker activity, I had this code snippet to read out the name and uri of available ringtones:

...
RingtoneManager rm = new RingtoneManager( getActivity() );
rm.setType( RingtoneManager.TYPE_NOTIFICATION );
Cursor c = rm.getCursor();
while( c.moveToNext() )
{
    String title = c.getString( RingtoneManager.TITLE_COLUMN_INDEX );
    String id = c.getString( RingtoneManager.ID_COLUMN_INDEX );
    String uri = c.getString( RingtoneManager.URI_COLUMN_INDEX );
    // ...put it to a local list
}
c.close()       // <<<< this line is the problem !!!
...

Well, the help text of RingtoneManager.getCursor() states it:

Returns a Cursor of all the ringtones available. The returned cursor will be the same cursor returned each time this method is called, so do not Cursor.close() the cursor. The cursor can be Cursor.deactivate() safely.

infero
  • 843
  • 2
  • 11
  • 22