Comment puis-je passer un objet Bitmap d'une activité à une autre
-
20-09-2019 - |
Question
Dans mon activité, je crée un Bitmap
objet et ensuite je dois en lancer un autre Activity
, Comment puis-je passer ça Bitmap
objet de la sous-activité (celle qui va être lancée) ?
La solution
Bitmap
implémente Parcelable
, donc vous pouvez toujours passer avec l'intention:
Intent intent = new Intent(this, NewActivity.class);
intent.putExtra("BitmapImage", bitmap);
et le récupérer à l'autre bout:
Intent intent = getIntent();
Bitmap bitmap = (Bitmap) intent.getParcelableExtra("BitmapImage");
Autres conseils
En fait, le passage d'un bitmap en tant que Parcelable se traduira par une erreur « JAVA BINDER FAILURE ». Essayez le passage du bitmap en tant que tableau d'octets et la construction pour l'affichage à l'activité suivante.
Je partageais ici ma solution:
comment passez-vous des images ( bitmaps) entre les activités Android à l'aide des paquets
Passsing bitmap parceable en bundle entre l'activité n'est pas une bonne idée en raison de la limitation de la taille des 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 quelques exemples de code.
Pour stocker dans un fichier bitmap myImage dans le stockage 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 à 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 Beaucoup de vérification de bitmap NULL et mise à l'échelle de ommited est.
Si l'image est trop grande et vous ne pouvez pas enregistrer et charger sur le stockage, vous devriez considérer simplement en utilisant une référence statique globale au bitmap (dans l'activité de réception), qui sera remis à null sur onDestory, seulement si "isChangingConfigurations" retourne vrai.
Parce que Intent a la limite de taille. J'utilise objet statique public de le faire bitmap passe du service à diffuser ....
public class ImageBox {
public static Queue<Bitmap> mQ = new LinkedBlockingQueue<Bitmap>();
}
passe dans 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 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);
}
}
};
Compresser et envoyer Bitmap
La réponse acceptée plantera lorsque le Bitmap
est trop grand. je crois que c'est un 1 Mo limite.Le Bitmap
doit être compressé dans un format de fichier différent tel qu'un JPG représenté par un ByteArray
, il peut alors être transmis en toute sécurité via un Intent
.
Mise en œuvre
La fonction est contenue dans un thread séparé utilisant Coroutines Kotlin parce que le Bitmap
la compression est enchaînée après le Bitmap
est créé à partir d'une URL String
.Le Bitmap
la création nécessite un thread séparé afin d'éviter L'application ne répond pas (ANR) les erreurs.
Concepts utilisés
- Coroutines Kotlin Remarques.
- Le Chargement, contenu, erreur (LCE) le modèle est utilisé ci-dessous.Si vous êtes intéressé, vous pouvez en savoir plus sur cette conférence et cette vidéo.
- Données en direct est utilisé pour renvoyer les données.J'ai compilé mes favoris Données en direct ressource dans ces notes.
- Dans Étape 3,
toBitmap()
est un Fonction d'extension Kotlin exigeant que cette bibliothèque soit ajoutée aux dépendances de l'application.
Code
1.Compresse Bitmap
à JPG ByteArray
après sa création.
Dépôt.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.Passer l'image comme ByteArray
via un Intent
.
Dans cet exemple, il est transmis 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)
})
3.Convertir ByteArray
retour à 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 est peut-être en retard, mais peut aider. Sur le premier fragment ou une activité faire déclarer 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 faire ..
Bitmap bm = postFragment.constan.photoMap;
final String itemName = postFragment.constan.namePass;
it helps.
Vous pouvez créer un transfert bitmap. essayer ....
Dans la première classe:
1) Créer:
private static Bitmap bitmap_transfer;
2) Créer getter et setter
public static Bitmap getBitmap_transfer() {
return bitmap_transfer;
}
public static void setBitmap_transfer(Bitmap bitmap_transfer_param) {
bitmap_transfer = bitmap_transfer_param;
}
3) Définir l'image:
ImageView image = (ImageView) view.findViewById(R.id.image);
image.buildDrawingCache();
setBitmap_transfer(image.getDrawingCache());
Ensuite, dans la deuxième classe:
ImageView image2 = (ImageView) view.findViewById(R.id.img2);
imagem2.setImageDrawable(new BitmapDrawable(getResources(), classe1.getBitmap_transfer()));
Toutes les solutions ci-dessus ne fonctionne pas pour moi, Envoi bitmap parceableByteArray
génère également android.os.TransactionTooLargeException: data parcel size
d'erreur.
Solution
- Enregistré le bitmap dans la mémoire interne comme suit:
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;
}
- et envoyer
putExtra(String)
comme
Intent intent = new Intent(ActivitySketcher.this,ActivityEditor.class);
intent.putExtra("KEY", saveBitmap(bmp));
startActivity(intent);
- et le recevoir dans d'autres activités comme:
if(getIntent() != null){
try {
src = BitmapFactory.decodeStream(openFileInput("myImage"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
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 2e activité n'a pas démarré. La même chose est arrivée quand je suis passé le bitmap comme octet [].
Je suivais cette et cela a fonctionné comme un charme et très rapide:
package your.packagename
import android.graphics.Bitmap;
public class CommonResources {
public static Bitmap photoFinishBitmap = null;
}
dans mon 1er acitiviy:
Constants.photoFinishBitmap = photoFinishBitmap;
Intent intent = new Intent(mContext, ImageViewerActivity.class);
startActivity(intent);
et voici le onCreate () de mon 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));
}
}