Bagaimana saya bisa meneruskan objek Bitmap dari satu aktivitas ke aktivitas lainnya


145

Dalam aktivitas saya, saya membuat Bitmapobjek dan kemudian saya harus meluncurkan yang lain Activity, Bagaimana saya bisa melewatkan Bitmapobjek ini dari sub-aktivitas (yang akan diluncurkan)?

Jawaban:


297

Bitmapmengimplementasikan Parcelable, sehingga Anda selalu bisa melewatinya dengan maksud:

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

dan mengambilnya di ujung yang lain:

Intent intent = getIntent(); 
Bitmap bitmap = (Bitmap) intent.getParcelableExtra("BitmapImage");

84
Jika bitmap ada sebagai file atau sumber daya, yang selalu lebih baik untuk lulus URIatau ResourceIDbitmap dan bukan bitmap itu sendiri. Melewati seluruh bitmap membutuhkan banyak memori. Melewati URL membutuhkan sedikit memori dan memungkinkan setiap aktivitas memuat dan menskalakan bitmap sesuai kebutuhan.
slayton

3
Tidak berfungsi untuk saya, tetapi yang ini berfungsi: stackoverflow.com/questions/11010386/…
Houssem

1
@slayton bagaimana cara mengirimkan gambar sebagai URI / ResourceIDs? contoh? Terima kasih!
WantIt

menempatkan bitmap pada ekstra seperti itu, bukan praktik terbaik, jika ukuran objek bitmap lebih besar, maka Anda mendapatkan "java.lang.SecurityException: Tidak dapat menemukan aplikasi untuk pemanggil android.app.ApplicationThreadProxy ......". cara yang disarankan adalah seperti yang dikatakan @slayton, Anda harus menyimpan bitmap pada penyimpanan eksternal dan hanya melewati URI.
AITAALI_ABDERRAHMANE

1
Berapa ukuran maksimum bitmap yang bisa dilewati?
AtifSayings


16

Melewati bitmap sebagai parceable dalam bundel di antara aktivitas bukanlah ide yang baik karena batasan ukuran Parceable (1mb). Anda dapat menyimpan bitmap dalam file di penyimpanan internal dan mengambil bitmap yang disimpan dalam beberapa aktivitas. Ini beberapa contoh kode.

Untuk menyimpan bitmap dalam file myImage di penyimpanan internal:

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;
}

Kemudian pada aktivitas selanjutnya Anda dapat mendekode file myImage ke bitmap menggunakan kode berikut:

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

Catatan Banyak memeriksa null dan menskalakan bitmap dihentikan.


Ini tidak dapat dikompilasi - tidak dapat menyelesaikan metode openFileOutput.
Elang seperti

4

Jika gambar terlalu besar dan Anda tidak dapat menyimpan & memuatnya ke penyimpanan, Anda harus mempertimbangkan hanya menggunakan referensi statis global ke bitmap (di dalam aktivitas penerima), yang akan diatur ulang ke nol pada onDestory, hanya jika "isChangingConfigurations" mengembalikan true.


3

Karena Intent memiliki batas ukuran. Saya menggunakan objek statis publik untuk melakukan pass bitmap dari layanan ke siaran ....

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

lulus dalam layanan saya

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();
            }
        });
    }

BroadcastReceiver saya

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);
            }
        }
    };

2

Kompres dan Kirim Bitmap

Jawaban yang diterima akan macet ketika Bitmapterlalu besar. Saya percaya ini adalah batas 1MB . The Bitmapharus dikompresi ke dalam format file yang berbeda seperti JPG diwakili oleh ByteArray, maka dapat dengan aman melewati melaluiIntent .

Penerapan

Fungsi ini terkandung dalam utas terpisah menggunakan Kotlin Coroutines karena Bitmapkompresi dirantai setelah Bitmapdibuat dari url String. The Bitmappenciptaan membutuhkan thread terpisah untuk menghindari Aplikasi Tidak Menanggapi (PPA) kesalahan.

Konsep yang Digunakan

  • Catatan Kotlin Coroutines .
  • Pola Memuat, Konten, Kesalahan (LCE) digunakan di bawah ini. Jika tertarik, Anda dapat mempelajari lebih lanjut tentang hal ini dalam pembicaraan dan video ini .
  • LiveData digunakan untuk mengembalikan data. Saya telah mengumpulkan sumber daya LiveData favorit saya di catatan ini .
  • Pada Langkah 3 , toBitmap()adalah fungsi ekstensi Kotlin yang membutuhkan pustaka yang akan ditambahkan ke dependensi aplikasi.

Kode

1. Kompres Bitmapke JPG ByteArray setelah itu dibuat.

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(), "")))
        }
    }

LihatModel.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. Lulus gambar ByteArraymelalui Intent.

Dalam sampel ini, ini diteruskan dari Fragmen ke Layanan . Itu adalah konsep yang sama jika dibagikan di antara dua Kegiatan .

Fragment.kt

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

3. Konversi ByteArraykembali ke 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()
        }
    }

1

Mungkin terlambat tetapi bisa membantu. Pada fragmen atau aktivitas pertama, deklarasikan sebuah kelas ... misalnya

   @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        description des = new description();

        if (requestCode == PICK_IMAGE_REQUEST && data != null && data.getData() != null) {
            filePath = data.getData();
            try {
                bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), filePath);
                imageView.setImageBitmap(bitmap);
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
                constan.photoMap = bitmap;
            } catch (IOException e) {
                e.printStackTrace();
            }
       }
    }

public static class constan {
    public static Bitmap photoMap = null;
    public static String namePass = null;
}

Kemudian pada kelas kedua / fragmen lakukan ini ..

Bitmap bm = postFragment.constan.photoMap;
final String itemName = postFragment.constan.namePass;

Semoga ini bisa membantu.


1

Semua solusi di atas tidak bekerja untuk saya, Mengirim bitmap parceableByteArrayjuga menghasilkan kesalahan android.os.TransactionTooLargeException: data parcel size.

Larutan

  1. Menyimpan bitmap dalam penyimpanan internal sebagai:
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. dan kirim putExtra(String)sebagai
Intent intent = new Intent(ActivitySketcher.this,ActivityEditor.class);
intent.putExtra("KEY", saveBitmap(bmp));
startActivity(intent);
  1. dan Terima dalam aktivitas lain seperti:
if(getIntent() != null){
  try {
           src = BitmapFactory.decodeStream(openFileInput("myImage"));
       } catch (FileNotFoundException e) {
            e.printStackTrace();
      }

 }


0

Anda dapat membuat transfer bitmap. coba ini....

Di kelas pertama:

1) Buat:

private static Bitmap bitmap_transfer;

2) Buat pengambil dan penyetel

public static Bitmap getBitmap_transfer() {
    return bitmap_transfer;
}

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

3) Atur gambar:

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

Kemudian, di kelas kedua:

ImageView image2 = (ImageView) view.findViewById(R.id.img2);
imagem2.setImageDrawable(new BitmapDrawable(getResources(), classe1.getBitmap_transfer()));

-2

Dalam kasus saya, cara yang disebutkan di atas tidak berhasil untuk saya. Setiap kali saya menaruh bitmap dalam maksud, aktivitas ke-2 tidak dimulai. Hal yang sama terjadi ketika saya melewati bitmap sebagai byte [].

Saya mengikuti tautan ini dan itu bekerja seperti pesona dan sangat cepat:

package your.packagename

import android.graphics.Bitmap;

public class CommonResources { 
      public static Bitmap photoFinishBitmap = null;
}

dalam kegiatan pertama saya:

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

dan ini adalah onCreate () dari Aktivitas ke-2 saya:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Bitmap photo = Constants.photoFinishBitmap;
    if (photo != null) {
        mViewHolder.imageViewerImage.setImageDrawable(new BitmapDrawable(getResources(), photo));
    }
}

Saya mencoba ini, tidak berhasil. Aku mengikuti link, dan tampaknya Anda harus menggunakan CommonResources.photoFinishBitmapbukan Constants.photoFinishBitmap.
Nathan Hutton

Latihan yang buruk. Apa yang akan terjadi dengan bidang statis di kelas Activity selama rekreasi seluruh proses (misalnya, karena mengubah izin untuk aplikasi saat runtime)? Jawabannya adalah NPE.
Alexander
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.