web-dev-qa-db-fra.com

Comment puis-je passer un objet Bitmap d'une activité à une autre

Dans mon activité, je crée un objet Bitmap puis je dois lancer un autre Activity, Comment puis-je transmettre cet objet Bitmap de la sous-activité (celle qui va être lancée)?

130
michael

Bitmap implémente Parcelable, vous pouvez donc toujours le transmettre 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");
276
Erich Douglass

En fait, le fait de passer un bitmap en tant que parcelle entraînera une erreur "Java BINDER FAILURE". Essayez de passer 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 passez-vous les images (bitmaps) entre les activités Android à l'aide de bundles?

21
Harlo Holmes

Passer des images bitmap comme pouvant être groupées entre activités n’est pas une bonne idée en raison de la limitation de la taille de cette option. Vous pouvez stocker le bitmap dans un fichier de la mémoire interne et récupérer le bitmap stocké dans plusieurs activités. Voici un exemple de code.

Pour stocker une image bitmap dans un fichier myImage dans la mémoire de 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 en une bitmap à l'aide du code suivant:

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

Remarque De nombreuses vérifications de null et de mise à l'échelle des images bitmap sont omises.

10
Illegal Argument

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 (dans l'activité de réception), qui sera réinitialisée à null sur onDestory, uniquement si "isChangingConfigurations" retourne vrai.

4

Parce que Intent a une taille limite . J'utilise un objet statique public pour faire passer bitmap du service à la diffusion ....

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 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);
            }
        }
    };
3
Deyu瑜

Compresser et envoyer Bitmap

La réponse acceptée plantera lorsque la Bitmap est trop grande. Je crois que c'est un 1MB limite. La Bitmap doit être compressée dans un format de fichier différent, tel qu'un JPG représenté par un ByteArray, puis il peut être passé en toute sécurité via un Intent.

La mise en oeuvre

La fonction est contenue dans un fil séparé utilisant Kotlin Coroutines car la compression Bitmap est chaînée après la création de la Bitmap url String. La création de Bitmap nécessite un thread distinct afin d'éviter les erreurs de l'application sans réponse (ANR) .

Concepts utilisés

  • Kotlin Coroutines notes .
  • Le modèle Chargement, contenu, erreur (LCE) est utilisé ci-dessous. Si vous êtes intéressé, vous pouvez en apprendre plus à ce sujet dans cette conversation et cette vidéo .
  • LiveData est utilisé pour renvoyer les données. J'ai compilé ma ressource préférée LiveData dans ces notes .
  • Dans Étape 3 , toBitmap() est un fonction d'extension Kotlin nécessitant l'ajout de cette bibliothèque aux dépendances de l'application.

Code

1. Compressez Bitmap en JPGByteArray 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}")
            }
        }
    })
}

2. Passez l'image en tant que ByteArray via un Intent.

Dans cet exemple, il est passé d'un fragment à un service . C'est le même concept si 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. Reconvertissez 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()
        }
    }
1
Adam Hurwitz

Toutes les solutions ci-dessus ne fonctionnent pas pour moi. L'envoi d'un bitmap en tant que parceableByteArray génère également l'erreur Android.os.TransactionTooLargeException: data parcel size.

Solution

  1. Enregistré le bitmap dans la mémoire interne en tant que:
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. et envoyez putExtra(String) en tant que
Intent intent = new Intent(ActivitySketcher.this,ActivityEditor.class);
intent.putExtra("KEY", saveBitmap(bmp));
startActivity(intent);
  1. et le recevoir dans une autre activité en tant que:
if(getIntent() != null){
  try {
           src = BitmapFactory.decodeStream(openFileInput("myImage"));
       } catch (FileNotFoundException e) {
            e.printStackTrace();
      }

 }


0
Ali Tamoor

Vous pouvez créer un transfert bitmap. essaye ça....

En première classe:

1) Créer:

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) Définissez l'image:

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

Ensuite, en deuxième classe:

ImageView image2 = (ImageView) view.findViewById(R.id.img2);
imagem2.setImageDrawable(new BitmapDrawable(getResources(), classe1.getBitmap_transfer()));
0
Rômulo Z. C. Cunha

Cela 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 seconde classe/fragment, faites ceci ..

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

J'espère que ça aide.

0
ANTONY MWANGI