使用AsyncTask加载位图图像

3

我正在尝试在用户使用我的应用程序时加载背景图像。我编写的逻辑如下:

public class ImageLoader extends AsyncTask <Context, Void, Bitmap>{

    private String URL;
    private int type;

    ImageLoader(String Url, int Type)
    {
        URL = Url;
        type = Type;
    }

    @Override
    protected Bitmap doInBackground(Context... arg0) {

        AssetManager assetMgr = arg0[0].getAssets();
        Bitmap bitmap = null;
        try {
            bitmap = BitmapFactory.decodeStream(assetMgr.open(URL));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    protected void onPostExecute( Bitmap result )  {
          super.onPostExecute(result);

          if (type == 1)
              Inst1 = result;
          else if (type == 2)
              Inst2 = result;
          else if (type == 3)
              Inst3 = result;
    }
}

然而,当我尝试像这样启动一个新线程时:
task = new ImageLoader("Instructions_2.png", 3);
task.execute(gameContext);

但是,在程序中我遇到了错误,提示需要先调用Looper.prepare()方法,然后是逻辑代码looper.quit()。

然而当我添加Looper.prepare()时,程序好像就出问题了,而且也没有可供调用的looper.quit()方法。

请问我的任务创建方式是否正确?

编辑:

这是运行时出现的错误日志:

task = new ImageLoader(gameContext, "Instructions_3.png", 3);

我有一个switch case语句,我把图像加载器声明放在外面。基本上我的代码是:

ImageLoader task;
switch(foo)
{
    case 0:
       ...
       task = new ImageLoader(gameContext, "Instructions_0.png", 3);
       task.execute();
       break;
    case 1:
       ...
       task = new ImageLoader(gameContext, "Instructions_1.png", 3));
       task.execute();
       break;
    ...
}

错误日志(每次我执行task = new ImageLoader(...);这行代码都会出错)

07-20 14:23:34.276: E/AndroidRuntime(16741): FATAL EXCEPTION: Thread-10
07-20 14:23:34.276: E/AndroidRuntime(16741): java.lang.ExceptionInInitializerError
07-20 14:23:34.276: E/AndroidRuntime(16741):    at com.petronicarts.stormthecastle.MainGamePanel.update(MainGamePanel.java:2578)
07-20 14:23:34.276: E/AndroidRuntime(16741):    at com.petronicarts.stormthecastle.MainThread.run(MainThread.java:63)
07-20 14:23:34.276: E/AndroidRuntime(16741): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
07-20 14:23:34.276: E/AndroidRuntime(16741):    at android.os.Handler.<init>(Handler.java:121)
07-20 14:23:34.276: E/AndroidRuntime(16741):    at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
07-20 14:23:34.276: E/AndroidRuntime(16741):    at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
07-20 14:23:34.276: E/AndroidRuntime(16741):    at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
07-20 14:23:34.276: E/AndroidRuntime(16741):    ... 2 more
1个回答

6

问题在于,您正在尝试从非 UI 线程访问和操作 UI 元素。如果按照以下方式更改您的 AsyncTask,我相信您将可以解决这个问题:

public class ImageLoader extends AsyncTask <Void, Void, Bitmap>{

private String URL;
private int type;
private Context context;
private InputStream in;

ImageLoader(Context context, String Url, int Type)
{
    URL = Url;
    type = Type;
    ImageLoader.this.context = context;
}

@Override
protected void onPreExecute()
{
   AssetManager assetMgr = context.getAssets();

   try {

       in = assetMgr.open(URL);
   } catch (IOException e) {

       e.printStackTrace();
   }

}

@Override
protected Bitmap doInBackground(Void... arg0) {

    Bitmap bitmap = null;
    try {
        bitmap = BitmapFactory.decodeStream(in);
        in.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return bitmap;
}

@Override
protected void onPostExecute( Bitmap result )  {

      if (type == 1)
          Inst1 = result;
      else if (type == 2)
          Inst2 = result;
      else if (type == 3)
          Inst3 = result;
}
}

同时更改您的AyncTask调用,例如:

task = new ImageLoader(gameContext, "Instructions_2.png", 3);
task.execute();

我仍然收到一个关于未调用Looper.prepare()的错误。放置它的理想位置在哪里? - Nathan Tornquist
@NathanTornquist 你能够发布你的错误日志并且指出在你的代码中抛出异常的行吗? - AggelosK
@NathanTornquist 你是在从另一个非“UI线程”调用switch case语句吗?如果是这样,请尝试在您的switch块中按以下方式调用ImageLoader AsyncTask:“runOnUiThread(new Runnable(){public void run(){task = new ImageLoader(gameContext,“Instructions_0.png”,3); task.execute();}});”。 - AggelosK
我有一个Activity,它将onPause、onResume、onDestroy等事件发送到我的MainGamePanel。该MainGamePanel是扩展的SurfaceView。我有一个MainThread,在MainGamePanel中运行更新和绘制函数。当初始化MainGamePanel时,线程被启动。希望这一切都说得通。但是,我似乎无法访问runOnUiThread。 - Nathan Tornquist
@NathanTornquist 如果你这样调用 yourActivity.runOnUiThread(...);,你就可以在 runOnUiThread 方法中访问了,其中 yourActivity 是指正在屏幕上显示的 Activity 的引用。我不知道我建议的方法是否一定能解决你的问题,但是当你在 UI 线程之外处理 UI 元素时,才会出现你遇到的错误,所以这是你需要寻找的。希望这有所帮助。 - AggelosK
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接