33

How can I pass an image, drawable type between activities?

I try this:

private Drawable imagen;

Bundle bundle = new Bundle();
bundle.putSerializable("imagen", (Serializable) unaReceta.getImagen());
Intent myIntent = new Intent(v.getContext(), Receta.class);
myIntent.putExtras(bundle);
startActivityForResult(myIntent, 0);

But it reports me an execption:

java.lang.ClassCastException: android.graphics.drawable.BitmapDrawable
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
android iPhone
  • 860
  • 2
  • 11
  • 22

7 Answers7

58

1) Passing in intent as extras

In the Activity A you decode your image and send it via intent:

  • Using this method (extras) image is passed in 162 milliseconds time interval
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);     
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); 
byte[] b = baos.toByteArray();

Intent intent = new Intent(this, ActivityB.class);
intent.putExtra("picture", b);
startActivity(intent);

In Activity B you receive intent with byte array (decoded picture) and apply it as source to ImageView:

Bundle extras = getIntent().getExtras();
byte[] b = extras.getByteArray("picture");

Bitmap bmp = BitmapFactory.decodeByteArray(b, 0, b.length);
ImageView image = (ImageView) findViewById(R.id.imageView1);

image.setImageBitmap(bmp);

2) Saving image file and passing its reference to another activity

"The size limit is: keep it as small as possible. Definitely don't put a bitmap in there unless it is no larger than an icon (32x32 or whatever).

  • In *Activity A* save the file (Internal Storage)
String fileName = "SomeName.png";
try {
    FileOutputStream fileOutStream = openFileOutput(fileName, MODE_PRIVATE);
    fileOutStream.write(b);  //b is byte array 
                             //(used if you have your picture downloaded
                             // from the *Web* or got it from the *devices camera*)
                             //otherwise this technique is useless
    fileOutStream.close();
} catch (IOException ioe) {
    ioe.printStackTrace();
}
  • Pass location as String to Activity B
Intent intent = new Intent(this, ActivityB.class);
intent.putExtra("picname", fileName);
  • In *Activity B* retrieve the file
Bundle extras = getIntent().getExtras();
String fileName = extras.getString("picname");
  • Make *drawable* out of the picture
File filePath = getFileStreamPath(fileName);
Drawable d = Drawable.createFromPath(filePath.toString());
  • Apply it to the ImageView resource
someImageView.setBackgroundDrawable(d);
  • 1
    this is efficient with big images? And how I pass a Bitmap into a Bundle()? – android iPhone Dec 06 '11 at 23:17
  • @user548834 you do it as I have showed in the example - you decode it to byte array and attach byte array to intent, then retrieve it on the other side (another activity). It depends how big is the image, simple icon or something like a digital camera photo. If we are talking about photos, then saving as files is the better idea –  Dec 07 '11 at 00:13
  • This answer shows definitely HOW to serialize a bitmap and pass it as part of an intent. It doesn't answer WHY a programmer might want to avoid this. But this is definitely the answer. – Plastic Sturgeon Dec 07 '11 at 00:20
  • @Mocialov Boris - Awesome edit, thanks. To summarize: pass ONLY small images in intent. With larger images, pass by reference. Pass by reference works in all cases unless the intent is to be handled by a separate application. But there is probably a better solution using public device storage instead for that case. – Plastic Sturgeon Dec 07 '11 at 02:15
  • Where can I found an example of pass a large image by reference? – android iPhone Dec 07 '11 at 12:06
  • what is this openFileOutput(fileName, MODE_PRIVATE); Where is this method? – Zia Ur Rahman Sep 01 '17 at 19:07
  • cannot resolved this method openFileOutput(fileName, MODE_PRIVATE); – Zia Ur Rahman Sep 01 '17 at 19:21
  • 1
    @ZiaUrRahman `openFileOutput()` function resides in your activity's `Context`. Just do `myActivity.openFileOutput(...)` – tom_mai78101 Oct 02 '18 at 14:43
  • @tom_mai78101, yes great! I already have done, but thanks for your respond. – Zia Ur Rahman Oct 05 '18 at 16:33
4

You can tag each image (in the xml, or programmaticlly) with the image resource name (like "img1.png"), then retrieve the image name using the getTag();

Then use getResources().getIdentifier(image name,"drawable", .getPackageName()) to get the drawable resource id.

And just pass the resource id through the intent -

intent.putExtra("img 1",resource id);

Lastly the result Activity can create the image from the resource using:

getResources().getDrawable(intent.getIntExtra("img 1",-1));    
Ravi Dhoriya ツ
  • 4,435
  • 8
  • 37
  • 48
3

Drawable objects are not inherently serializable, so they cannot be passed directly in Intent extras. You must find another way to serialize or persist the image data and retrieve it in the new Activity.

For example, if you are working with BitmapDrawable instances, the underlying Bitmap could be written out to a file and read back, or serialized into a byte array (if its small enough) and the byte array could be passed via extras of an Intent.

HTH

devunwired
  • 62,780
  • 12
  • 127
  • 139
  • The file is definitely the better choice here, intent extras should be as small as possible due to [performance reasons](http://groups.google.com/group/android-developers/msg/e3f6be3a09d8a526). –  Dec 06 '11 at 22:31
  • How could Bitmap writte out to a file and read back?? The images are big so I need an an efficient solution. – android iPhone Dec 06 '11 at 23:13
  • `Bitmap.compress()` to write the data out to a file, and `BitmapFactory.decodeFile()` to read the data back into memory. `Bitmap.compress()` would also be used to write the data into a byte array...just a different type of `OutputStream`. If that's not fast enough, you will need to create a global memory location (static field in Application, perhaps) to store the information during the transition. Beware of static memory, though, and creating an unnecessary leak. – devunwired Dec 07 '11 at 20:10
  • By doing the first step the clarity decreases significantly any suggestion on how to improve that? – Mohammed Abid Nafi Mar 26 '21 at 18:14
2

Much much much better not to pass (or serialize) Drawables around among Activities. Very likely your are getting the drawable out of a resource. Hence there's a resource ID. Pass that around instead, that's just an int. And re-hydrate the Drawable in the other Activity.

If the Drawable is not coming from a resource, but it's built at runtime in memory ... well let's speak about it. @Devunwired has a nice suggestion in that case.

superjos
  • 12,189
  • 6
  • 89
  • 134
  • how to get resource id of another application icon?! – TheMMSH Aug 03 '16 at 10:31
  • 1
    The direct answer is *I don't know*. The indirect one is: I'm not sure you can do that and I'm not even sure it makes sense. I guess resource ID is primarily meaningful if you are in the context of same project source, the same application, so you have access to the same common resource embedded in APK. – superjos Aug 03 '16 at 16:01
1

You can simply use a native buildDrawingCache method:

    ImageView imageView = imageLayout.findViewById (R.id.img_thumb);
    imageView.buildDrawingCache ();

    Bundle extras = new Bundle ();
    extras.putParcelable ("image", imageView.getDrawingCache ());

    Intent intent = new Intent (this, ImageActivity.class);
    intent.putExtras (extras);

    startActivity (intent);

then get it at your ImageActivity:

    Bundle bundle = getIntent ().getExtras ();

    if (bundle != null) {

        ImageView imageView = findViewById (R.id.img_full);

        Bitmap image = bundle.getParcelable ("image");
        imageView.setImageBitmap (image);

    }
Acuna
  • 1,741
  • 17
  • 20
  • Deprecated as of API level 28. https://developer.android.com/reference/android/view/View.html#buildDrawingCache(boolean) – tom_mai78101 Oct 02 '18 at 13:30
0

I don't know if this is the case, but if the reason why you are trying to pass a drawable is because you are using an Imageview, just put the resource id in the imageview's tag, pass the tag as an Integer instead of the drawable in the intent's extra and use the following line in the receiving activity: imageView.setImageDrawable(getResources().getDrawable(getIntent().getIntExtra("image_id",0)));

Hope it will help someone.

Eran Katsav
  • 1,324
  • 15
  • 16
0

In case you pull those images from web and load them again and again, caching them would be really good option since you'll decrease network traffic and increase loading speed. I suggest using WebImageView from Droid-Fu. Really good solution, used it on some projects and I'm very satisfied with it.

vbokan
  • 133
  • 6