Bir Bitmap nesnesini bir etkinlikten diğerine nasıl geçirebilirim


146

Etkinliğimde, bir Bitmapnesne oluşturuyorum ve sonra başka bir başlatmam gerekiyor Activity, Bu Bitmapnesneyi alt aktiviteden (başlatılacak olandan) nasıl geçirebilirim ?

Yanıtlar:


297

Bitmapuygular Parcelable, böylece her zaman niyetle geçebilirsiniz:

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

ve diğer ucundan alın:

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

85
Bitmap bir dosya veya kaynak olarak varsa , bitmap'in kendisini değil, bitmap'i URIveya ResourceIDbitmap'i iletmek her zaman daha iyidir . Tüm bitmap'i geçmek çok fazla bellek gerektirir. URL'yi iletmek çok az bellek gerektirir ve her etkinliğin bitmap'i ihtiyaç duydukları şekilde yüklemesine ve ölçeklendirmesine izin verir.
slayton

3
Benim için çalışmıyor, ancak bu işe yarıyor: stackoverflow.com/questions/11010386/…
Houssem

1
@slayton görüntüleri URI / ResourceID olarak nasıl iletiriz? misal? Teşekkürler!
WantIt

bitmap'i bu şekilde ekstra koymak, bitmap nesne boyutu daha büyükse, "java.lang.SecurityException: arayan android.app.ApplicationThreadProxy ......" için uygulama bulunamıyor. Önerilen yol, @slayton'un dediği gibi, harici depolama alanında bitmap'i kaydetmeniz ve sadece URI'yi geçirmeniz gerektiği gibi.
AITAALI_ABDERRAHMANE

1
iletilebilen maksimum bitmap boyutu nedir?
AtifSayings


17

Bit eşlemin, etkinlik arasında paket halinde ayrıştırılabilir olarak geçirilmesi, Parceable (1mb) boyut sınırlaması nedeniyle iyi bir fikir değildir. Bitmap'i dahili depolama alanındaki bir dosyada saklayabilir ve saklanan bitmap'i çeşitli etkinliklerde alabilirsiniz. İşte bazı örnek kod.

Bitmap'i dahili depolama birimindeki myImage dosyasında saklamak için:

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

Sonra bir sonraki aktivitede bu dosyayı myImage kodunu bir bitmap'e şu kodu kullanarak çözebilirsiniz:

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

Not Null ve ölçeklendirme bitmap'leri için çok fazla denetim önerilir.


Bu derlenmeyecektir - yöntem çözülemez openFileOutput.
Hawklike

4

Görüntü çok büyükse ve depoya kaydedip yükleyemiyorsanız, yalnızca bitmap'e (alıcı etkinliğin içinde) genel statik bir referans kullanmayı düşünmelisiniz; true değerini döndürür.


3

Çünkü niyetin boyut sınırı vardır. Ben hizmetten yayın bit eşlem geçmek için genel statik nesne kullanın ....

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

servisime geç

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'ım

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

Sıkıştır ve Gönder Bitmap

Kabul edilen cevap Bitmapçok büyük olduğunda kilitlenir . 1 MB'lık bir sınır olduğuna inanıyorum . Bu Bitmap, a ile temsil edilen bir JPG gibi farklı bir dosya biçiminde sıkıştırılmalıdır ByteArray, daha sonra birIntent .

uygulama

Bu işlev, bir url'den oluşturulduktan sonra sıkıştırma zincirlendiğinden , Kotlin Coroutines kullanan ayrı bir iş parçacığında bulunur . Engellenmesi için ayrı bir iş parçacığı gerektirmektedir Yanıt vermeyen uygulama (ANR)BitmapBitmapStringBitmap hataları.

Kullanılan Kavramlar

  • Kotlin Coroutines notları .
  • Yükleme, İçerik, Hata (LCE) deseni aşağıda kullanılır. İlgileniyorsanız, bu konuşma ve videoda daha fazla bilgi edinebilirsiniz .
  • LiveData verileri döndürmek için kullanılır. En sevdiğim LiveData kaynağımı bu notlarda derledim .
  • Olarak Aşama 3 , toBitmap()a, Kotlin uzantı işlevi bu kütüphane gerektiren uygulama bağımlılıkları eklenecek.

kod

1. sıkıştır Bitmapiçin JPG ByteArray oluşturulduktan sonra.

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. ByteArrayBir Intent.

Bu örnekte, bir den geçirilen Fragment a Service . İki Faaliyet arasında paylaşılıyorsa aynı kavram .

Fragment.kt

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

3. 'e ByteArraygeri dönün 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

Geç olabilir ama yardımcı olabilir. İlk parçada veya aktivitede bir sınıf beyan edin ... örneğin

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

Sonra ikinci sınıfta / parçada bunu yapın ..

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

Umarım yardımcı olur.


1

Yukarıdaki çözümlerin hepsi benim için çalışmıyor, Bitmap gönderme aynı parceableByteArrayzamanda hata veriyorandroid.os.TransactionTooLargeException: data parcel size .

Çözüm

  1. Dahili depolamadaki bitmap'i şu şekilde kaydetti:
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. ve göndermek putExtra(String)olarak
Intent intent = new Intent(ActivitySketcher.this,ActivityEditor.class);
intent.putExtra("KEY", saveBitmap(bmp));
startActivity(intent);
  1. ve diğer etkinliklerde şu şekilde alın:
if(getIntent() != null){
  try {
           src = BitmapFactory.decodeStream(openFileInput("myImage"));
       } catch (FileNotFoundException e) {
            e.printStackTrace();
      }

 }


0

Bir bitmap aktarımı oluşturabilirsiniz. bunu dene....

Birinci sınıfta:

1) Oluşturun:

private static Bitmap bitmap_transfer;

2) Alıcı ve ayarlayıcı oluşturma

public static Bitmap getBitmap_transfer() {
    return bitmap_transfer;
}

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

3) Görüntüyü ayarlayın:

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

Sonra, ikinci sınıfta:

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

-2

Benim durumumda, yukarıda belirtilen yol benim için işe yaramadı. Bitmap'i her ne zaman niyetime koyduğumda 2. etkinlik başlamadı. Aynı şey bitmap'i bayt [] olarak geçtiğimde de oldu.

Bu bağlantıyı takip ettim ve bir charme gibi çalıştı ve çok hızlı:

package your.packagename

import android.graphics.Bitmap;

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

benim 1. etkinliğimde:

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

ve işte 2. Etkinliğimin onCreate () yöntemi:

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

Bunu denedim, işe yaramadı. Bağlantıyı izledim ve bunun CommonResources.photoFinishBitmapyerine kullanmanız gerektiği anlaşılıyor Constants.photoFinishBitmap.
Nathan Hutton

Kötü uygulama. Tüm sürecin yeniden oluşturulması sırasında Activity sınıfındaki statik alanla ne olur (örneğin, çalışma zamanında uygulama için izinlerin değiştirilmesi nedeniyle)? Cevap NPE.
Alexander
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.