How can I pass a Bitmap object from one activity to another

前端 未结 10 921
隐瞒了意图╮
隐瞒了意图╮ 2020-11-22 03:39

In my activity, I create a Bitmap object and then I need to launch another Activity, How can I pass this Bitmap object from the sub-ac

相关标签:
10条回答
  • 2020-11-22 03:47

    Compress and Send Bitmap

    The accepted answer will crash when the Bitmap is too large. I believe it's a 1MB limit. The Bitmap must be compressed into a different file format such as a JPG represented by a ByteArray, then it can be safely passed via an Intent.

    Implementation

    The function is contained in a separate thread using Kotlin Coroutines because the Bitmap compression is chained after the Bitmap is created from an url String. The Bitmap creation requires a separate thread in order to avoid Application Not Responding (ANR) errors.

    Concepts Used

    • Kotlin Coroutines notes.
    • The Loading, Content, Error (LCE) pattern is used below. If interested you can learn more about it in this talk and video.
    • LiveData is used to return the data. I've compiled my favorite LiveData resource in these notes.
    • In Step 3, toBitmap() is a Kotlin extension function requiring that library to be added to the app dependencies.

    Code

    1. Compress Bitmap to JPG ByteArray after it has been created.

    Repository.kt

    suspend fun bitmapToByteArray(url: String) = withContext(Dispatchers.IO) {
        MutableLiveData<Lce<ContentResult.ContentBitmap>>().apply {
            postValue(Lce.Loading())
            postValue(Lce.Content(ContentResult.ContentBitmap(
                ByteArrayOutputStream().apply {
                    try {                     
                        BitmapFactory.decodeStream(URL(url).openConnection().apply {
                            doInput = true
                            connect()
                        }.getInputStream())
                    } catch (e: IOException) {
                       postValue(Lce.Error(ContentResult.ContentBitmap(ByteArray(0), "bitmapToByteArray error or null - ${e.localizedMessage}")))
                       null
                    }?.compress(CompressFormat.JPEG, BITMAP_COMPRESSION_QUALITY, this)
               }.toByteArray(), "")))
            }
        }
    

    ViewModel.kt

    //Calls bitmapToByteArray from the Repository
    private fun bitmapToByteArray(url: String) = liveData {
        emitSource(switchMap(repository.bitmapToByteArray(url)) { lce ->
            when (lce) {
                is Lce.Loading -> liveData {}
                is Lce.Content -> liveData {
                    emit(Event(ContentResult.ContentBitmap(lce.packet.image, lce.packet.errorMessage)))
                }
                is Lce.Error -> liveData {
                    Crashlytics.log(Log.WARN, LOG_TAG,
                            "bitmapToByteArray error or null - ${lce.packet.errorMessage}")
                }
            }
        })
    }
    

    2. Pass image as ByteArray via an Intent.

    In this sample it's passed from a Fragment to a Service. It's the same concept if being shared between two Activities.

    Fragment.kt

    ContextCompat.startForegroundService(
        context!!,
        Intent(context, AudioService::class.java).apply {
            action = CONTENT_SELECTED_ACTION
            putExtra(CONTENT_SELECTED_BITMAP_KEY, contentPlayer.image)
        })
    

    3. Convert ByteArray back to Bitmap.

    Utils.kt

    fun ByteArray.byteArrayToBitmap(context: Context) =
        run {
            BitmapFactory.decodeByteArray(this, BITMAP_OFFSET, size).run {
                if (this != null) this
                // In case the Bitmap loaded was empty or there is an error I have a default Bitmap to return.
                else AppCompatResources.getDrawable(context, ic_coinverse_48dp)?.toBitmap()
            }
        }
    
    0 讨论(0)
  • 2020-11-22 03:52

    You can create a bitmap transfer. try this....

    In the first class:

    1) Create:

    private static Bitmap bitmap_transfer;
    

    2) Create getter and setter

    public static Bitmap getBitmap_transfer() {
        return bitmap_transfer;
    }
    
    public static void setBitmap_transfer(Bitmap bitmap_transfer_param) {
        bitmap_transfer = bitmap_transfer_param;
    }
    

    3) Set the image:

    ImageView image = (ImageView) view.findViewById(R.id.image);
    image.buildDrawingCache();
    setBitmap_transfer(image.getDrawingCache());
    

    Then, in the second class:

    ImageView image2 = (ImageView) view.findViewById(R.id.img2);
    imagem2.setImageDrawable(new BitmapDrawable(getResources(), classe1.getBitmap_transfer()));
    
    0 讨论(0)
  • 2020-11-22 03:59

    All of the above solutions doesn't work for me, Sending bitmap as parceableByteArray also generates error android.os.TransactionTooLargeException: data parcel size.

    Solution

    1. Saved the bitmap in internal storage as:
    public String saveBitmap(Bitmap bitmap) {
            String fileName = "ImageName";//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;
        }
    
    1. and send in putExtra(String) as
    Intent intent = new Intent(ActivitySketcher.this,ActivityEditor.class);
    intent.putExtra("KEY", saveBitmap(bmp));
    startActivity(intent);
    
    1. and Receive it in other activity as:
    if(getIntent() != null){
      try {
               src = BitmapFactory.decodeStream(openFileInput("myImage"));
           } catch (FileNotFoundException e) {
                e.printStackTrace();
          }
    
     }
    
    
    
    0 讨论(0)
  • 2020-11-22 03:59

    In my case, the way mentioned above didn't worked for me. Every time I put the bitmap in the intent, the 2nd activity didn't start. The same happened when I passed the bitmap as byte[].

    I followed this link and it worked like a charme and very fast:

    package your.packagename
    
    import android.graphics.Bitmap;
    
    public class CommonResources { 
          public static Bitmap photoFinishBitmap = null;
    }
    

    in my 1st acitiviy:

    Constants.photoFinishBitmap = photoFinishBitmap;
    Intent intent = new Intent(mContext, ImageViewerActivity.class);
    startActivity(intent);
    

    and here is the onCreate() of my 2nd Activity:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bitmap photo = Constants.photoFinishBitmap;
        if (photo != null) {
            mViewHolder.imageViewerImage.setImageDrawable(new BitmapDrawable(getResources(), photo));
        }
    }
    
    0 讨论(0)
  • 2020-11-22 04:00

    Because Intent has size limit . I use public static object to do pass bitmap from service to broadcast ....

    public class ImageBox {
        public static Queue<Bitmap> mQ = new LinkedBlockingQueue<Bitmap>(); 
    }
    

    pass in my service

    private void downloadFile(final String url){
            mExecutorService.submit(new Runnable() {
                @Override
                public void run() {
                    Bitmap b = BitmapFromURL.getBitmapFromURL(url);
                    synchronized (this){
                        TaskCount--;
                    }
                    Intent i = new Intent(ACTION_ON_GET_IMAGE);
                    ImageBox.mQ.offer(b);
                    sendBroadcast(i);
                    if(TaskCount<=0)stopSelf();
                }
            });
        }
    

    My BroadcastReceiver

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
            public void onReceive(Context context, Intent intent) {
                LOG.d(TAG, "BroadcastReceiver get broadcast");
    
                String action = intent.getAction();
                if (DownLoadImageService.ACTION_ON_GET_IMAGE.equals(action)) {
                    Bitmap b = ImageBox.mQ.poll();
                    if(b==null)return;
                    if(mListener!=null)mListener.OnGetImage(b);
                }
            }
        };
    
    0 讨论(0)
  • 2020-11-22 04:01

    Bitmap implements Parcelable, so you could always pass it with the intent:

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

    and retrieve it on the other end:

    Intent intent = getIntent(); 
    Bitmap bitmap = (Bitmap) intent.getParcelableExtra("BitmapImage");
    
    0 讨论(0)
提交回复
热议问题