how do you pass images (bitmaps) between android activities using bundles?
Asked Answered
I

10

57

Suppose I have an activity to select an image from the gallery, and retrieve it as a BitMap, just like the example: here

Now, I want to pass this BitMap to be used in an ImageView for another activity. I am aware bundles can be passed between activities, but how would I store this BitMap into the bundle?

or is there another approach I should take?

Isoprene answered 4/12, 2010 at 5:49 Comment(0)
W
56

I would highly recommend a different approach.

It's possible if you REALLY want to do it, but it costs a lot of memory and is also slow. It might not work if you have an older phone and a big bitmap. You could just pass it as an extra, for example intent.putExtra("data", bitmap). A Bitmap implements Parcelable, so you can put it in an extra. Likewise, a bundle has putParcelable.

If you want to pass it inbetween activities, I would store it in a file. That's more efficient, and less work for you. You can create private files in your data folder using MODE_PRIVATE that are not accessible to any other app.

Waterproof answered 4/12, 2010 at 6:0 Comment(8)
what if I just passed the path of the image to the other activity?Isoprene
Absolutely, that's perfect! I thought the Bitmap was temporarily created by your activity, that's why you had to pass it along. (If you DID create it like that, you may want to save it to your local folder and then reload it).Waterproof
Btw, one more thing - in my rant about it being bad, I'm talking about full-size images. If you have smaller bitmaps, it's certainly okay to pass them as a Parcelable.Waterproof
I may end up doing that though since I want to replicate the contact image picker, select an image and crop it. but I'll post that in another question, thanks!Isoprene
Please help me..thanksFidelafidelas
greatest answerAggravation
Does this solution require android.permission.WRITE_EXTERNAL_STORAGE?Kassala
The official documentation developer.android.com/guide/components/activities/… says "We recommend that you keep saved state to less than 50k of data".Hel
B
45

If you pass it as a Parcelable, you're bound to get a JAVA BINDER FAILURE error. So, the solution is this: If the bitmap is small, like, say, a thumbnail, pass it as a byte array and build the bitmap for display in the next activity. For instance:

in your calling activity...

Intent i = new Intent(this, NextActivity.class);
Bitmap b; // your bitmap
ByteArrayOutputStream bs = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.PNG, 50, bs);
i.putExtra("byteArray", bs.toByteArray());
startActivity(i);

...and in your receiving activity

if(getIntent().hasExtra("byteArray")) {
    ImageView previewThumbnail = new ImageView(this);
    Bitmap b = BitmapFactory.decodeByteArray(
        getIntent().getByteArrayExtra("byteArray"),0,getIntent().getByteArrayExtra("byteArray").length);        
    previewThumbnail.setImageBitmap(b);
}
Borchert answered 25/10, 2011 at 13:57 Comment(9)
Can you explain how this helps avoid a Java Binder Failure?Etherege
And if the bitmap is not very small?Pestana
Why are you compressing the file, when you don't use the compressed version anyhow?Evoke
@Evoke It's being compressed into the bs variable which is used.Lita
It does not works for meFidelafidelas
you should not pass a bitmap through binder without knowing how big it is. You are most likely getting a Binder FailurePrivilege
Does anybody know how big must be the bitmap to get out of memory error?Hutchens
I would use Parcelable when bitmap is small. The problem comes when you are passing more than 1mb of data in bundle.Makowski
it works but for large size image do not work, it says system do not allow...Merous
S
24

As suggested by @EboMike I saved the bitmap in a file named myImage in the internal storage of my application not accessible my other apps. Here's the code of that part:

public String createImageFromBitmap(Bitmap bitmap) {
    String fileName = "myImage";//no .png or .jpg needed
    try {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
        FileOutputStream fo = openFileOutput(fileName, Context.MODE_PRIVATE);
        fo.write(bytes.toByteArray());
        // remember close file output
        fo.close();
    } catch (Exception e) {
        e.printStackTrace();
        fileName = null;
    }
    return fileName;
}

Then in the next activity you can decode this file myImage to a bitmap using following code:

Bitmap bitmap = BitmapFactory.decodeStream(context
                    .openFileInput("myImage"));//here context can be anything like getActivity() for fragment, this or MainActivity.this

Note A lot of checking for null and scaling bitmap's is ommited.

Shurlocke answered 8/7, 2014 at 11:32 Comment(5)
do I have to delete the file after?Aqualung
@Aqualung I dont think you need to delete the image because every time you use the function the previous image is overwritten. However you could delete it if you wanted toShurlocke
Probably should delete it.Shad
Does this require android.permissions.WRITE_EXTERNAL_STORAGE at all?Kassala
@AlanNelson You dont need the permission if you save the image in the apps private storage. If you save it in public folder like gallery you would need the permission.Shurlocke
A
9

Activity

To pass a bitmap between Activites

Intent intent = new Intent(this, Activity.class);
intent.putExtra("bitmap", bitmap);

And in the Activity class

Bitmap bitmap = getIntent().getParcelableExtra("bitmap");

Fragment

To pass a bitmap between Fragments

SecondFragment fragment = new SecondFragment();
Bundle bundle = new Bundle();
bundle.putParcelable("bitmap", bitmap);
fragment.setArguments(bundle);

To receive inside the SecondFragment

Bitmap bitmap = getArguments().getParcelable("bitmap");

Transferring large bitmap (Compress bitmap)

If you are getting failed binder transaction, this means you are exceeding the binder transaction buffer by transferring large element from one activity to another activity.

So in that case you have to compress the bitmap as an byte's array and then uncompress it in another activity, like this

In the FirstActivity

Intent intent = new Intent(this, SecondActivity.class);

ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPG, 100, stream);
byte[] bytes = stream.toByteArray(); 
intent.putExtra("bitmapbytes",bytes);

And in the SecondActivity

byte[] bytes = getIntent().getByteArrayExtra("bitmapbytes");
Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Alchemist answered 22/1, 2016 at 7:14 Comment(1)
where in firstactivity should the above code be used. Should it be in init or as a seperate method ( and call this method in secondactivity ??Ligulate
L
2

Bitmap is Parcelable so you can add using [putExtra(String,Parcelable)][2] method, But not sure it is a best practice, If it is large size data it is better to store in a single place and use from both activities.

[2]: http://developer.android.com/reference/android/content/Intent.html#putExtra(java.lang.String, android.os.Parcelable)

Laryngeal answered 4/12, 2010 at 5:59 Comment(0)
P
2

in first.java

Intent i = new Intent(this, second.class);
                    i.putExtra("uri",uri);
                    startActivity(i);

in second.java

Bundle bd = getIntent().getExtras();
        Uri uri = bd.getParcelable("uri");
        Log.e("URI", uri.toString());
        try {
            Bitmap bitmap = Media.getBitmap(this.getContentResolver(), uri);
            imageView.setImageBitmap(bitmap);

        } 
        catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
Pigeontoed answered 4/10, 2014 at 5:29 Comment(1)
is imageShow an object of imageView?Bertine
M
1

I had to rescale the bitmap a bit to not exceed the 1mb limit of the transaction binder. You can adapt the 400 the your screen or make it dinamic it's just meant to be an example. It works fine and the quality is nice. Its also a lot faster then saving the image and loading it after but you have the size limitation.

public void loadNextActivity(){
    Intent confirmBMP = new Intent(this,ConfirmBMPActivity.class);

    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    Bitmap bmp = returnScaledBMP();
    bmp.compress(Bitmap.CompressFormat.JPEG, 100, stream);

    confirmBMP.putExtra("Bitmap",bmp);
    startActivity(confirmBMP);
    finish();

}
public Bitmap returnScaledBMP(){
    Bitmap bmp=null;
    bmp = tempBitmap;
    bmp = createScaledBitmapKeepingAspectRatio(bmp,400);
    return bmp;

}

After you recover the bmp in your nextActivity with the following code:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_confirmBMP);
    Intent intent = getIntent();
    Bitmap bitmap = (Bitmap) intent.getParcelableExtra("Bitmap");

}

I hope my answer was somehow helpfull. Greetings

Monogenetic answered 30/4, 2014 at 6:51 Comment(0)
R
1

Write this code from where you want to Intent into next activity.

    yourimageView.setDrawingCacheEnabled(true); 
    Drawable drawable = ((ImageView)view).getDrawable(); 
    Bitmap bitmap = imageView.getDrawingCache();
    Intent intent = new Intent(getBaseContext(), NextActivity.class);
    intent.putExtra("Image", imageBitmap);

In onCreate Function of NextActivity.class

Bitmap hotel_image;
Intent intent = getIntent();
hotel_image= intent.getParcelableExtra("Image");
Reformed answered 19/1, 2018 at 10:4 Comment(0)
J
1

You can pass image in short without using bundle like this This is the code of sender .class file

Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher;
Intent intent = new Intent();
Intent.setClass(<Sender_Activity>.this, <Receiver_Activity.class);
Intent.putExtra("Bitmap", bitmap);
startActivity(intent);

and this is receiver class file code.

Bitmap bitmap = (Bitmap)this.getIntent().getParcelableExtra("Bitmap");
ImageView viewBitmap = (ImageView)findViewById(R.id.bitmapview);
viewBitmap.setImageBitmap(bitmap);

No need to compress. that's it

Jovi answered 26/1, 2018 at 21:42 Comment(0)
M
0

It's better to save the file in temp/cache folder and pass the file path through intent data as I did it. here is sample code:

from on Button Click (Here bitmapFullScreen is a bitmap data which I have collected from Live Server)

Intent intent = new Intent(context, FullscreenActivity.class);
String fPath = CreateTempFile(bitmapFullScreen);
if(!StringUtils.isEmpty(fPath)) {
    intent.putExtra("image", fPath);
    startActivity(intent);
}

Function to create a File on Temp/Cache folder

public String CreateTempFile(Bitmap mBitmap) {
    File f3 = new File(Environment.getExternalStorageDirectory() + "/inpaint/");
    if (!f3.exists())
        f3.mkdirs();

    OutputStream outStream = null;
    SimpleDateFormat dateFormatter;
    dateFormatter = new SimpleDateFormat("MMddyyyyhhmmss", Locale.US);
    String FN = Environment.getExternalStorageDirectory() + "/inpaint/" + dateFormatter.format(Calendar.getInstance().getTime()) + ".png";
    File file = new File(FN);
    try {
        outStream = new FileOutputStream(file);
        mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
        outStream.close();
        return file.getAbsolutePath();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "";
}

2nd File where we need the file

Global var

String FileName = "";

Receive the Intent String data as FilePath to View Image on ImageView this code will be onCreate

ImageView imgUpload = findViewById(R.id.imgUpload);
try {
    if (getIntent().hasExtra("image")) {
        FileName = getIntent().getStringExtra("image");
        Bitmap b = BitmapFactory.decodeFile(FileName);
        imgUpload.setImageBitmap(b);
    }
} catch (Exception ex) {
    Toast.makeText(context, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
}

After display the Image we need to delete temp file

@Override
public void onBackPressed() {
    super.onBackPressed();
    try {
        File file = new File(FileName);
        file.delete();
    } catch (Exception ex) {
        Toast.makeText(context, "Error: " + ex.getMessage(), Toast.LENGTH_LONG).show();
    }
}
Merous answered 14/12, 2021 at 10:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.