【问题标题】:Android BitmapFactory.decodeFile intermittently returning nullAndroid BitmapFactory.decodeFile 间歇性返回 null
【发布时间】:2015-03-13 07:51:51
【问题描述】:

我使用的是安卓 4.0.4,内核 3.0.8+

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

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

有很多人抱怨这个。大多数问题的答案都涉及位图的放置位置,或者刷新的输入流/http 连接/其他的性质。我已经排除了这些 - 事实上,我已经将我的问题简化为一个简单到可以称为测试用例的 android 应用程序。

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

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 分之一。失败并不总是同一个文件,但有些文件确实似乎比其他文件更频繁。

我最好的预感是 png 解码器出现故障,如果运行时间较长,则更有可能发生故障,但在那之后我有点迷茫。如果有人对这个问题有任何看法,或者加载 png 文件的替代方法,我将不胜感激!

【问题讨论】:

  • 我应该说 - 在报告空位图之前,我看到了skia信息消息“---解码器->解码返回错误”
  • 我面临同样的问题,没有任何解决方案。

标签: android bitmap


【解决方案1】:

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

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

我的总体意见是,这是一个很少发生的错误,其存在被大量没有足够仔细地处理输入流的人所掩盖。对于 this 问题,我在任何地方看到的唯一答案是尝试循环加载位图 (OMG)。但是,如果数百人因为有这些症状而发现这个问题,请确保他们在诉诸这种邪恶的黑客之前 100% 确保他们正在使用可行的刷新输入流,那么我认为我们会很感激的!

谢谢

附:将其称为“答案”会感到内疚吗?

【讨论】:

  • 我已经确认 - 我有一个设备崩溃日志,在解码 png 时在 libskia 中显示 SIGSEGV(信号 11)。这次它重新启动了整个设备,而不是返回 null。它有一些严重的问题。我认为没有人可以为不是 4.0.4 的 A10 设备推荐稳定的固件映像,他们可以吗?
  • Aaaaa 我要撤销我自己的答案。我现在在 4.2.2 设备上看到此失败。我认为这不再是“Java”或“Android”错误,而是某些设备上的设备驱动程序/内核级别问题。
  • 我现在没有什么动力去尝试解决这个问题,所以我会用我所知道的来整理这个问题并放弃它。我最好的选择是,这是 AllWinner 设备中的一个错误,与他们声称对 png 文件进行硬件解码有关。我没有观察到 JPEG 的问题,也没有观察到 Rockchip 设备上的问题。 AllWinner 用一组相当常规的问题回答了我,然后忘记了我的存在,所以我无法确认任何事情或修复任何事情。祝你好运。
【解决方案2】:

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

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

希望这会有所帮助。

【讨论】:

  • 可以肯定,如果我的权限错误,我总是会失败或总是成功,而不是随机的一个或另一个......
猜你喜欢
  • 1970-01-01
  • 2016-10-17
  • 2018-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多