使用AsyncTask时出现NetworkOnMainThreadException

3
我正在制作一个使用互联网检索信息的应用程序。当我尝试在3.0及以上版本上运行它时,出现了一个NetworkOnMainThreadException异常,因此我尝试使用AsyncTask进行设置,但仍然出现异常,我不知道问题出在哪里。有趣的是,我在这个线程上读到了Android NetworkOnMainThreadException inside of AsyncTask,如果你只从清单文件中删除android:targetSdkVersion="10"语句,它将能够运行。这样做是可以解决问题,但我认为这不是正确的解决方法。
所以,如果有人能告诉我我在AsyncTask中做错了什么,我会非常感激。此外,如果有人知道为什么删除清单中的语句会使它起作用,我也很感兴趣。
我的代码看起来像这样: 编辑:更新代码。
public class MainActivity extends Activity {

static ArrayList<Tumblr> tumblrs;
ListView listView;
TextView footer;
int offset = 0;
ProgressDialog pDialog;
View v;
String responseBody = null;
HttpResponse r;
HttpEntity e;
String searchUrl;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

    final ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    final NetworkInfo activeNetwork = conMgr.getActiveNetworkInfo();
    if (activeNetwork != null && activeNetwork.isConnected()) {

        setContentView(R.layout.main);

        try {
            tumblrs = getTumblrs();
            listView = (ListView) findViewById(R.id.list);
            View v = getLayoutInflater().inflate(R.layout.footer_layout,
                    null);
            footer = (TextView) v.findViewById(R.id.tvFoot);
            listView.addFooterView(v);
            listView.setAdapter(new UserItemAdapter(this, R.layout.listitem));

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        new GetChicks().execute();
        footer.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                new loadMoreListView().execute();
            }
        });

    } else {
        setContentView(R.layout.nonet);

    }

}

public class UserItemAdapter extends ArrayAdapter<Tumblr> {

    public UserItemAdapter(Context context, int imageViewResourceId) {
        super(context, imageViewResourceId, tumblrs);

    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        if (v == null) {

            LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.listitem, null);

        }

        Tumblr tumblr = tumblrs.get(position);
        if (tumblr != null) {

            ImageView image = (ImageView) v.findViewById(R.id.avatar);

            if (image != null) {
                image.setImageBitmap(getBitmap(tumblr.image_url));

            }
        }

        return v;
    }
}

public Bitmap getBitmap(String bitmapUrl) {
    try {
        URL url = new URL(bitmapUrl);
        return BitmapFactory.decodeStream(url.openConnection()
                .getInputStream());
    } catch (Exception ex) {
        return null;
    }
}

public ArrayList<Tumblr> getTumblrs() throws ClientProtocolException,
        IOException, JSONException {
    searchUrl = "http://api.tumblr.com/v2/blog/factsandchicks.com/posts?api_key=rTZsymOWtMudbb5tql2U20qQ5ooYLPYVNnL3COPpO2qBHDxJUu&limit=2&offset=0";

    ArrayList<Tumblr> tumblrs = new ArrayList<Tumblr>();
    return tumblrs;
}

private class GetChicks extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... unused) {
        // TODO Auto-generated method stub


                HttpClient client = new DefaultHttpClient();
                HttpGet get = new HttpGet(searchUrl);

                HttpResponse r = null;
                try {
                    r = client.execute(get);
                    int status = r.getStatusLine().getStatusCode();
                    if (status == 200) {
                        e = r.getEntity();
                        responseBody = EntityUtils.toString(e);
                    }
                } catch (ClientProtocolException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }

                JSONObject jsonObject;
                try {
                    jsonObject = new JSONObject(responseBody);

                    JSONArray posts = jsonObject.getJSONObject("response")
                            .getJSONArray("posts");

                    for (int i = 0; i < posts.length(); i++) {
                        JSONArray photos = posts.getJSONObject(i)
                                .getJSONArray("photos");
                        for (int j = 0; j < photos.length(); j++) {
                            JSONObject photo = photos.getJSONObject(j);
                            String url = photo.getJSONArray("alt_sizes")
                                    .getJSONObject(0).getString("url");

                            Tumblr tumblr = new Tumblr(url);
                            tumblrs.add(tumblr);

                        }
                    }

                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }



        return null;
    }

}

public class Tumblr {

    public String image_url;

    public Tumblr(String url) {

        this.image_url = url;

    }
}

private class loadMoreListView extends AsyncTask<Void, Void, Void> {

    @Override
    protected void onPreExecute() {
        // Showing progress dialog before sending http request
        pDialog = new ProgressDialog(MainActivity.this);
        pDialog.setMessage("More chicks coming up..");
        pDialog.setIndeterminate(true);
        pDialog.setCancelable(false);
        pDialog.show();
    }

    @Override
    protected Void doInBackground(Void... unused) {
        // TODO Auto-generated method stub

                // increment current page
                offset += 2;

                // Next page request
                tumblrs.clear();
                String searchUrl = "http://api.tumblr.com/v2/blog/factsandchicks.com/posts?api_key=rTZsymOWtMudbb5tql2U20qQ5ooYLPYVNnL3COPpO2qBHDxJUu&limit=2&offset="
                        + offset;

                HttpClient client = new DefaultHttpClient();
                HttpGet get = new HttpGet(searchUrl);

                HttpResponse r = null;
                try {
                    r = client.execute(get);
                    int status = r.getStatusLine().getStatusCode();
                    if (status == 200) {
                        HttpEntity e = r.getEntity();
                        responseBody = EntityUtils.toString(e);
                    }
                } catch (ClientProtocolException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }

                JSONObject jsonObject;
                try {
                    jsonObject = new JSONObject(responseBody);

                    JSONArray posts = jsonObject.getJSONObject("response")
                            .getJSONArray("posts");

                    for (int i = 0; i < posts.length(); i++) {
                        JSONArray photos = posts.getJSONObject(i)
                                .getJSONArray("photos");
                        for (int j = 0; j < photos.length(); j++) {
                            JSONObject photo = photos.getJSONObject(j);
                            String url = photo.getJSONArray("alt_sizes")
                                    .getJSONObject(0).getString("url");

                            Tumblr tumblr = new Tumblr(url);
                            tumblrs.add(tumblr);

                        }
                    }

                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                // Setting new scroll position
                listView.setSelectionFromTop(0, 0);



        return null;
    }

    protected void onPostExecute(Void unused) {
        pDialog.dismiss();

    }

}

@Override
public boolean onCreateOptionsMenu(android.view.Menu menu) {
    // TODO Auto-generated method stub
    super.onCreateOptionsMenu(menu);
    MenuInflater blowUp = getMenuInflater();
    blowUp.inflate(R.menu.cool_menu, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // TODO Auto-generated method stub
    switch (item.getItemId()) {
    case R.id.aboutUs:
        Intent i = new Intent("com.example.example.ABOUT");
        startActivity(i);

        break;
    case R.id.refresh:
        Intent f = new Intent(MainActivity.this, MainActivity.class);
        startActivity(f);
        finish();
        break;
    case R.id.exit:
        finish();
        break;
    }
    return false;
}

}

日志看起来像这样:

 10-07 10:27:56.163: E/AndroidRuntime(923): FATAL EXCEPTION: AsyncTask #2
 10-07 10:27:56.163: E/AndroidRuntime(923): java.lang.RuntimeException: An error  occured while executing doInBackground()
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.os.AsyncTask$3.done(AsyncTask.java:278)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at  java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at  java.util.concurrent.FutureTask.run(FutureTask.java:137)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at  java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at java.lang.Thread.run(Thread.java:856)
 10-07 10:27:56.163: E/AndroidRuntime(923): Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that  created a view hierarchy can touch its views.
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:3939)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:701)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.view.View.requestLayout(View.java:12555)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.view.View.requestLayout(View.java:12555)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.view.View.requestLayout(View.java:12555)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.view.View.requestLayout(View.java:12555)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.view.View.requestLayout(View.java:12555)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.widget.AbsListView.requestLayout(AbsListView.java:1690)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.widget.ListView.setSelectionFromTop(ListView.java:1928)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at com.fansheroid.facts.chicks.MainActivity$loadMoreListView.doInBackground(MainActivity.java:291)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at com.fansheroid.facts.chicks.MainActivity$loadMoreListView.doInBackground(MainActivity.java:1)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at android.os.AsyncTask$2.call(AsyncTask.java:264)
 10-07 10:27:56.163: E/AndroidRuntime(923):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
 10-07 10:27:56.163: E/AndroidRuntime(923):     ... 5 more

1
没有合适的装备,很难“GetChicks” :) - Nate
抱歉,Fansher。这只是一个玩笑,如果英语不是您的母语,可能无法理解。句子末尾的小“:)”表示有人正在尝试幽默。不过,并不意味着他们已经成功了。 - Nate
哈哈,我明白了。当时我太忙于寻找我的错误,所以我的幽默感被关闭了 ;) - STHOH
可能是重复的问题:Android XML解析器异常捕获 - rene
如果您在更新问题时附上答案,那么有相同问题的人如何查看错误信息呢?! - Mickäel A.
1个回答

5

doInBackground()方法中,使用AsyncTask来运行长时间的过程,以避免拦截UI线程。您正在调用runOnUiThread()方法。我认为,去掉runOnUiThread()就可以完成任务。


我也需要删除 public void run() { 吗?还是这一行需要保留? - STHOH
是的,您还需要将其删除,并且不要忘记关闭括号。 - Hesham Saeed
当我删除了这两行时,应用程序会崩溃并显示以下异常信息: 10-07 09:54:47.913: E/AndroidRuntime(723): Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. - STHOH
我已经更新了问题中的代码并添加了日志。当应用程序启动时,它不会执行 GetChicks,并且在尝试执行 loadMoreListView 时出现错误。 - STHOH
listView.setSelectionFromTop(0, 0);放在onPostExecute()方法中。因为你正在处理另一个线程中的UI元素ListView - Hesham Saeed
显示剩余5条评论

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