Android:在getView()中执行异步操作的最佳实践

Lis*_*nne 6 concurrency multithreading android asynchronous

请不要关闭这个,恕我直言这是体面的,可能有用的编程问题.


请我阅读很多东西,因为我读了不同的意见和不同的方法,我感到很困惑.

问题如下:

getView()一个Adapter我需要执行一些异步操作,如检查在网络上的形成和更新基于该视图.

我使用了以下方法:

每次getView()都叫我开始了Thread

但我的做法为我赢得了很多批评:

/sf/answers/1993904181/

/sf/answers/1993903481/

/sf/answers/1993904601/

public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder holder;            
    if (convertView == null) {                
        //...         
    } 
    else {                
        //...
    }     

    Thread th= new Thread(new Runnable() {

           @Override
           public void run() {
                mActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {

                        CheckSomeInfoOverTheInternet(url, new myCallback {


                            @Override
                            public void onSuccess() {
                            holder.textview.setText("OK");
                            }

                            @Override
                            public void onFailre() {
                            holder.textview.setText("NOT OK!!!!");
                            }    

                        });
                    }
                });


           }
       });

    th.start();

    return convertView;
}  
Run Code Online (Sandbox Code Playgroud)

请问做这样事情的最佳做法是什么?


请注意,我不是在寻找执行网络请求的解决方案getView(),而是根据异步调用的结果更新视图.

Ale*_*x K 5

这绝对不是一个更新信息的好方法ListView.该getView方法应该只根据您已有的数据创建视图.当然不应该运行任何东西来获取更多信息.

我能给你的最好建议是事先获取数据.拉取数据,更新ArrayListAdapter所连接的数据,然后调用adapter.notifyDataSetChanged().这将重绘您的所有信息.

一次性拉动数据 - 不是小部件.这是执行此操作的最佳和最合理的方法.


Dro*_*kas 2

为此有几种方法。虽然你现在做的事情确实不合适。

  1. 异步任务

    • 这里的线程池是在内部完成的,所以你不需要为此操心
    • 它是解决问题的更清晰的方法,而不是生成单独的线程。
    • 如果您的用户在 API 调用期间更改屏幕,您也可以取消调用
    • 您必须启用notifyDatasetChanged()
    • 您需要重写很少的函数来实现您想要的功能。
  2. 异步任务加载器

    • 它为您提供了更多控制权,但您失去了几个隐式定义的函数
    • 您需要更多知识才能使用它,并且应该精通LoaderManagerLoader等类。
    • 更改是自动触发的 假设您要更改基础数据集,这些更改将自动触发并为您的 UI 提供更改。
  3. 处理程序和线程

    • 这比您当前的方法高一级,但提供更多好处
    • 您可以抽象线程创建并提供一个处理程序来处理所有 id 的调用。
    • 您可以对线程和传递的消息进行排队。
    • 如果屏幕发生变化,您可以删除回调和消息

总之,当前方法的主要缺点: - 需要进行更改时会丢失上下文。- 显式创建多个线程

虽然后者是一个主要问题,但更“用户引人注目”的问题将是第一个。

根据您需要的控制以及您在 android 回调和线程管理方面的专业知识,还有并且可能有几种其他方法。但这三种(根据我的说法)是最合适的。

PS:所有这些方法的共同点是,

public View getView(int position, View convertView, ViewGroup     parent) { 
    ViewHolder holder;            
    if (convertView == null) {                
        //...         
    } 
    else {                
        //...
    }     

    //execute a task for your given id where task could be:
    //1. AsyncTask
    //2. AsyncTaskLoader
    //3. Handlers and thread
    //call notifyDataSetChanged() in all the cases,




    return convertView;
}

 @Override
 public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
        //do any tasks which you feel are required
 } 
Run Code Online (Sandbox Code Playgroud)

PPS:您还可以查看DataSetObserver来再次自动化您的需求。