Come posso passare un oggetto Bitmap da un'attività all'altra
-
20-09-2019 - |
Domanda
Nella mia attività creo a Bitmap
object e quindi devo avviarne un altro Activity
, Come posso passare questo Bitmap
oggetto dalla sottoattività (quella che verrà lanciata)?
Soluzione
Bitmap
implementa Parcelable
, quindi si può sempre passare con l'intento:
Intent intent = new Intent(this, NewActivity.class);
intent.putExtra("BitmapImage", bitmap);
e recuperarlo sull'altra estremità:
Intent intent = getIntent();
Bitmap bitmap = (Bitmap) intent.getParcelableExtra("BitmapImage");
Altri suggerimenti
In realtà, il superamento di un bitmap come Parcelable si tradurrà in un errore "JAVA BINDER GUASTO". Prova a passare il bitmap come matrice di byte e la costruzione per la visualizzazione dell'attività successiva.
Ho condiviso la mia soluzione qui:
come si fa a passare le immagini ( bitmap) tra le attività Android utilizzando fasci?
Passare la bitmap come parceable in bundle tra un'attività e l'altra non è una buona idea a causa della limitazione delle dimensioni di Parceable(1mb).È possibile archiviare la bitmap in un file nella memoria interna e recuperare la bitmap archiviata in diverse attività.Ecco del codice di esempio.
Per memorizzare bitmap in un file miaimmagine nella memoria interna:
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;
}
Quindi nell'attività successiva puoi decodificare questo file myImage in una bitmap utilizzando il seguente codice:
//here context can be anything like getActivity() for fragment, this or MainActivity.this
Bitmap bitmap = BitmapFactory.decodeStream(context.openFileInput("myImage"));
Nota Molti controlli per bitmap nulli e di ridimensionamento vengono omessi.
Se l'immagine è troppo grande e non è possibile salvare e caricarlo per l'archiviazione, si dovrebbe prendere in considerazione solo con un riferimento globale statico al bitmap (all'interno l'attività di ricezione), che sarà riportato a NULL in onDestory, solo se "isChangingConfigurations" restituisce true.
Perché Intent ha limite di dimensione. Io uso oggetto statico pubblico di fare passare bitmap dal servizio per trasmettere ....
public class ImageBox {
public static Queue<Bitmap> mQ = new LinkedBlockingQueue<Bitmap>();
}
passaggio nel mio servizio
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();
}
});
}
Il mio 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);
}
}
};
Comprimi e invia Bitmap
La risposta accettata si bloccherà quando il file Bitmap
è troppo grande. Credo che sia un 1 MB limite.IL Bitmap
deve essere compresso in un formato di file diverso come a JPG rappresentato da a ByteArray
, quindi può essere passato in sicurezza tramite un file Intent
.
Implementazione
La funzione è contenuta in un thread separato utilizzando Coroutine di Kotlin perché il Bitmap
la compressione è concatenata dopo il Bitmap
viene creato da un URL String
.IL Bitmap
la creazione richiede un thread separato per evitare L'applicazione non risponde (ANR) errori.
Concetti utilizzati
- Coroutine di Kotlin Appunti.
- IL Caricamento, contenuto, errore (LCE) il modello è utilizzato di seguito.Se sei interessato puoi saperne di più in questo discorso e questo video.
- LiveData viene utilizzato per restituire i dati.Ho compilato il mio preferito LiveData risorsa dentro queste note.
- In Passaggio 3,
toBitmap()
è un Funzione di estensione Kotlin richiedendo che la libreria venga aggiunta alle dipendenze dell'app.
Codice
1.Comprimere Bitmap
A JPG ByteArray
dopo che è stato creato.
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.Passa l'immagine come ByteArray
tramite un Intent
.
In questo campione è passato da a Frammento ad a Servizio.È lo stesso concetto se condiviso tra due Attività.
Frammento.kt
ContextCompat.startForegroundService(
context!!,
Intent(context, AudioService::class.java).apply {
action = CONTENT_SELECTED_ACTION
putExtra(CONTENT_SELECTED_BITMAP_KEY, contentPlayer.image)
})
3.Convertire ByteArray
tornare a Bitmap
.
Utilis.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()
}
}
Potrebbe essere in ritardo, ma può aiutare. Sul primo frammento o attività fare dichiarare una classe ... per esempio
@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;
}
Poi sulla seconda classe / frammento fare questo ..
Bitmap bm = postFragment.constan.photoMap;
final String itemName = postFragment.constan.namePass;
Speranza che aiuta.
È possibile creare un trasferimento bitmap. provare questo ....
Nella prima classe:
1) Creazione:
private static Bitmap bitmap_transfer;
2) Creare getter e setter
public static Bitmap getBitmap_transfer() {
return bitmap_transfer;
}
public static void setBitmap_transfer(Bitmap bitmap_transfer_param) {
bitmap_transfer = bitmap_transfer_param;
}
3) Impostare l'immagine:
ImageView image = (ImageView) view.findViewById(R.id.image);
image.buildDrawingCache();
setBitmap_transfer(image.getDrawingCache());
Poi, nella seconda classe:
ImageView image2 = (ImageView) view.findViewById(R.id.img2);
imagem2.setImageDrawable(new BitmapDrawable(getResources(), classe1.getBitmap_transfer()));
Tutte le soluzioni di cui sopra non funziona per me, invio bitmap come parceableByteArray
genera anche android.os.TransactionTooLargeException: data parcel size
errore.
Soluzione
- salvata l'immagine bitmap nella memoria interna come:
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;
}
- e inviare in
putExtra(String)
come
Intent intent = new Intent(ActivitySketcher.this,ActivityEditor.class);
intent.putExtra("KEY", saveBitmap(bmp));
startActivity(intent);
- e ricevilo in altre attività come:
if(getIntent() != null){
try {
src = BitmapFactory.decodeStream(openFileInput("myImage"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
Nel mio caso, il modo di cui sopra non ha funzionato per me. Ogni volta che ho messo la bitmap nell'intento, il 2 ° di attività non è stato avviato. Lo stesso è accaduto quando ho passato la bitmap come byte [].
Ho seguito questo link e ha funzionato come un fascino e molto veloce:
package your.packagename
import android.graphics.Bitmap;
public class CommonResources {
public static Bitmap photoFinishBitmap = null;
}
nel mio primo acitiviy:
Constants.photoFinishBitmap = photoFinishBitmap;
Intent intent = new Intent(mContext, ImageViewerActivity.class);
startActivity(intent);
e qui è l'onCreate () della mia seconda attività:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bitmap photo = Constants.photoFinishBitmap;
if (photo != null) {
mViewHolder.imageViewerImage.setImageDrawable(new BitmapDrawable(getResources(), photo));
}
}