Android BitmapFactory.decodeFile间歇性地返回null

时间:2013-10-22 10:32:21

标签: 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;
      }
    }
  }
}    

我会看到这样的输出:

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

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

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

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

2 个答案:

答案 0 :(得分:2)

进一步的实验表明,这种情况发生在我拥有的每台设备上(我有很多),它运行4.0.4的特殊风味,但即使在4.1.1设备上过夜运行也不会发生。考虑到代码的简单性,以及后来的Android版本没有复制它,我倾向于将此标记为Android中的一个错误,在某些时候已修复。有了这些信息可以提供帮助,我将假设这是SKIA中的一个错误,这个错误在这个主题中被认为是nth degree:

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

我的总体看法是,这是一个很少发生的错误,其存在被大量未充分处理其输入流的人所掩盖。我在这个问题的任何地方看到的唯一答案是尝试在循环(OMG)中加载位图。但是,如果因为他们有这些症状而找到这个问题的数百人可以100%确定他们使用可行的刷新输入流然后再诉诸这种邪恶的黑客,那么我认为我们我们都很感激!

由于

P.S。将这称为“答案”感到内疚是否可以?

答案 1 :(得分:0)

我的问题很相似,但我只是通过向外部存储添加访问权限来解决它:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

希望这有帮助。