简体   繁体   中英

How to save a string before a Back button press, and retrieve it when you go back to the activity?

I am developing an app to compare two photos. On the home screen, there are two buttons, one button leads you to an activity to pick a photo from your Photos and the other button does the same for the second photo.

The problem is when the user picks the first photo and presses the Back button to go back the home screen into the pick the 2nd photo, the first photo gets erased.

I first tried converting the uri to string and store it in SharePreference, but then there is a error because I don't have Manifest.permission.MANAGE_DOCUMENT, which is NEVER granted to 3rd party app like mine.

So I look to onSaveInstanceState() to save the string in the savedInstanceState Bundle object to be retrieved in onCreate(). But I learned that onSaveInstanceState() is never executed when the back button is pressed.

So I try manually calling it:

@Override
public void onBackPressed(){
    Bundle bundle=new Bundle();
    bundle.putString("photoUri",stringUri);
    onSaveInstanceState(bundle);
    super.onBackPressed();
}

@Override
public void onSaveInstanceState(Bundle outState){
    super.onSaveInstanceState(outState);
}

But now, the problem is the back button won't work anymore.

EDIT: this is my entire java code:

public class Photo1 extends AppCompatActivity implements View.OnClickListener{

Button btnPhoto1Picker;//The button that you click to open select photo menu
private int PICK_IMAGE_REQUEST = 1;
SharedPreferences pref;//for permanent storage
SharedPreferences.Editor editor;//for tapping into permanent storage
ImageView imageView;//for displaying selected photo
@Override

/**
 * @throws NullPointerException For the very time and the only time after the try statement is written, there is nothing in "encoded" variable
 * so it is null. If there is no catch statement, the app will crash.
 */
protected void onCreate(Bundle savedInstanceState){
    //Initializing permanent storage and its editor
    pref=getApplicationContext().getSharedPreferences("MyPref",MODE_PRIVATE);
    editor=pref.edit();

    super.onCreate(savedInstanceState);
    setContentView(R.layout.photo1);

    //setting up displaying image view and the select button
    imageView = (ImageView) findViewById(R.id.displayPhoto1View);
    btnPhoto1Picker=(Button) findViewById(R.id.pickPhoto1Button);
    btnPhoto1Picker.setOnClickListener(this);

    try {
        String stringUri = pref.getString("photo1String", null);
        Uri uri=Uri.parse(stringUri);
        setImageView(uri);
    } catch (IOException e) {
    }
}

/**
 * This method is triggered when the select image button is clicked. It sends a request for a select photo window to be opened.
 * @param v the button view
 */
@Override
public void onClick(View v){
    Intent intent = new Intent();
    // Show only images, no videos or anything else
    intent.setType("image/*");//indicate an explicit MIME data type to return
    intent.setAction(Intent.ACTION_GET_CONTENT);//set general action to perform
    // Always show the chooser (if there are multiple options available)
    startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST);
}

/**
 *When an activity you launched exits, giving you the requestCode you started it with.
 * @param requestCode PICK_IMAGE-REQUEST, the integer request code originally supplied to startActivityForResult(),
 *                    used to identify who the result come from
 * @param resultCode  an integer return by child activity through
 * @param data The data use to get the photo selected.
 */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {

        Uri uri = data.getData();
        String stringUri=uri.toString();
        editor.putString("photo1String",stringUri).apply();

        try {
            setImageView(uri);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}//onActivity ends
private void setImageView(Uri uri) throws IOException{
    Bitmap bitmap1= MediaStore.Images.Media.getBitmap(getContentResolver(), uri);//this is the photo selected
    // Log.d(TAG, String.valueOf(bitmap));
    imageView.setImageBitmap(bitmap1);
}

}

And this is the error message:

06-21 10:13:14.274 21113-21113/? E/AndroidRuntime: FATAL EXCEPTION: main
                                               Process: com.example.android.sidebyside, PID: 21113
                                               java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.sidebyside/com.example.android.sidebyside.Photo1}: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{6297a23 21113:com.example.android.sidebyside/u0a170} (pid=21113, uid=10170) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS
                                                   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2678)
                                                   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2743)
                                                   at android.app.ActivityThread.-wrap12(ActivityThread.java)
                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1490)
                                                   at android.os.Handler.dispatchMessage(Handler.java:102)
                                                   at android.os.Looper.loop(Looper.java:154)
                                                   at android.app.ActivityThread.main(ActivityThread.java:6165)
                                                   at java.lang.reflect.Method.invoke(Native Method)
                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)
                                                Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{6297a23 21113:com.example.android.sidebyside/u0a170} (pid=21113, uid=10170) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS
                                                   at android.os.Parcel.readException(Parcel.java:1684)
                                                   at android.os.Parcel.readException(Parcel.java:1637)
                                                   at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:4279)
                                                   at android.app.ActivityThread.acquireProvider(ActivityThread.java:5517)
                                                   at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2239)
                                                   at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1517)
                                                   at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1131)
                                                   at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:984)
                                                   at android.content.ContentResolver.openInputStream(ContentResolver.java:704)
                                                   at android.provider.MediaStore$Images$Media.getBitmap(MediaStore.java:872)
                                                   at com.example.android.sidebyside.Photo1.setImageView(Photo1.java:100)
                                                   at com.example.android.sidebyside.Photo1.onCreate(Photo1.java:56)
                                                   at android.app.Activity.performCreate(Activity.java:6687)
                                                   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1140)
                                                   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2631)
                                                   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2743) 
                                                   at android.app.ActivityThread.-wrap12(ActivityThread.java) 
                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1490) 
                                                   at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                   at android.os.Looper.loop(Looper.java:154) 
                                                   at android.app.ActivityThread.main(ActivityThread.java:6165) 
                                                   at java.lang.reflect.Method.invoke(Native Method) 
                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888) 
                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778) 

If you got that error when writing to a SharedPreference, you were doing something really wrong. You don't need any permissions to write to a shared preference.

You should never call onSaveInstanceState manually. This is a lifecycle function, and will be called when appropriate by the framework. Calling it by hand will not do what you hope to do. Go back to the shared preference.

Hardware onBackPressed will trigger finish() in most of cases .which means Activity will be created again based on launchMode . Also please check about onSaveInstanceState in android developer docs.it clearly says :

onSaveInstanceState() is not called when the user explicitly closes the activity or in other cases when finish()is called.

you should consider storing it to place where data will not be lost .one possible solution could be having one property in Application class and use it accordingly.

Using SharedPreference doesnt need any permission and is an excellent choice to store small collection .you can store data in following way

SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("Photo_Uri", stringUri);
editor.commit();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM