This is more of a design question. I have a MasterActivity showing a not-so-little preview of an image, and a DetailActivity that should show the image in fullscreen.
Picture is retrieved from server using parse.com services and assigned to ParseImageViews, namely view.setParseFile(file); view.loadInBackground(). Average size is approx. 800x1000px: thus picture is scaled down in master activity, bigger in detail. In both cases I refer to the same 800x1000px file on the backend. Downloading takes some 2s. I do not want to store smaller sizes.
When the user taps a button, I need to pass this Bitmap (ParseFile, objectId, whatever) to DetailActivity, if it was loaded into theMasterActivity.
Option1: Parcelable through Intent
Issue: Binder Transaction Failed
Intent i = new Intent(this, DetailActivity.class);
Bitmap b = ((BitmapDrawable) picture.getDrawable()).getBitmap();
i.putExtra("bitmap", b);
startActivity(i);
Doesn't work, getting Binder Transaction Failed!. It is well documented here on SO (example) that you can't pass objects larger than 1MB (more or less) like that.
Option2: byte[] through Intent
Issue: Binder Transaction Failed
ByteArrayOutputStream stream = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bytes = stream.toByteArray();
i.putExtra("bitmap", bytes);
As suggested elsewhere I tried to compress the bitmap, but I'm getting the same size error. To avoid transaction limit here I should drop the quality down to 50 or so, and the result is not good to see.
Option3: download the file again in DetailActivity.onCreate()
Issue: OutOfMemoryError
This was a promising option, but didn't work, throwing OOM. My debug opinion is that:
I download the image in MasterActivity;
I launch DetailActivity, while master is still in the backstack;
I download a second instance of the picture, thus going OOM.
I'm stuck at this point. What can I do? If both activities could share the same Bitmap instance, I could avoid OOM.
Related
I have searched online for a tutorial on how to send a bitmap data over to another activity using the putExtra() method in kotlin, but nothing seems to pop up. I do not know how to code in java so all the tutorials and stack overflow threads that talk about converting to a byte array do not help much. Can someone please help me with maybe a solution?
What I did so far (My project is in no regards to this post) is I saved a image using my camera as a bitmap using the code:
val thumbnail : Bitmap = data!!.extras!!.get("data") as Bitmap
(the key word "data" is a intent inside the upper override function (onActivityResult))
This saves a bitmap of the image I took with the camera and now I tried to send it over, using the putExtra() command as so:
var screenSwitch2 = Intent(this#MainActivity,mlscreen::class.java)
screenSwitch2.putExtra("bitmap", thumbnail)
On the other screen "mlscreen" I tried to recover the data using a intent.getStringExtra("bitmap")
val thumbnail = intent.getStringExtra("bitmap")
and then I set my image view in the "mlscreen" using the setImageBitmap method as here:
iv_image.setImageBitmap(thumbnail)
I got the error that I was looking for a bitmap data and not a string data for the method. I knew this would occur though because I had to use intent.getSTRINGExtra which would mean its converting it to a string I presume.
Any help with this would be appreciated! Thanks.
There are 3 ways to do that :
1 - Using Intent (not recommended)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
thumbnail.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
intent.putExtra("image", b);
startActivity(intent);
2 - Using static (not recommended)
public static Bitmap thumbnail;
3 - Using Path (recommended)
Save your Bitmap as an image file in specific folder (make it invisible to the users).
Get the path from the saved file.
Use intent.putExtrat("imagePath",path);.
Use BitmapFactory.decodeFile(filePath); to get the Bitmap from the path.
Remove the path.
I want to pass my image from one Activity to another. At first I tried to do this with a base64 String of my image. But this only works for small pictures. It worked with 400 kb but not with 600 kb. Is there a better way to do this? By the way, I don't save the image locally, I get the image from a server, so I don't have a real Drawable.
If you only have the remote URL, then you can directly share it, otherwise you can save the image in the local media store and then share its local URL. Something like:
Bitmap bitmap = ...
String path = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "Image Description", null);
Uri uri = Uri.parse(path);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(intent, "Share Image"));
Even though it is a bit discouraged to pass large "blocks" of data through intents in android (use a singleton or store the image on the internal memory, etc), you can achieve it by doing :
1 - On your Sender Activity
Intent yourIntent = new Intent(YourActivity.this, DestinationActivity.class);
Bitmap bmp; // store the image in your bitmap
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 50, baos);
yourIntent.putExtra("yourImage", baos.toByteArray());
startActivity(yourIntent);
2 - On your Receiver Activity
// parse the intent onCreate()
if(getIntent().hasExtra("yourImage")) {
ImageView iv = new ImageView(this);
Bitmap bmp = BitmapFactory.decodeByteArray(getIntent().getByteArrayExtra("yourImage"), 0, getIntent().getByteArrayExtra("yourImage").length);
iv.setImageBitmap(bmp);
}
It is strongly discouraged that you do it this way because :
1 - There is a memory limit to the passing of data through an intent.
The maximum amount of data you can transfer using an Intent is 500KB (tested on API 10, 16, 19 and 23). check this external reference
Sometimes, the bitmap might be too large for processing, thus leading to OOM (I have experienced this in the past) or cause a bad UI experience.
2 - If your activity crashes by any reason, thus leading to a crash on the application, you will lose the image because it is stored in temporary memory. If you save it internally, you can persist the image even if the application crashes.
General the best practice is to process the image when you need it, store it on a device folder (can be internal or external memory) and later when you need it retrieve it again for more processing. This way you avoid unnecessary memory allocation throughout the application.
Also, you can use third-party libraries like Picasso or Glide. I personally like Glide as it is better in performance than any other.
I have been going crazy with this android error and from browsing the previous posts about this error none of the solutions that were given helped me.
I am of course talking about the all powerful killer known as the 'android Out of memory on a (NUMBER)-byte allocation.' I am trying to create a photo uploader and after the 3rd maybe 4th image my app crashes. I know to stop the crash to use a catch exception however that is not my problem. I am here to ask the community is there any solution to fixing this byte allocation error ?
Here is a snippet of my code involving the bit map .
String post = editTextPost.getText().toString().trim();
// get the photo :
Bitmap image = ((BitmapDrawable)postImage.getDrawable()).getBitmap();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// compress the image to jpg format :
image.compress(Bitmap.CompressFormat.JPEG, 45, byteArrayOutputStream);
byte[] imageBytes = byteArrayOutputStream.toByteArray();
String encodeImage = Base64.encodeToString(imageBytes,Base64.DEFAULT);
// Recycle bitmap :
image.recycle();
image=null;
// send data :
sendPost p = new sendPost(this);
p.execute(post, encodeImage);
imageBytes=null;
Im not using any libraries and would like to keep it that way however if using a library is the only option I will use one. Hopefully someone can help.
Bitmaps won't completely recycle if they are attached to a View, for example to a ImageView, if you do imageView.setImageBitmap(bitmap), you need to clear it before doing imageView.setImageBitmap(null) and clearing any other reference to any view.
After you finish uplloading the image release the memory occupied by the "postImage" -
postImage.setImageDrawable(null);
This will release any memory occupied by the bitmap associated with postImage
General Answer:
When you upload files you need to open a stream to your server and to
your file at same time. read and write chunk by chunk of 1 MB for
example. this way you will not get an out of memory exception.
I use the following code to obtain a bitmap from an ImageView. This image is not saved anywhere else on my device. I want to upload this image into an online mysqli database. However, to do so I need to decrease the size of the file first. I found a lot of links about this, however they all require the file to be saved on the device and then use FileOutputStream. I am looking for a way to reduce the file size so that it can be comfortably transferred using the Volley API ( i am currently receiving either run out of memory exceptions or broken pipe errors). Hence I am looking for a way to modify this code to be able to significantly decrease the file size, whilst still maintaining a quality which can be comfortably shown on a mobile device. The original image is taken straight from the camera hence the size is quite large. Here is my code:
ImageView pic_holder = (ImageView) findViewById(R.id.picturedisplay);
Bitmap bitmap = ((BitmapDrawable)pic_holder.getDrawable()).getBitmap();
ByteArrayOutputStream stream=new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream);
byte[] image=stream.toByteArray();
String img_str = Base64.encodeToString(image, 0);
I would like to decrease the size of the img_str which is passed to my Volley method.
Simply put I need to capture image using camera and upload it to facebook via my android application. And I successfully did that. The problem is when the photo posted in facebook, it's just too small and in low resolution while the image I took is in high resolution.
I understand that: in order to upload to facebook, i need to convert the captured image which is in bitmap format into byte array. So i have method for that:
public static byte[] convertBitmapToByteArray(Bitmap bm){
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bm.compress(CompressFormat.PNG, 100, bos);
byte[] bitmapdata = bos.toByteArray();
return bitmapdata;
}
Then to upload the image to facebook, i have code below where byteData is byte array I converted from bitmap image using the method above.
parameters.putString("message", "Test");
parameters.putByteArray("source", byteData);
String facebookResponse = facebookInstance.request(albumId+"/photos",parameters,"POST");
return facebookResponse;
I am pretty sure the problem is my convertBitmapToByteArray method since the method is to compress the bitmap image and turn it into byte array, and this made my image into low resolution image. However I can't seem to find the way to upload the image without converting it into byte array first. Any solution for me?
Alright even this thread is old, i found out the answer. It's not the problem of CompressFormant.JPEG or CompressFormat.JPG. Simply put, intent in android isn't designed to carry big data like image from activity through activity. I need to save the image from intent to sd card first before able to pull it out from there. It's my solution.