【问题标题】:AsyncTask exception异步任务异常
【发布时间】:2012-09-27 14:16:01
【问题描述】:

我是 Android 开发的初学者,我正在使用我的第一个应用程序,但遇到了问题。 我必须下载一些图片扔到互联网上,并在活动中展示它们。 在下载图像之前,我有一个 UI 延迟,所以我必须使用多线程。

我阅读了更多关于它的信息,我认为最简单的是使用 AsyncTask,但我收到了一个例外:Only the original thread that created a view hierarchy can touch its views.

我需要帮助。任何人都可以帮助我吗?代码是这样的:

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);

    }
}}

【问题讨论】:

    标签: android exception android-asynctask


    【解决方案1】:

    doInBackgorund() 是一个非 UI 线程,您无法访问其中的 UI 元素。 doInBackground() 中的代码在一个单独的非 UI 线程上运行,该线程无法访问布局中定义的 UI 元素。此外,由于您通过 Intent 调用另一个 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 元素。通过在后台进行处理,使用全局数组来存储 Drawables,然后在 onPostExecute() 中更新 UI。

    【讨论】:

    • 您确实意识到您移动到onPostExecute(在主UI 线程上)要在while 循环中运行的方法ImageOperations 是一个冗长的操作?
    • 没错。提问者不应该实现这样的代码,而是在doInBackground()中做所有繁重的工作,并将他想要设置为result的图像返回给onPostExecute。或者,设置doInBackground中的所有ImageViews,并将所有ImageViews作为变量返回给onPostExecute()设置为contentView
    • @Luksprog :是的,先生,我绝对愿意!问题是我试图解决问题指定的错误,尽管现在我意识到在主 UI 线程上移动 ImageOperation 部分可能不是一个好主意。所以也许在另一个后台线程上进行图像处理,然后在 postExecute() 上设置图像。这样可以吗?
    • @tolgap :是的,先生,我完全理解。
    • @Luksprog :先生,我已经修改了代码并将ImageOperations 移动到doInBackground 线程。看一看。希望现在是正确的。如果现在正确,请考虑删除您的反对票。谢谢。 :)
    猜你喜欢
    • 2012-10-26
    • 2021-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-26
    • 2014-05-20
    • 2019-04-12
    • 2015-10-03
    相关资源
    最近更新 更多