异步任务异常

3

我是Android开发的初学者,正在开发我的第一个应用程序,遇到了一个问题。

我需要从互联网上下载一些图片,并在活动中显示它们。但是,由于图片下载需要时间,UI会有延迟,因此我必须使用多线程。

我阅读了更多相关资料,认为最简单的方法是使用AsyncTask,但我收到了一个异常:只有创建视图层次结构的原始线程才能触摸其视图。

我需要帮助,有人能帮我吗?以下是代码:

public class Main extends Activity{



protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Download download = new Download();
    download.execute(null);
}

private class Download extends AsyncTask<String, Void, String>{
    ImageButtonOverloaded[] imgView = new ImageButtonOverloaded[24];
    TextView[] textView = new TextView[24];
    @Override
    protected String doInBackground(String... params) {
        try{

            URL url = null;
            url = new URL(StaticClass.URL_HOST + "front_page_last_games_plaintext.php");
            URLConnection conn = url.openConnection();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;

            initCovers();
            int i = 0;
            Log.d("SYNC", "i = 0");
            while((line = reader.readLine()) != null){
                String gameInfo[] = line.split("<NEXT>");
                //Log.d("SYNC", gameInfo[0]);
                //Log.d("SYNC", gameInfo[1]);
                Drawable x = ImageOperations(Main.this, StaticClass.URL_HOST + "resize.php?imagine=" + gameInfo[0] ,"image.jpg");

                Log.d("SYNC", "in while");
                imgView[i].setImageDrawable(x);
                Log.d("SYNC", "in while");
                imgView[i].setGameID(gameInfo[0]);
                imgView[i].setOnClickListener(new OnClickListener() {

                    public void onClick(View v) {
                        ImageButtonOverloaded temp = (ImageButtonOverloaded) v;
                        Intent intent = new Intent(Main.this, Single.class);
                        intent.putExtra("ID", temp.getGameID());
                        startActivity(intent);

                    }
                });

                textView[i].setText(gameInfo[1]);
                textView[i].setGravity(Gravity.TOP);
                textView[i].setGravity(Gravity.CENTER_HORIZONTAL);
                textView[i].setTextColor(Color.WHITE);
                i++;
            }
        }catch(Exception ex){
            Log.d("SYNC", ex.getMessage());
        }
        return null;
    }
    private Drawable ImageOperations(Context ctx, String url, String saveFilename) {
        try {
            InputStream is = (InputStream) this.fetch(url);
            Drawable d = Drawable.createFromStream(is, "src");
            return d;
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public Object fetch(String address) throws MalformedURLException,IOException {
        URL url = new URL(address);
        Object content = url.getContent();
        return content;
    }
    private void initCovers(){
        imgView[0] = (ImageButtonOverloaded) findViewById(R.id.imageButton1);
        imgView[1] = (ImageButtonOverloaded) findViewById(R.id.imageButton2);
        imgView[2] = (ImageButtonOverloaded) findViewById(R.id.imageButton3);
        imgView[3] = (ImageButtonOverloaded) findViewById(R.id.imageButton4);
        imgView[4] = (ImageButtonOverloaded) findViewById(R.id.imageButton5);
        imgView[5] = (ImageButtonOverloaded) findViewById(R.id.imageButton6);
        imgView[6] = (ImageButtonOverloaded) findViewById(R.id.imageButton7);
        imgView[7] = (ImageButtonOverloaded) findViewById(R.id.imageButton8);
        imgView[8] = (ImageButtonOverloaded) findViewById(R.id.imageButton9);
        imgView[9] = (ImageButtonOverloaded) findViewById(R.id.imageButton10);
        imgView[10] = (ImageButtonOverloaded) findViewById(R.id.imageButton11);
        imgView[11] = (ImageButtonOverloaded) findViewById(R.id.imageButton12);
        imgView[12] = (ImageButtonOverloaded) findViewById(R.id.imageButton13);
        imgView[13] = (ImageButtonOverloaded) findViewById(R.id.imageButton14);
        imgView[14] = (ImageButtonOverloaded) findViewById(R.id.imageButton15);
        imgView[15] = (ImageButtonOverloaded) findViewById(R.id.imageButton16);
        imgView[16] = (ImageButtonOverloaded) findViewById(R.id.imageButton17);
        imgView[17] = (ImageButtonOverloaded) findViewById(R.id.imageButton18);
        imgView[18] = (ImageButtonOverloaded) findViewById(R.id.imageButton19);
        imgView[19] = (ImageButtonOverloaded) findViewById(R.id.imageButton20);
        imgView[20] = (ImageButtonOverloaded) findViewById(R.id.imageButton21);
        imgView[21] = (ImageButtonOverloaded) findViewById(R.id.imageButton22);
        imgView[22] = (ImageButtonOverloaded) findViewById(R.id.imageButton23);
        imgView[23] = (ImageButtonOverloaded) findViewById(R.id.imageButton24);

        textView[0] = (TextView) findViewById(R.id.textView1);
        textView[1] = (TextView) findViewById(R.id.textView2);
        textView[2] = (TextView) findViewById(R.id.textView3);
        textView[3] = (TextView) findViewById(R.id.textView4);
        textView[4] = (TextView) findViewById(R.id.textView5);
        textView[5] = (TextView) findViewById(R.id.textView6);
        textView[6] = (TextView) findViewById(R.id.textView7);
        textView[7] = (TextView) findViewById(R.id.textView8);
        textView[8] = (TextView) findViewById(R.id.textView9);
        textView[9] = (TextView) findViewById(R.id.textView10);
        textView[10] = (TextView) findViewById(R.id.textView11);
        textView[11] = (TextView) findViewById(R.id.textView12);
        textView[12] = (TextView) findViewById(R.id.textView13);
        textView[13] = (TextView) findViewById(R.id.textView14);
        textView[14] = (TextView) findViewById(R.id.textView15);
        textView[15] = (TextView) findViewById(R.id.textView16);
        textView[16] = (TextView) findViewById(R.id.textView17);
        textView[17] = (TextView) findViewById(R.id.textView18);
        textView[18] = (TextView) findViewById(R.id.textView19);
        textView[19] = (TextView) findViewById(R.id.textView20);
        textView[20] = (TextView) findViewById(R.id.textView21);
        textView[21] = (TextView) findViewById(R.id.textView22);
        textView[22] = (TextView) findViewById(R.id.textView23);
        textView[23] = (TextView) findViewById(R.id.textView24);

    }
}}
1个回答

5

doInBackground() 是一个非UI线程,你不能在其中访问UI元素。在doInBackground()中运行的代码在单独的非UI线程上运行,无法访问布局中定义的UI元素。此外,由于你通过意图调用另一个Activity,你应该始终记住,Activity在UI线程上运行,因此你不应该从非UI线程内部启动另一个Activity。

因此,请移除从doInBackground()中访问UI元素的代码,并将其放入onPostExecute()中,这是一个UI线程,在doInBackground()完成后调用以进行后台处理。

int i =0; // global variable
Drawable drawableArray []; // global array to store all the drawables 

doInBackground(String... params) {
        try{

            URL url = null;
            url = new URL(StaticClass.URL_HOST + "front_page_last_games_plaintext.php");
            URLConnection conn = url.openConnection();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;

            initCovers();
            while((line = reader.readLine()) != null){
                String gameInfo[] = line.split("<NEXT>");
                //Log.d("SYNC", gameInfo[0]);
                //Log.d("SYNC", gameInfo[1]);
                drawableArray[i] = ImageOperations(Main.this, StaticClass.URL_HOST + "resize.php?imagine=" + gameInfo[0] ,"image.jpg");
                i++;
}

onPostExecute()
{
   for(j=0;j<=i;j++)

                Log.d("SYNC", "in while");
                imgView[j].setImageDrawable(drawableArray[j]);
                Log.d("SYNC", "in while");
                imgView[j].setGameID(gameInfo[0]);
                imgView[j].setOnClickListener(new OnClickListener() {

                    public void onClick(View v) {
                        ImageButtonOverloaded temp = (ImageButtonOverloaded) v;
                        Intent intent = new Intent(Main.this, Single.class);
                        intent.putExtra("ID", temp.getGameID());
                        startActivity(intent);

                    }
                });

                textView[j].setText(gameInfo[1]);
                textView[j].setGravity(Gravity.TOP);
                textView[j].setGravity(Gravity.CENTER_HORIZONTAL);
                textView[j].setTextColor(Color.WHITE);
                j++;
            }
}

编辑:正如@Luksprog@tolgap所指出的那样,主UI线程上的图像处理部分是一个冗长的操作,可能会使UI无响应。因此,最好也在后台线程上进行图像处理,然后使用onPostExecute()仅设置图像位图并更新其他UI元素。通过在后台进行处理来使用全局数组存储可绘制对象,然后只需在onPostExecute()内部更新UI。


1
你应该意识到,你将ImageOperations方法移动到主线程的onPostExecute中,在那个while循环中运行是一个耗时的操作。 - user
没错。提问者不应该像这样实现代码,而是应该在 doInBackground() 中完成所有繁重的工作,并将他想要设置为 result 的图像返回到 onPostExecute。或者,在 doInBackground 中设置所有的 ImageViews,并将所有的 ImageViews 作为一个变量返回到 onPostExecute() 中,以便设置为 contentView。 - tolgap
@Luksprog:是的,我完全同意!问题在于我一直在尝试解决问题所指定的错误,但现在我意识到将ImageOperation部分移动到主UI线程上可能不是一个好主意。因此,也许可以在另一个后台线程上进行图像处理,然后在postExecute()中设置图像。这样可以吗? - Swayam
@Luksprog:先生,我已经修改了代码,并将“ImageOperations”移动到“doInBackground”线程中。请看看。希望现在是正确的。如果现在是正确的,请考虑删除您的踩票。谢谢。 :) - Swayam

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