ListView.post只能使用一次,但只能在某些设备

时间:2017-09-08 03:43:48

标签: android listview

我创建了一个ListView,可以动态添加/删除其集合,并使用自定义ArrayAdapterRunnable动态调整其高度:

以下是我的自定义ArrayAdapter ItemListAdapter初始化的方式:

  private Activity activity;
  public ListView listView;

  public ItemListAdapter(Activity activity, ListView listView...) { //other items are irrelevant
    super(context, resource, values); //typical initalization
    this.activity = activity;
    this.listView = listView;
    ... other codes are irrelevant
  }

重要的是,适配器接受一项活动,并在该活动的布局中使用ListView

然后,当然,我还有以下重写的notifyDataSetChanged代码,当在适配器中更改数据集时调用该代码:

  @Override
  public void notifyDataSetChanged() {
    if(listView != null) {
      listView.post(ListViewHelper.GetRunnableSetCorrectHeight(listView)); //works well but only once
//      activity.runOnUiThread(ListViewHelper.GetRunnableSetCorrectHeight(listView)); //this also not working
    }
  }

由于在更改数据集时绘制UI之前无法知道新高度,因此上述notifyDataSetChanged使用listView方法动态设置ListView.post的正确高度

Runnable参数取自static GetRunnableSetCorrectHeight中的ListViewHelper方法class,如下所示:

  public static Runnable GetRunnableSetCorrectHeight(final ListView listView){
    return new Runnable() {
      @Override
      public void run() {
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = DataHolder.LvBaseOffset + getHeight(listView, listView.getAdapter()); //this is the actual set up of the view, the view should be changed because of this, except for the first time...
        listView.setLayoutParams(params); //if this is not there, the first show in the main activity will nor be complete (only show the first item)
//        listView.requestLayout(); //not needed
      }
    };
  }

并且,可能与该问题没有直接关系,但仅仅是为了完整性'为此,上述方法中调用的getHeight方法如下:

  public static int getHeight(ListView listView, ListAdapter adapter){
    int totalHeight = 0;
    int listWidth = listView.getMeasuredWidth();

    for (int i = 0; i < adapter.getCount(); i++) {
      View mView = adapter.getView(i, null, listView);
      mView.measure(View.MeasureSpec.makeMeasureSpec(listWidth, View.MeasureSpec.EXACTLY),
          View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
      totalHeight += mView.getMeasuredHeight();
    }

    return totalHeight + (listView.getDividerHeight() * (adapter.getCount() - 1));
  }

在活动的布局中,我有一个AddDelete按钮,可触发调用notifyDataSetChanged添加/删除项目并重新绘制ListView正确的身高:

enter image description here

例如,如果按下Add按钮,结果将如下:

enter image description here

以上代码运行良好,至少在我的Android模拟器,华为平板电脑和小米手机中。当我说得好时,这意味着可以多次点击Add按钮,它将始终产生新行并调整高度。

enter image description here

但是当我尝试在其他设备上部署时,只能使用一次。我的意思是,如果我第一次按下AddDelete按钮 ,则会在ListView中添加/删除该项目。但是,当我第二次单击时,应用程序崩溃并显示典型的错误消息框:

Unfortunately, [Application Name] has stopped.

                                                   OK

现在,我阅读了一些有关此问题的帖子,其中提到问题可能是由于未在UI线程中运行Runnable引起的。因此,如上所示,我在ItemListAdapter的构造中添加了活动,我也尝试更改方法:

  @Override
  public void notifyDataSetChanged() {
    if(listView != null) {
      listView.post(ListViewHelper.GetRunnableSetCorrectHeight(listView)); //works well but only once
//      activity.runOnUiThread(ListViewHelper.GetRunnableSetCorrectHeight(listView)); //this also not working
    }
  }

  @Override
  public void notifyDataSetChanged() {
    if(listView != null) {
      //listView.post(ListViewHelper.GetRunnableSetCorrectHeight(listView)); //works well but only once
      activity.runOnUiThread(ListViewHelper.GetRunnableSetCorrectHeight(listView)); //this also not working
    }
  }

但问题仍然存在。我也试着延迟:

  @Override
  public void notifyDataSetChanged() {
    if(listView != null) {
      //listView.post(ListViewHelper.GetRunnableSetCorrectHeight(listView)); //works well but only once
      activity.runOnUiThread(ListViewHelper.GetRunnableSetCorrectHeight(listView)); //this also not working

      try {
        sleep(500); // does not help
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

使用Handler(Looper.getMainLooper()).post

  @Override
  public void notifyDataSetChanged() {
    if(listView != null) {
      //listView.post(ListViewHelper.GetRunnableSetCorrectHeight(listView)); //works well but only once
      new Handler(Looper.getMainLooper()).post(ListViewHelper.GetRunnableSetCorrectHeight(listView)); //this also not working

      try {
        sleep(500); // does not help
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

但是没有什么有效,而且我的想法用完了......

为什么会这样?为什么post只能使用一次虽然我试图在UI线程上运行,使用主循环,或者延迟?如何解决?

1 个答案:

答案 0 :(得分:0)

RecyclerViewListView的高级版本。你可以找到它的official doc

如果您想参加演示check this blog