Risposte:
Bitmap
implementa Parcelable
, quindi puoi sempre passarlo con l'intento:
Intent intent = new Intent(this, NewActivity.class);
intent.putExtra("BitmapImage", bitmap);
e recuperarlo dall'altra parte:
Intent intent = getIntent();
Bitmap bitmap = (Bitmap) intent.getParcelableExtra("BitmapImage");
In realtà, il passaggio di una bitmap come Parcelable comporterà un errore "JAVA BINDER FAILURE". Prova a passare la bitmap come array di byte e crearla per la visualizzazione nella prossima attività.
Ho condiviso la mia soluzione qui:
come si passano le immagini (bitmap) tra le attività Android utilizzando i bundle?
Passare bitmap come paragonabile in bundle tra attività 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 memorizzata in diverse attività. Ecco un po 'di codice di esempio.
Per memorizzare bitmap in un file myImage 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 nella prossima attività puoi decodificare questo file myImage in una bitmap usando il seguente codice:
//here context can be anything like getActivity() for fragment, this or MainActivity.this
Bitmap bitmap = BitmapFactory.decodeStream(context.openFileInput("myImage"));
Nota Un sacco di controllo per null e scalare bitmap è ommited.
openFileOutput
.
Se l'immagine è troppo grande e non puoi salvarla e caricarla nella memoria, dovresti considerare di utilizzare solo un riferimento statico globale alla bitmap (all'interno dell'attività di ricezione), che verrà reimpostata su null su onDestory, solo se "isChangingConfigurations" ritorna vero.
Perché Intent ha un limite di dimensioni. Uso un oggetto statico pubblico per passare bitmap dal servizio alla trasmissione ....
public class ImageBox {
public static Queue<Bitmap> mQ = new LinkedBlockingQueue<Bitmap>();
}
passare al 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();
}
});
}
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);
}
}
};
Bitmap
La risposta accettata si bloccherà quando Bitmap
è troppo grande. Credo che sia un limite di 1 MB . Il Bitmap
devono essere compressi in un formato di file diverso, ad esempio un JPG rappresentato da una ByteArray
, allora può essere passato in modo sicuro tramite una Intent
.
La funzione è contenuta in un thread separato usando Coroutine di Kotlin perché la Bitmap
compressione è concatenata dopo la Bitmap
creazione da un url String
. La Bitmap
creazione richiede un thread separato per evitare errori ANR (Application Not Responding) .
toBitmap()
è una funzione di estensione Kotlin che richiede che la libreria venga aggiunta alle dipendenze dell'app.Bitmap
in 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}")
}
}
})
}
ByteArray
tramite un Intent
.In questo esempio viene passato da un frammento a un servizio . È lo stesso concetto se condiviso tra due attività .
Fragment.kt
ContextCompat.startForegroundService(
context!!,
Intent(context, AudioService::class.java).apply {
action = CONTENT_SELECTED_ACTION
putExtra(CONTENT_SELECTED_BITMAP_KEY, contentPlayer.image)
})
ByteArray
nuovamente in 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()
}
}
Potrebbe essere tardi, ma può aiutare. Sul primo frammento o attività 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;
}
Quindi sulla seconda classe / frammento fare questo ..
Bitmap bm = postFragment.constan.photoMap;
final String itemName = postFragment.constan.namePass;
Spero che sia d'aiuto.
Tutte le soluzioni di cui sopra non funzionano per me, l'invio di bitmap in quanto parceableByteArray
genera anche errori android.os.TransactionTooLargeException: data parcel size
.
Soluzione
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;
}
putExtra(String)
comeIntent intent = new Intent(ActivitySketcher.this,ActivityEditor.class);
intent.putExtra("KEY", saveBitmap(bmp));
startActivity(intent);
if(getIntent() != null){
try {
src = BitmapFactory.decodeStream(openFileInput("myImage"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
È possibile creare un trasferimento bitmap. prova questo....
Nella prima classe:
1) Creare:
private static Bitmap bitmap_transfer;
2) Crea 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) Imposta l'immagine:
ImageView image = (ImageView) view.findViewById(R.id.image);
image.buildDrawingCache();
setBitmap_transfer(image.getDrawingCache());
Quindi, nella seconda classe:
ImageView image2 = (ImageView) view.findViewById(R.id.img2);
imagem2.setImageDrawable(new BitmapDrawable(getResources(), classe1.getBitmap_transfer()));
Nel mio caso, il modo sopra menzionato non ha funzionato per me. Ogni volta che ho messo la bitmap nell'intento, la seconda attività non è iniziata. Lo stesso è accaduto quando ho passato la bitmap come byte [].
Ho seguito questo link e ha funzionato come un incantesimo e molto velocemente:
package your.packagename
import android.graphics.Bitmap;
public class CommonResources {
public static Bitmap photoFinishBitmap = null;
}
nella mia prima azione:
Constants.photoFinishBitmap = photoFinishBitmap;
Intent intent = new Intent(mContext, ImageViewerActivity.class);
startActivity(intent);
ed ecco 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));
}
}
CommonResources.photoFinishBitmap
posto di Constants.photoFinishBitmap
.
URI
oResourceID
della bitmap e non la bitmap stessa. Il passaggio dell'intera bitmap richiede molta memoria. Il passaggio dell'URL richiede pochissima memoria e consente a ciascuna attività di caricare e ridimensionare la bitmap quando necessario.