Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListView in swipe tab not updated unless restart

In my app, it has two tabs, one is Reminder and the other is Completed Task.

enter image description here

When the toggle button is clicked, I want it move the list to Completed Task.

The idea are :

  • Get the checked row id from sqlite
  • Retrieve the data based on id from Reminder Table and insert into Completed Table.
  • Call Retrieve method in Completed Tab.

But when I clicked the toggle button and swipe to Completed, it still empty. After I exit the app, and swipe to the Tab,only the data shown.

How can I made the data straight away show in Completed Tab when swipe instead of exit the app and re-open again ? Thanks

AllAdapter (Reminder)

 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());
                    }
                }
            });

CompletedTask

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

Completed Tab

http://pastebin.com/WCCbZ0h4

CompleteAdapter

http://pastebin.com/QdbuTQKm

like image 439
Hoo Avatar asked Nov 24 '16 10:11

Hoo


2 Answers

By default closest tabs inside ViewPager are loaded at the same time. So that happened because the data had been loaded to the second tab before you made any switches with your toggle button. To fix an issue you have to update data in the completed tab in case any data changes.

This could be achieved with several ways:

  • First fragment should send an event on each change and second should subscribe on that event and update data manually

  • Use loader & content provider ( or just custom uri's). Loader subscribes to any uri changes and your repository/dao database helpers notify such uri's about any change (when insert/update/delete methods have been called)

context.getContentResolver().notifyChange(uri);

Loader for your objects.

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;
}
}

call register uri to subscribe on that uri changes.

Or use a CursorLoader, because you operate with cursors directly. As i see in updated question

I prefer second approach, but first one is simpler

like image 107
Beloo Avatar answered Oct 03 '22 21:10

Beloo


From the Android documentation for fragment lifecycle

System Displayed fragments onResume() or onPause() will be called only when the Activities onResume() or onPause() is called. They are tightly coupled to the Activity.

Due to this you are not able to refresh your view when tab is changing.

To resolve this problem i found one solution in setUserVisibleHint in my application as we were having same requirement. Viewpager calls following function of your fragment and implement it in your fragment code

@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");

        }
    }
}

This is what documentation says

Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore.An app may set this to false to indicate that the fragment's UI is scrolled out of visibility or is otherwise not directly visible to the user. This may be used by the system to prioritize operations such as fragment lifecycle updates or loader ordering behavior.This method may be called outside of the fragment lifecycle. and thus has no ordering guarantees with regard to fragment lifecycle method calls.

ViewPager calls this on its childfragment. For more information, ViewPager also calls setMenuVisibility you can use it if you are facing issue in displaying or removing Menu. please see the link for setMenuVisiblity documnet which states that

Set a hint for whether this fragment's menu should be visible. This is useful if you know that a fragment has been placed in your view hierarchy so that the user can not currently seen it, so any menu items it has should also not be shown.

like image 33
Swapnil Avatar answered Oct 03 '22 20:10

Swapnil