Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
android异步任务和UI线程交互_Android_Android Listview_Android Asynctask - Fatal编程技术网

android异步任务和UI线程交互

android异步任务和UI线程交互,android,android-listview,android-asynctask,Android,Android Listview,Android Asynctask,我使用AsyncTask打开URL、访问服务器、获取内容并在主活动的列表视图中显示它们。提取的内容包括报纸标题和网站的URL,如果单击“阅读”按钮,这些内容将在第二个活动的WebView上显示。我直接编写了这个程序,它可以工作,但是当我回顾它时,我发现一些似乎不合理的地方,所以我主要想弄清楚代码是如何工作的。以下是主要活动的代码: package com.example.newsapp; public class MainActivity extends Activity { sta

我使用AsyncTask打开URL、访问服务器、获取内容并在主活动的列表视图中显示它们。提取的内容包括报纸标题和网站的URL,如果单击“阅读”按钮,这些内容将在第二个活动的WebView上显示。我直接编写了这个程序,它可以工作,但是当我回顾它时,我发现一些似乎不合理的地方,所以我主要想弄清楚代码是如何工作的。以下是主要活动的代码:

package com.example.newsapp;

public class MainActivity extends Activity {

    static final private String LOG_TAG = "main";
    private ArrayList<Content> aList;

    private class Content{

        Content() {};
        public String title;
        public String url;
    }

    private class MyAdapter extends ArrayAdapter<Content>{

        int resource;


        public MyAdapter(Context _context, int _resource, List<Content> titles) {
            super(_context, _resource, titles);
            resource = _resource;
        //  this.context = _context;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            LinearLayout newView;

            final Content content = getItem(position);

            // Inflate a new view if necessary.
            if (convertView == null) {
                newView = new LinearLayout(getContext());
                String inflater = Context.LAYOUT_INFLATER_SERVICE;
                LayoutInflater vi = (LayoutInflater) getContext().getSystemService(inflater);
                vi.inflate(resource,  newView, true);
            } else {
                newView = (LinearLayout) convertView;
            }

            // Fills in the view.
            TextView tv = (TextView) newView.findViewById(R.id.listText);
            ImageButton b = (ImageButton) newView.findViewById(R.id.listButton);
            b.setBackgroundResource(0);
            tv.setText(content.title);
            Typeface type = Typeface.createFromAsset(getAssets(),"LiberationSerif-BoldItalic.ttf"); 
            tv.setTypeface(type);

            // Sets a listener for the button, and a tag for the button as well.
            b.setTag(Integer.toString(position));
            b.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    // Reacts to a button press.
                    Intent intent = new Intent(MainActivity.this, WebPage.class);
                    Bundle bundle = new Bundle();
                    bundle.putString("URL", content.url);
                    intent.putExtras(bundle);
                    startActivity(intent);
                }
            });
            return newView;
        }       
    }

    class MyAsyncTask extends AsyncTask<String, String, String> {
         private ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
         InputStream inputStream = null;
         String result = ""; 
         Content content;

         protected void onPreExecute() {
             super.onPreExecute();
             progressDialog.setMessage("Downloading the news...");
             progressDialog.show();
             progressDialog.setOnCancelListener(new OnCancelListener() {
                 public void onCancel(DialogInterface arg0) {
                     MyAsyncTask.this.cancel(true);
                 }
             });
         }

         @Override
         protected String doInBackground(String... params) {

             String url_select = params[0];

             ArrayList<NameValuePair> param = new ArrayList<NameValuePair>();

             try {
                 // Set up HTTP post
                 // HttpClient is more then less deprecated. Need to change to URLConnection
                 HttpClient httpClient = new DefaultHttpClient();

                 HttpPost httpPost = new HttpPost(url_select);
                 httpPost.setEntity(new UrlEncodedFormEntity(param));
                 HttpResponse httpResponse = httpClient.execute(httpPost);
                 HttpEntity httpEntity = httpResponse.getEntity();

                 // Read content & Log
                 inputStream = httpEntity.getContent();
                } catch (UnsupportedEncodingException e1) {
                    Log.e("UnsupportedEncodingException", e1.toString());
                    e1.printStackTrace();
                } catch (ClientProtocolException e2) {
                    Log.e("ClientProtocolException", e2.toString());
                    e2.printStackTrace();
                } catch (IllegalStateException e3) {
                    Log.e("IllegalStateException", e3.toString());
                    e3.printStackTrace();
                } catch (IOException e4) {
                    Log.e("IOException", e4.toString());
                    e4.printStackTrace();
                }
             // Convert response to string using String Builder
             try {
                 BufferedReader bReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"), 8);
                 StringBuilder sBuilder = new StringBuilder();
                 String line = null;
                 while ((line = bReader.readLine()) != null) {
                     sBuilder.append(line + "\n");
                 }
                 inputStream.close();
                 result = sBuilder.toString();
             } catch (Exception e) {
                 Log.e("StringBuilding & BufferedReader", "Error converting result " + e.toString());
             }
             return result;
         } // protected Void doInBackground(String... params)


         protected void onPostExecute(String result) {
             //parse JSON data
             try {
                 super.onPostExecute(result);
                 Log.i(LOG_TAG, result);
                 JSONObject object = new JSONObject(result);
                 JSONArray jArray = object.getJSONArray("sites");
                 for(int i=0; i < jArray.length(); i++) {
                     JSONObject jObject = jArray.getJSONObject(i);
                     content = new Content();
                     if (jObject.has("title") && jObject.has("url")){
                         content.title = jObject.getString("title");
                         content.url = jObject.getString("url");
                         aList.add(content);
                         aa.notifyDataSetChanged();
                     }
                 } // End Loop
                 progressDialog.dismiss();
             } catch (JSONException e) {
            //   progressDialog.dismiss();
                 Log.e("JSONException", "Error: " + e.toString());
             }

         } // protected void onPostExecute(String result)
    }

    private MyAdapter aa;
    private MyAsyncTask loadTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        loadTask = new MyAsyncTask();
        loadTask.execute("http://luca-ucsc.appspot.com/jsonnews/default/news_sources.json");
        aList = new ArrayList<Content>();
        aa = new MyAdapter(this, R.layout.list_element, aList);
        ListView myListView = (ListView) findViewById(R.id.listView1);
        myListView.setAdapter(aa);
        aa.notifyDataSetChanged();
    }

    public void refresh(View v){
        if (loadTask.getStatus() == AsyncTask.Status.FINISHED){
            aList.clear();
            aa.notifyDataSetChanged();
            new MyAsyncTask().execute("http://luca-ucsc.appspot.com/jsonnews/default/news_sources.json");
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}

进入
onPostExecute()
,这对我来说更符合逻辑,但应用程序会以这种方式崩溃。我还认为删除
aa.notifyDataSetChanged()onPostExecute()
中的code>应该没有问题,因为它也在
onCreate()
方法中,但这实际上会导致列表视图为空,没有任何内容。实际上,将
loadTask.execute()
之后的任何代码放入
onPostExecute()
方法的if块会导致一些问题,或者导致应用程序崩溃。如果有人能给出一些见解或提示,那就太好了。感谢阅读。

后台任务完成工作后,在UI线程上调用onPostExecute
。您无法保证此调用相对于UI线程上的其他调用的计时

由于您已经自己实现了
getView
,因此我建议您扩展
BaseAdapter
,而不是
ArrayAdapter
,并实现其他几个必需的方法。这并不难,您可以使用任何数据结构来支持适配器。假设您使用一个
列表
来支持适配器,您可以编写一个方法来交换列表,如下所示:

public void swapList(List<Content> newList) {
    this.list = newList;
    notifyDataSetChanged();
}
Params的
字符串
是URL(与您现在所做的相同)<代码>作废以获取进度,因为您无论如何都不会发布进度<代码>列表以获得结果,因为这是您在完成任务后真正想要得到的结果

您应该在
doInBackground
中完成所有工作。没有理由将字符串反序列化为JSONArray并与
onPostExecute
中的字符串混淆,特别是因为这是在主线程上发生的。重写
doInBackground
以返回
列表
,onPostExecute中所需的全部内容如下:

public void onPostExecute(List<Content> result) {
   adapter.swapList(result);
}
public void onPostExecute(列表结果){
适配器。swapList(结果);
}

现在,您可以创建一次适配器(在
onCreate()
)并在适当的时候交换列表。

onPostExecute
在后台任务完成后在UI线程上调用。您无法保证此调用相对于UI线程上的其他调用的计时

由于您已经自己实现了
getView
,因此我建议您扩展
BaseAdapter
,而不是
ArrayAdapter
,并实现其他几个必需的方法。这并不难,您可以使用任何数据结构来支持适配器。假设您使用一个
列表
来支持适配器,您可以编写一个方法来交换列表,如下所示:

public void swapList(List<Content> newList) {
    this.list = newList;
    notifyDataSetChanged();
}
Params的
字符串
是URL(与您现在所做的相同)<代码>作废以获取进度,因为您无论如何都不会发布进度<代码>列表以获得结果,因为这是您在完成任务后真正想要得到的结果

您应该在
doInBackground
中完成所有工作。没有理由将字符串反序列化为JSONArray并与
onPostExecute
中的字符串混淆,特别是因为这是在主线程上发生的。重写
doInBackground
以返回
列表
,onPostExecute中所需的全部内容如下:

public void onPostExecute(List<Content> result) {
   adapter.swapList(result);
}
public void onPostExecute(列表结果){
适配器。swapList(结果);
}

现在,您可以创建一次适配器(在
onCreate()
)并在适当的时候交换列表。

但是您必须在
onPostExecute()
方法中更新
UI
。@PiYusHGuPtA我认为aa.notifyDataSetChanged()会更新UI,但您必须在
onPostExecute()中更新
UI
method.@PiYusHGuPtA我认为aa.notifyDataSetChanged()更新UIonPostExecute,向主线程的运行循环发送消息。这将由主线程在准备就绪时执行。很可能在onCreate完成后。非常感谢您的解释。是的,我认为将背景工作和出版物分开绝对是一种更好、更干净的方法。但我仍然不明白为什么不能用旧方法在onPostExecute方法中创建arraylist和adapter对象。您能解释一下为什么在这里扩展BaseAdapter更好吗?我在基类中找不到list字段,所以我还需要重写notifyDataSetChanged()方法?谢谢。您不需要重写
notifyDataSetChanged()
,只要在更改支持适配器的数据集时调用它即可。我只是建议扩展
BaseAdapter
,以便更好地控制其行为,因为您已经实现了
getView()
,这实际上是适配器的核心。如果愿意,您可以在每次
onPostExecute
中创建一个新适配器。onPostExecute会向主线程的运行循环发送一条消息。这将由主线程在准备就绪时执行。很可能在onCreate完成后。非常感谢您的解释。是的,我认为将背景工作和出版物分开绝对是一种更好、更干净的方法。但我仍然不明白为什么不能用旧方法在onPostExecute方法中创建arraylist和adapter对象。您能解释一下为什么在这里扩展BaseAdapter更好吗?我在基类中找不到list字段,所以我还需要重写notifyDataSetChanged()方法?谢谢。你不必担心