Android BitmapFactory.decodeFile间歇性地返回null

And*_*man 7 android bitmap

我使用的是android 4.0.4,内核3.0.8+

BitmapFactory.decodeFile经常返回一个空位图.

请注意,如果位图工厂无法加载位图,我会立即再次尝试,最多4次,这通常有效(!)

有很多人抱怨这个.大多数问题的答案涉及位图的放置位置,或者刷新的输入流/ http连接的性质等等.我已经排除了这些 - 实际上,我已经将我的问题减少到了一个如此荒谬简单的Android应用程序,它可以被称为测试用例.

我的应用程序有一个活动,其中包含一个按钮,当按下该按钮时,会启动一个循环通过外部文件目录的线程,尝试将其中的所有内容加载到位图中.我不使用位图,或保留它,或任何东西,我只是加载并忘记:

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;
      }
    }
  }
}    
Run Code Online (Sandbox Code Playgroud)

我会看到这样的输出:

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
Run Code Online (Sandbox Code Playgroud)

您将在上面的代码中看到一个注释掉的替代加载序列,其中而不是使用decodeFile我将文件加载到byte []然后使用decodeByteArray.这具有相同的效果(decodeByteArray失败,然后立即在完全相同的字节数组上成功!),但我注意到失败不太常见.

在decodeFile的情况下,10次尝试中可能有1次返回null.在decodeByteArray的情况下,也许只有100中的1.它并不总是同一个文件失败,但有些文件似乎比其他文件更频繁地失败.

我最好的预感是png解码器出现故障,如果它运行的时间更长,则更容易发生,但之后我有点迷失了.如果有人对这个问题有所了解,或者加载png文件的其他方法,我真的很感激!

And*_*man 2

进一步的实验表明,这种情况发生在我拥有的每台运行 4.0.4 特定版本的设备(我有很多)上,但即使在 4.1.1 设备上运行过夜也不会发生。考虑到代码的简单性,并且后来的 Android 版本不会复制它,我倾向于将其标记为 Android 中的一个错误,该错误在某些时候已被修复。有了这些信息的帮助,我将假设这是 SKIA 中的一个错误,在此线程中对此进行了第 n 度的争论:

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

我的总体观点是,这是一个很少发生的错误,它的存在被大量没有足够仔细处理输入流的人所掩盖。我在任何地方看到的这个问题的唯一答案是尝试在循环中加载位图(OMG)。然而,如果数百名因为有这些症状而发现这个问题的人能够在诉诸这种邪恶的黑客之前百分百确定他们正在使用可行的刷新输入流,那么我想我们都会感激不尽!

谢谢

PS,是否可以因为将此称为“答案”而感到内疚?