Réponses:
Bitmap
implémente Parcelable
, de sorte que vous puissiez toujours le transmettre avec l'intention:
Intent intent = new Intent(this, NewActivity.class);
intent.putExtra("BitmapImage", bitmap);
et récupérez-le à l'autre bout:
Intent intent = getIntent();
Bitmap bitmap = (Bitmap) intent.getParcelableExtra("BitmapImage");
En fait, passer un bitmap en tant que Parcelable entraînera une erreur "JAVA BINDER FAILURE". Essayez de transmettre le bitmap sous forme de tableau d'octets et de le construire pour l'afficher dans l'activité suivante.
J'ai partagé ma solution ici:
comment passer des images (bitmaps) entre les activités Android à l'aide de bundles?
Passer le bitmap comme parceable dans le bundle entre les activités n'est pas une bonne idée en raison de la limitation de taille de Parceable (1mb). Vous pouvez stocker le bitmap dans un fichier dans la mémoire interne et récupérer le bitmap stocké dans plusieurs activités. Voici un exemple de code.
Pour stocker le bitmap dans un fichier myImage dans la mémoire interne:
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;
}
Ensuite, dans l'activité suivante, vous pouvez décoder ce fichier myImage en un bitmap en utilisant le code suivant:
//here context can be anything like getActivity() for fragment, this or MainActivity.this
Bitmap bitmap = BitmapFactory.decodeStream(context.openFileInput("myImage"));
Remarque Une grande partie de la vérification des bitmap nuls et de mise à l'échelle est omise.
openFileOutput
.
Si l'image est trop grande et que vous ne pouvez pas l'enregistrer et la charger dans le stockage, vous devriez envisager d'utiliser simplement une référence statique globale au bitmap (à l'intérieur de l'activité de réception), qui sera réinitialisée à null sur onDestory, uniquement si "isChangingConfigurations" renvoie vrai.
Parce que l'intention a une limite de taille. J'utilise un objet statique public pour passer le bitmap d'un service à l'autre ...
public class ImageBox {
public static Queue<Bitmap> mQ = new LinkedBlockingQueue<Bitmap>();
}
passer à mon 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();
}
});
}
Mon récepteur de diffusion
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 réponse acceptée plantera lorsque le Bitmap
est trop grand. Je pense que c'est une limite de 1 Mo. Le Bitmap
doit être compressé dans un format de fichier différent tel qu'un JPG représenté par un ByteArray
, puis il peut être transmis en toute sécurité via un fichier Intent
.
La fonction est contenue dans un thread séparé à l'aide de Kotlin Coroutines car la Bitmap
compression est chaînée après la Bitmap
création de l'URL String
. La Bitmap
création nécessite un thread distinct afin d'éviter les erreurs ANR (Application Not Responding) .
toBitmap()
une fonction d'extension Kotlin nécessite que cette bibliothèque soit ajoutée aux dépendances de l'application.Bitmap
en JPG ByteArray
après sa création.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
via unIntent
.Dans cet exemple, il est passé d'un fragment à un service . C'est le même concept s'il est partagé entre deux activités .
Fragment.kt
ContextCompat.startForegroundService(
context!!,
Intent(context, AudioService::class.java).apply {
action = CONTENT_SELECTED_ACTION
putExtra(CONTENT_SELECTED_BITMAP_KEY, contentPlayer.image)
})
ByteArray
en 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()
}
}
Il peut être tard mais peut aider. Sur le premier fragment ou activité déclarez une classe ... par exemple
@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;
}
Ensuite, sur la deuxième classe / fragment, faites ceci.
Bitmap bm = postFragment.constan.photoMap;
final String itemName = postFragment.constan.namePass;
J'espère que ça aide.
Toutes les solutions ci-dessus ne fonctionnent pas pour moi, l'envoi de bitmap parceableByteArray
génère également une erreurandroid.os.TransactionTooLargeException: data parcel size
.
Solution
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)
commeIntent 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();
}
}
Vous pouvez créer un transfert bitmap. essaye ça....
Dans la première classe:
1) Créez:
private static Bitmap bitmap_transfer;
2) Créer un getter et un setter
public static Bitmap getBitmap_transfer() {
return bitmap_transfer;
}
public static void setBitmap_transfer(Bitmap bitmap_transfer_param) {
bitmap_transfer = bitmap_transfer_param;
}
3) Réglez l'image:
ImageView image = (ImageView) view.findViewById(R.id.image);
image.buildDrawingCache();
setBitmap_transfer(image.getDrawingCache());
Puis, en deuxième classe:
ImageView image2 = (ImageView) view.findViewById(R.id.img2);
imagem2.setImageDrawable(new BitmapDrawable(getResources(), classe1.getBitmap_transfer()));
Dans mon cas, la manière mentionnée ci-dessus n'a pas fonctionné pour moi. Chaque fois que je mets le bitmap dans l'intention, la deuxième activité ne démarre pas. La même chose s'est produite lorsque j'ai passé le bitmap en tant que byte [].
J'ai suivi ce lien et cela a fonctionné comme un charme et très vite:
package your.packagename
import android.graphics.Bitmap;
public class CommonResources {
public static Bitmap photoFinishBitmap = null;
}
dans ma 1ère activité:
Constants.photoFinishBitmap = photoFinishBitmap;
Intent intent = new Intent(mContext, ImageViewerActivity.class);
startActivity(intent);
et voici le onCreate () de ma 2ème activité:
@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
place de Constants.photoFinishBitmap
.
URI
ouResourceID
du bitmap et non le bitmap lui-même. Passer le bitmap entier nécessite beaucoup de mémoire. La transmission de l'URL nécessite très peu de mémoire et permet à chaque activité de charger et de mettre à l'échelle le bitmap selon ses besoins.