来自Adapter的getView里面的HttpPost

时间:2013-07-01 21:18:45

标签: android android-listview androidhttpclient

我有一个包含多个项目的Listview,每个项目都有2个按钮。我想要做的是当我点击一个按钮时,它会通过HttpPost将一些数据发送到服务器。我在我的Adapter.getView()中放了一个Thread,但它不能正常工作,因为适配器在异步线程中很常见。你知道我怎么能让它发挥作用?

我的ListView:

// ... OnCreate ListView ...
// ... new ListAppTask().execute();
// ...
public class ListAppTask extends AsyncTask<Void, Void, List<ProductExtended>> {

    protected List<ProductExtended> doInBackground(Void... args) {
        Product product = new Product();
        List<ProductExtended> products = product.getLastProducts(getApplicationContext());

        return products;
    }

    protected void onPostExecute(List<ProductExtended> result) {
        data.addAll(result);
        adapter.notifyDataSetChanged();
        if (progressDialog != null) {
            progressDialog.dismiss();
            progressDialog = null;
        }
    }
}

我的适配器:

    public class PackageAdapter extends BaseAdapter {

        private List<ProductExtended> data;
        private Context context;

        public PackageAdapter(Context context, List<ProductExtended> data) {
            this.context = context;
            this.data = data;
        }

        @Override
        public int getCount() {
            return data.size();
        }

        @Override
        public ProductExtended getItem(int position) {
            return data.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            final ProductExtended item = getItem(position);
            ViewHolder holder;
            if (convertView == null) {
                LayoutInflater li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = li.inflate(R.layout.package_row, parent, false);
                holder = new ViewHolder();
                holder.btnBa = (LinearLayout) convertView.findViewById(R.id.idBonneaffaire);
                holder.btnJl = (LinearLayout) convertView.findViewById(R.id.idJelai);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }


            holder.btnBa.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {

                        new Thread() {

                            @Override
                            public void run() {
                                // ---------------- PROBLEM HERE -------------------
                                HttpClient httpclient = new DefaultHttpClient();
                                HttpPost httppost = new HttpPost("My URL");
                                // Execute HTTP Post Request
                                try {
                                    HttpResponse response = httpclient.execute(httppost);
                                    String reponse = EntityUtils.toString(response.getEntity());

                                } catch (UnknownHostException e) {
                                } catch (HttpHostConnectException e) {
                                } catch (ClientProtocolException e) {
                                } catch (IOException e) {
                                }
                            }
                        }.start();
                }
            });

          // Same for the second LinearLayout considered as Button



            return convertView;
        }

        static class ViewHolder {
            LinearLayout btnBa;
            LinearLayout btnJl;
        }

错误显示:

Only the original thread that created a view hierarchy can touch its views. adapter

感谢的, 阿克拉姆

2 个答案:

答案 0 :(得分:2)

此错误主要描述您正在尝试从主线程之外的其他线程更新UI。如果由于某种原因您试图触摸onClickListener所播放的线程的Run方法中的视图,则会发生这种情况。 它在您的示例中不可见,但是您可以检查您所说的内容“//对于第二个被视为按钮的LinearLayout而言相同吗?”

为了防止发生此异常,您可以在需要更新UI时使用android.os.Handler在主线程上执行Runnable。

例如:

Handler mHandler = new Handler();

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder holder;
    if(convertView == null){
        convertView = mInflater.inflate(R.layout.item_simple_row, parent, false);
        holder = new ViewHolder();
        holder.textView = (TextView) convertView.findViewById(R.id.txt);
        holder.button = (Button) convertView.findViewById(R.id.btn);
        convertView.setTag(holder);
    }else{
        holder = (ViewHolder) convertView.getTag();
    }

    final String url = getItemAtPosition(position);
    holder.textView.setText(url);
    holder.button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            final Thread worker = new Thread(new Runnable(){

                @Override
                public void run()
                {
//WATCH OUT IF YOU TOUCH YOUR VIEW HERE WITHOUT USING A HANDLER YOU MAY GET THE ERROR YOUR ARE TALKING ABOUT

                    HttpGet request = new HttpGet(url);
                    DefaultHttpClient httpClient = new DefaultHttpClient();
                    try {
                        final HttpResponse response = httpClient.execute(request);

                        mHandler.post(new Runnable() {

                            @Override
                            public void run() {
//UPDATE YOUR UI HERE
                                holder.textView.setText(url+ " : " +response.getStatusLine());
                            }
                        });

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

            worker.start();


        }
    });

    return convertView;
}

答案 1 :(得分:1)

我更喜欢保持简单。 ThreadHandler分别是重要的java和android概念,但在响应UI事件时执行http在Android中非常常见,他们发明了一个名为AsyncTask的神奇助手。

创建此类的匿名实例,其中包含对封闭的Activity类的内部引用(即,实际上,在您的活动中定义类,而不是使其成为static)。这是开发人员在设计Android UI和线程模式时所考虑的Java的这些特性。

来自上述文档:

  

执行异步任务时,任务将完成......

     doInBackground(Params...)完成执行后,

onPreExecute()在后台线程上立即调用。此步骤用于执行可能需要很长时间的后台计算。 ...

     后台计算完成后,在线程上调用

onPostExecute(Result)。后台计算的结果作为参数传递给此步骤。

[我已经省略了额外的细节,也是我的重点]。

你的适配器的getView应该引用一个异步任务,该任务将信息从一个代码块传递到UI线程上可以使用的代码块中,该代码块包含所有同步的http请求。触摸其视图(您在此处更新列表视图)。

NB 请勿忘记在任务完成后检查列表视图是否与该数据相关,或者,由于AbsListView查看回收,您将数据放入显然是错误的单元格的风险。

最佳,

汤姆。