How to save & retrieve the image's URI though onSaveInstanceState?

Andros Adrianopolos :

I'm trying to work with orientation change. At the moment, the image in my fragment is gone when I rotate the phone. This is obviously because the activity is destroyed & recreated. Instead of trying to save such a large data like an image, I decided to work around that by saving the image's Uri in the onSaveInstanceState method:

@Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable("imageUri", imageUri);
    }

And in my fragment's onCreateView, I tried to retrieve the Uri and paste it back into the ImageView by also keeping the null possibility in mind.

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

        imageView = view.findViewById(R.id.meme_image_view);

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                selectedImage(v);
            }
        });

        topTextView = view.findViewById(R.id.top_text_view);
        bottomTextView = view.findViewById(R.id.bottom_text_view);

        if(savedInstanceState != null){
            if(imageUri != null){
                Uri savedUri = savedInstanceState.getParcelable("imageUri");
                imageView.setImageURI(savedUri);
            }
        }

        return view;
    }

And for some reason, it doesn't work. The image is still lost when I rotate the phone.

Full fragment:

public class TopImageFragment extends Fragment {

    ImageView imageView;
    TextView topTextView, bottomTextView;
    public static final int PICK_IMAGE = 1;
    Uri imageUri;
    int counter = 0;
    String timeStamp = new SimpleDateFormat("yyyyMMdd").format(new Date());

    MemeViewModel memeViewModel;

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

        imageView = view.findViewById(R.id.meme_image_view);

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                selectedImage(v);
            }
        });

        topTextView = view.findViewById(R.id.top_text_view);
        bottomTextView = view.findViewById(R.id.bottom_text_view);

        if(savedInstanceState != null){
            Uri savedUri = savedInstanceState.getParcelable("imageUri");
            imageView.setImageURI(savedUri);
        }

        return view;
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable("imageUri", imageUri);
    }

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

        memeViewModel = ViewModelProviders.of(Objects.requireNonNull(getActivity())).get(MemeViewModel.class);

        memeViewModel.getTopText().observe(getViewLifecycleOwner(), new Observer<CharSequence>() {
            @Override
            public void onChanged(@Nullable CharSequence charSequence) {
                topTextView.setText(charSequence);
            }
        });

        memeViewModel.getBottomText().observe(getViewLifecycleOwner(), new Observer<CharSequence>() {
            @Override
            public void onChanged(@Nullable CharSequence charSequence) {
                bottomTextView.setText(charSequence);
            }
        });
    }

    public void selectedImage(View v) {
        Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
        startActivityForResult(intent, PICK_IMAGE);
    }

    public void createBitmapAndSave(ImageView img) {

        BitmapDrawable bitmapDrawable = ((BitmapDrawable) img.getDrawable());
        Bitmap bitmap = bitmapDrawable.getBitmap();
        Bitmap mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

        String topText = topTextView.getText().toString();
        String bottomText = bottomTextView.getText().toString();

        Canvas canvas = new Canvas(mutableBitmap);
        TextPaint topPaint = new TextPaint();
        TextPaint bottomPaint = new TextPaint();
        Typeface typeface = getResources().getFont(R.font.impact);

        topPaint.setColor(Color.WHITE);
        topPaint.setStyle(Paint.Style.FILL);
        topPaint.setShadowLayer(10f, 10f, 10f, Color.BLACK);
        topPaint.setTextSize(topTextView.getTextSize());
        topPaint.setTypeface(typeface);

        bottomPaint.setColor(Color.WHITE);
        bottomPaint.setStyle(Paint.Style.FILL);
        bottomPaint.setShadowLayer(10f, 10f, 10f, Color.BLACK);
        bottomPaint.setTextSize(bottomTextView.getTextSize());
        bottomPaint.setTypeface(typeface);

        float topTextMeasurement = topPaint.measureText(topText);
        float bottomTextMeasurement = bottomPaint.measureText(bottomText);

        StaticLayout topLayout = new StaticLayout(topText, topPaint, canvas.getWidth(), Layout.Alignment.ALIGN_CENTER, 1.0f,
                0.0f, false);
        StaticLayout bottomLayout = new StaticLayout(bottomText, bottomPaint, canvas.getWidth(), Layout.Alignment.ALIGN_CENTER,
                1.0f, 0.0f, false);

        canvas.translate(0,0);
        topLayout.draw(canvas);

        canvas.translate(0, canvas.getHeight() - 210);
        bottomLayout.draw(canvas);
        counter++;

        File file;
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

        String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath();
        file = new File(path + "/SimpliMeme/" + timeStamp + "-" + counter + ".jpg");
        file.getParentFile().mkdir();

        try {
            OutputStream stream = new FileOutputStream(file);
            mutableBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
            stream.flush();
            stream.close();
            Toast.makeText(getContext(), "Top Text: " + String.valueOf(topTextMeasurement) + " and bottom text: " + String.valueOf(bottomTextMeasurement),
                    Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            e.printStackTrace();
        }

        Uri contentUri = Uri.fromFile(file);
        mediaScanIntent.setData(contentUri);
        Objects.requireNonNull(getContext()).sendBroadcast(mediaScanIntent);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK && requestCode == PICK_IMAGE) {
            imageUri = Objects.requireNonNull(data).getData();
            imageView.setImageURI(imageUri);
            memeViewModel.setSharedId(imageUri.getLastPathSegment());
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(listener, new IntentFilter("CUSTOM_ACTION"));
    }

    private BroadcastReceiver listener = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String data = intent.getStringExtra("DATA");
            createBitmapAndSave(imageView);
        }
    };

    @Override
    public void onPause() {
        super.onPause();
        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(listener);
    }
}

SOLUTION

These are the changes I've made to my onCreateView method. Turns out, I was not saving the retrieved Uri to the imageUri field

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ...

        if(savedInstanceState != null){
            imageUri = savedInstanceState.getParcelable("imageUri");
            imageView.setImageURI(imageUri);
        }

        ...
    }
CommonsWare :

Replace:

outState.putString(String.valueOf(imageUri), "imageUri");

with:

outState.putParcelable("imageUri", imageUri);

and replace:

String raw = savedInstanceState.getString("imageUri");
Uri savedUri = Uri.parse(raw);

with:

Uri savedUri = savedInstanceState.getParcelable("imageUri");

The put...() methods on Bundle take the key, followed by the value. You have the value, followed by the key. And, in the case of Uri, you do not need to convert it to and from String.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=96744&siteId=1