7 votes

Android BitmapFactory.decodeFile retourne de façon intermittente null

Je suis sous Android 4.0.4, kernel 3.0.8+

De temps en temps BitmapFactory.decodeFile retourne un bitmap nul.

Notez que si l'usine de bitmaps échoue à charger le bitmap, j'essaie immédiatement à nouveau, jusqu'à 4 fois, et cela fonctionne souvent (!)

Beaucoup de personnes se plaignent de cela. La plupart des réponses aux questions impliquent l'endroit où le bitmap est placé, ou la nature du flux d'entrée effacé / connexion HTTP / autre. J'ai exclu ces causes - en fait, j'ai réduit mon problème à une application android d'une simplicité ridicule qui pourrait être appelée un cas de test.

Mon application a une seule activité, qui contient un seul bouton, qui lorsqu'il est pressé lance un thread qui parcourt le répertoire des fichiers externes en essayant de charger tout ce qui s'y trouve en bitmaps. Je n'utilise pas le bitmap, ni ne le garde, ni rien, je charge simplement et oublie :

public class MainActivity extends Activity {

  private static final String TAG = "bmpbash";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  public void onGo(View view) {
    view.setVisibility(View.GONE);
    start();
  }

  /**
   * Start the thread.
   */
  public void start() {
    Runnable r = new Runnable() {
      @Override
      public void run() {
        mainLoop();
      }
    };
    Thread thread = new Thread(r);
    thread.start();
  }

  public void mainLoop() {
    int index = 0;
    File top = getExternalFilesDir(null);
    while (true) {
      File[] files = top.listFiles();
      if (files.length < 1) {
        Log.e(TAG, "no files found");
      } else {
        if (files.length <= index) {
          index = 0;
        }
        File file = files[index];

        //byte[] data = readFile(file);

        try {
          boolean ok = false;
          for (int i = 0; i < 4 && !ok; ++i) {
            //Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
            if (bitmap == null) {
              Log.e(TAG, file.getName() + "[" + i + "] - NULL bitmap");
            } else {
              ok = true;
              Log.w(TAG, file.getName() + "[" + i + "] - OK");
            }
          }
        } catch (Exception e) {
          Log.e(TAG, file.getName() + " - DIED", e);
        } catch (OutOfMemoryError oom) {
          Log.e(TAG, file.getName() + " - OOM");
        }
        ++index;
      }
    }
  }
}    

Je verrai une sortie comme ceci :

10-22 17:27:57.688: W/bmpbash(1131): translucent.png[0] - OK
10-22 17:27:57.698: W/bmpbash(1131): fearthecow.png[0] - OK
10-22 17:27:57.798: W/bmpbash(1131): gui2.png[0] - OK
10-22 17:27:57.888: W/bmpbash(1131): gui.png[0] - OK
10-22 17:27:58.058: W/bmpbash(1131): boot.png[0] - OK
10-22 17:27:58.218: E/bmpbash(1131): trainer2.png[0] - NULL bitmap
10-22 17:27:58.378: W/bmpbash(1131): trainer2.png[1] - OK

Vous remarquerez dans le code ci-dessus qu'il y a une séquence de chargement alternative mise en commentaire, dans laquelle au lieu d'utiliser decodeFile, je charge le fichier dans un byte[] et utilise ensuite decodeByteArray. Cela a le même effet (decodeByteArray échoue puis réussit immédiatement sur exactement le même tableau de bytes!), mais je note que les échecs sont beaucoup moins fréquents.

Dans le cas de decodeFile, peut-être 1 tentative sur 10 renvoie null. Dans le cas de decodeByteArray, peut-être seulement 1 sur 100. Ce n'est pas toujours le même fichier qui échoue, mais certains fichiers semblent échouer plus souvent que d'autres.

Mon meilleur soupçon est que le décodeur png a une défaillance qui est plus susceptible de se produire s'il fonctionne sur une plus longue période, mais après cela, je suis un peu perdu. Si quelqu'un peut éclairer le problème, ou proposer des approches alternatives pour charger des fichiers png, je vous en serais très reconnaissant !

2voto

Andy Newman Points 279

De plus, des expériences supplémentaires montrent que cela se produit sur chaque appareil que j'ai (j'en ai pas mal) qui fonctionne avec une version particulière de 4.0.4, mais ne se produit pas même s'il est laissé en cours d'exécution toute la nuit sur un appareil 4.1.1. Étant donné la simplicité du code, et le fait qu'une version ultérieure d'Android ne le reproduit pas, j'ai tendance à considérer cela comme un bug dans Android qui a, à un moment donné, été corrigé. Avec ces informations pour aider, je vais supposer qu'il s'agit d'un bug dans SKIA qui est discuté en long et en large dans ce fil de discussion ici :

http://code.google.com/p/android/issues/detail?id=6066

Mon opinion générale est qu'il s'agit d'un bug rare dont l'existence est obscurcie par le grand nombre de personnes qui ne gèrent pas assez soigneusement leurs flux d'entrée. La seule réponse que j'ai vue n'importe où pour ce problème est d'essayer de charger l'image en boucle (OMG). Cependant, si les centaines de personnes qui trouvent cette question parce qu'elles ont ces symptômes pouvaient s'il vous plaît s'assurer à 100% qu'elles utilisent un flux d'entrée correctement vidé avant de recourir à une telle astuce, alors je pense que nous apprécierions tous!

Merci

P.S. Est-il acceptable de se sentir coupable d'appeler cela une "réponse" ?

0voto

Najor Points 161

Mon problème était similaire mais je l'ai résolu en ajoutant simplement des permissions d'accès au stockage externe :

J'espère que cela vous aidera.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X