【问题标题】:ListView in swipe tab not updated unless restart除非重新启动,否则滑动选项卡中的 ListView 不会更新
【发布时间】:2016-11-24 10:03:10
【问题描述】:

在我的应用程序中,它有两个选项卡,一个是提醒,另一个是已完成任务。

单击切换按钮时,我希望它将列表移动到已完成的任务。

想法是:

  • 从 sqlite 获取选中的行 id
  • 根据 id 从提醒表中检索数据并插入到已完成表中。
  • 在 Completed 选项卡中调用 Retrieve 方法。

但是当我点击切换按钮并滑动到已完成时,它仍然是空的。退出应用程序并滑动到选项卡后,仅显示数据。

当滑动而不是退出应用程序并重新打开时,如何使数据立即显示在已完成选项卡中?谢谢

AllAdapter(提醒)

 holder.toggle.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (((ToggleButton)v).isChecked()) {
                        int getPosition = (Integer) v.getTag();  // Here we get the position that we have set for the checkbox using setTag.
                        search.get(getPosition).setSelected(((ToggleButton) v).isChecked());
                        int id= search.get(getPosition).getID();
                        mdb = new MyDatabaseHelper(v.getContext());
                        database = mdb.getReadableDatabase();
                        Cursor cursor = database.rawQuery("SELECT * FROM " + MyDatabaseHelper.TABLE__TASK + " WHERE ID = ? ", new String[]{id+""}, null);
                        if (cursor != null && cursor.getCount() > 0) {
                            while (cursor.moveToNext()) {
                                String allTask = cursor.getString(cursor.getColumnIndex("Title"));
                                String name = cursor.getString(cursor.getColumnIndex("Name"));
                                String allTime = cursor.getString(cursor.getColumnIndex("Time"));
                                String allDate = cursor.getString(cursor.getColumnIndex("Date"));
                                insertDataToCompleteTab(id,name,allTask,allTime,allDate);    // insert to another table
                            } 

                        }
                    } else {
                        int getPosition = (Integer) v.getTag();  // Here we get the position that we have set for the checkbox using setTag.
                        search.get(getPosition).setSelected(((ToggleButton) v).isChecked());
                    }
                }
            });

已完成任务

retrieveList(name);

 public void retrieveList(String name) {
        Toast.makeText(getActivity(),name,Toast.LENGTH_SHORT).show();
        search.clear();
        database = mdb.getReadableDatabase();
        Cursor cursor = database.rawQuery("SELECT * FROM " + MyDatabaseHelper.TABLE_TASKCOMPLETED + " WHERE Name = ? ", new String[]{name}, null);
        if (cursor != null && cursor.getCount() > 0) {
            while (cursor.moveToNext()) {
                int iD = cursor.getInt(cursor.getColumnIndex("ID"));
                String allTask = cursor.getString(cursor.getColumnIndex("Title"));
                String allTime = cursor.getString(cursor.getColumnIndex("Time"));
                String allDate = cursor.getString(cursor.getColumnIndex("Date"));

                if (adapter != null) {
                    adapter.add(iD, allTask, allTime, allDate);
                    listview.setAdapter(adapter);
                    adapter.getCount();
//                    check();
                }
            }
        } else {
        }
    }

AllAdapter

http://pastebin.com/qbLDtf4v

已完成标签

http://pastebin.com/WCCbZ0h4

完整适配器

http://pastebin.com/QdbuTQKm

【问题讨论】:

  • 如果您使用列表来显示数据,请确保在列表的适配器上调用 notifyDataSetChanged(),以便它使用新数据更新视图。
  • 不要将数据从一个表移动到另一个表,而是只创建一个任务表,其中有一个布尔列,表示是否已完成。而切换只是从表中更新该字段。你的代码在哪里?
  • @AmrutBidri 请检查
  • @VeselinTodorov 请检查。
  • 你能告诉我们你的适配器代码吗?另外,您将数据数组/列表保存在哪里。您从光标获得的更改应该反映在适配器使用的数组/列表中,然后调用 listview.getAdapter().notifyDataSetChanged()。无需每次都设置新的适配器。

标签: android sqlite listview swipe


【解决方案1】:

默认情况下,ViewPager 中最近的选项卡会同时加载。之所以发生这种情况,是因为在您使用切换按钮进行任何切换之前,数据已加载到第二个选项卡。要解决问题,您必须更新已完成选项卡中的数据,以防发生任何数据更改。

这可以通过多种方式实现:

  • 第一个片段应在每次更改时发送一个事件,第二个片段应订阅该事件并手动更新数据

  • 使用加载器和内容提供程序(或仅使用自定义 uri)。 Loader 订阅任何 uri 更改,并且您的存储库/dao 数据库助手会通知此类 uri 任何更改(当调用 insert/update/delete 方法时)

context.getContentResolver().notifyChange(uri);

您的对象的加载器。

abstract class CachedLoader<T> extends AsyncTaskLoader<T> {

@Nullable
private T cachedData;

CachedLoader(Context context) {
    super(context);
}

void registerUri(Uri... observerUris) {
    for (Uri uri:observerUris) {
        getContext().getContentResolver().registerContentObserver(uri, true, createContentObserver());
    }
}

ContentObserver createContentObserver() {
    return new ForceLoadContentObserver();
}

@Override
public void deliverResult(T data) {
    super.deliverResult(data);
    this.cachedData = data;
}

@Override
public void onContentChanged() {
    super.onContentChanged();
    cachedData = null;
}

@Override
protected void onStartLoading() {
    if (!takeContentChanged() && cachedData != null) {
        deliverResult(cachedData);
        return;
    }

    forceLoad();
}

@Override
protected void onReset() {
    super.onReset();
    cachedData = null;
}
}

调用 register uri 以订阅该 uri 更改。

或者使用CursorLoader,因为您直接使用游标进行操作。正如我在更新的问题中看到的那样

我更喜欢第二种方法,但第一种更简单

【讨论】:

  • 我不明白你:(
【解决方案2】:

来自Android documentation for fragment lifecycle

系统显示的片段onResume()onPause() 将仅在调用活动onResume()onPause() 时被调用。它们与 Activity 紧密耦合。

由于此,当标签更改时,无法刷新您的视图。

为了解决这个问题,我在setUserVisibleHint 找到了一个解决方案 在我的申请中,因为我们有相同的要求。 Viewpager 调用片段的以下函数并在片段代码中实现它

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    // Make sure that we are currently visible
    if (this.isVisible()) {
        // If we are becoming invisible, then...
        if (!isVisibleToUser) {
            Log.d("TAG", "Stop animation and audio you are not visible");

        }
    }
}

这就是文档所说的

向系统设置有关此片段的 UI 当前是否为当前状态的提示 对用户可见。此提示默认为 true 并且是持久的 跨片段实例状态保存和恢复。应用程序可以将其设置为 false 表示片段的 UI 被滚动到不可见 或者对用户不直接可见。这可以由 系统优先考虑诸如片段生命周期更新之类的操作 或加载程序排序行为。此方法可以在外部调用 片段生命周期。因此没有关于以下方面的订购保证 片段生命周期方法调用。

ViewPager 在其子片段上调用它。 有关更多信息,ViewPager 还调用setMenuVisibility,如果您在显示或删除菜单时遇到问题,可以使用它。请参阅setMenuVisiblity documnet 的链接,其中指出

设置此片段的菜单是否可见的提示。这是 如果您知道片段已放置在您的视图中,则很有用 层次结构,以便用户当前无法看到它,因此任何菜单 也不应该显示它拥有的项目。

【讨论】:

    【解决方案3】:

    所以我只是将下面的代码放在我的已完成任务片段中

     @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
            if(isVisibleToUser){
                retrieveList(name);//call the method to be refreshed
            }
            else{
                //no
            }
    
        }
    

    从@Swapnil 获得提示并从https://stackoverflow.com/a/40763755/5261462 回答

    【讨论】:

      【解决方案4】:

      像这样在片段 onResumse 上放下面的代码

       @Override
        public void onResume() {
      
           super.onResume();
           retrieveList(name);
        }
      

      【讨论】:

        【解决方案5】:

        你可以做的是按照以下方式创建一个界面

        public interface ReminderCompletedListener
        {
            void reminderCompleted();
        }
        

        CompletedTask 中创建该侦听器的实例并将其注册到您的活动中。

        ((MyActivity) getActivity()).setReminderCompletedListener(new ReminderCompletedListener()
        {
            @Override
            public void reminderCompleted()
            {
                retrieveList(name);
            }
        });
        

        在您的 Activity 中创建一个可以从切换点击监听器调用的方法

        ((MyActivity) getActivity()).reminderCompleted();
        

        当您从“提醒”选项卡完成任务时,这将触发“已完成”列表重新加载。从此解决方案中要考虑的一个主要考虑因素是,它将您的 Fragments 与您的 Activity 直接耦合。

        还有其他解决方案,您可以使用诸如总线(eventbus/otto)之类的东西,也可能是 rxjava,如果您愿意,您可以探索这些,但我给出的原版解决方案应该可以很好地完成工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-03-09
          • 1970-01-01
          • 1970-01-01
          • 2015-03-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多