6

Good day, as the title say, anyone know how to implement a progress dialog while loading data from a CursorLoader within a fragment. can't find any example in this regard. Any link or guide on how to do it will be highly appreciated. Thank you

AMerle
  • 4,354
  • 1
  • 28
  • 43
irobotxx
  • 5,963
  • 11
  • 62
  • 91

2 Answers2

4

I think @Michal's solution would be good for showing an indeterminate ProgressDialog via ProgressDialog#setIndeterminate(true) so I've added a +1. I'm not sure adding a Fragment to a Fragment like this (SomeFragment adding DialogFragment..) is approved as I've come a cropper on SO before suggesting something similar. Plus, it's ok that the ProgressDialog is used here since ultimately it is a component of the fragment thus belongs under the fragment without needing to exist as a separate Fragment entity.

To expand on this answer, if you were wanting to provide a real-time progress update then I would suggest that after each "unit of work" (the lowest denominator of work you can count at the CursorLoader level) you should fire an event via the LocalBroadcastManger (keep it local, no one else needs to know) which your Fragment will be listening for.

On receiving the event under the Fragment's nested BroadcastReceiver#onReceive() method can get a reference to your Fragment's ProgressDialog and increment the displayed progress with incrementProgressBy(diff) or similar.

If however, you just want to pop-up a "I'm doing something" dialog then setting the ProgressDialog to use setIndeterminate(true) will suffice.

Finally, have you considered using the pattern of adding the indeterminate progress dialog to the ActionBar? That is how a lot of the core apps operate whilst an underlying CursorLoader is working. It would be nice to keep it consistent. Check out items pertaining to requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS).

Cheers.

Update

To achieve the last approach you need to set-up your parent activity (the bit owning the ActionBar) with code similar to (I'm just writing this from memory!);

    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Note that this is requested before you have called setContentView...
    getWindow().requestFeature(Window.FEATURE_PROGRESS);
    setContentView(R.layout.yourLayout);

At this point you have said, "I would like that spinny progress thing in my Activity ActionBar". Now depending on your activity implementation you can choose to show the indeterminate progress bar immediately in onCreate by writing;

    setProgressBarIndeterminateVisibility(true);

But this may be too simplistic if an additional action causes the CursorLoader to be started. What is important to note throughout this exercise is that the progress dialog in the ActionBar is a feature of the owning activity and not your underlying Fragment. You don't want your fragment assuming that the INDETERMINATE_PROGRESS feature has been requested since (a) it may not have and (b) it's not it's prerogative to understand such things. In other words if you find yourself writing getActivity().setProgressBarIndeterminateVisibility(true) stop and think.

I think you should leverage a more decoupled approach where the underlying Fragments says, "I have started to perform a load" so in your CursorLoader callback, onCreateLoader something like;

       @Override
       public Loader<Result> onCreateLoader(int id, Bundle b) {
        // Fire event saying this load is starting.
        final Intent loadStarted = new Intent();
        loadStarted.setAction(YourFragment.LOAD_STARTED);
        return new SomeCursorLoader(this.getActivity());
       }

Your activity can be listening for this event and then when it receives it, sets the indeterminate progress bar visibility to true.

Similiarly, when the CursorLoader callback, onLoaderFinished is called then fire another event like;

    @Override
    public void onLoadFinished(Loader<Result> loader, Result data) {
     // Fire event saying this load is finished.
     final Intent loadFinished = new Intent();
     loadFinished.setAction(YourFragment.LOAD_FINISHED);
    }

Finally your activity can then sets the indeterminate progress bar visibility to false onReceivieing this event and the cursor results are shown to the user...

BrantApps
  • 6,362
  • 2
  • 27
  • 60
  • your last point on adding it in the actionbar is exactly what i am looking for. if you can help me with any links that does that, would be highly appreciated but i did look around. I will also keep in mind your other solutions. I have this done in an AsyncTask but i would like to switch to CursorLoaders. thanks once again. – irobotxx Aug 03 '12 at 12:01
  • Hi, I think that invoking `show()` of DialogFragment in other Fragment is fine. Cause `getFragmentManager` returns Activity`s fragmentManager, so `show()` method begins new FragmentTransaction adds DialogFragment and commits transaction. BTW I like your solution for showing progress. – Michal Aug 03 '12 at 12:01
  • Cool.That clears that up then. Yea, I had a more involved issue with Google TV layouts that was met with some resistance so have always been on the look out to correct my code since. @manuelJ, great. Plenty of example implementations out there after a quick Google. – BrantApps Aug 03 '12 at 12:10
  • @manuelJ cf. my updated answer. More work but in my opinion, the best route for making your code robust and reusable. – BrantApps Aug 03 '12 at 12:34
  • @OceanLife thanks a lot!! now am having dilemma who i should mark since i guess both of you voted each others answer. :) – irobotxx Aug 03 '12 at 12:43
  • Haha. We're just glad we can be of use. :) – BrantApps Aug 03 '12 at 12:45
0

I think you can implement LoaderCallback in your Fragment there you can use callback methods like onCreateLoader to show dialog, and onLoadFinished to dismiss dialog. Look at code below:

public class SomeFragment extends Fragment implements LoaderCallbacks<Result> {
     private DialogFragment dialog;

     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         //you should implement yours DialogFragment
         dialog = new DialogFragment();
         //Start loader
         getLoaderManager().initLoader(0, null, this);
    }

    @Override
    public Loader<Result> onCreateLoader(int id, Bundle b) {
         //Show dialog 
         dialog.show(getFragmentManager(), "TAG");
         return new SomeCursorLoader(this.getActivity());
    }

    @Override
    public void onLoadFinished(Loader<Result> loader, Result data) {
        handler.sendEmptyMessage(0);            
    }

    @Override
    public void onLoaderReset(Loader<Result> arg0) {
    }

    private Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            dialog.dismiss();
        }
    };
}
Michal
  • 2,074
  • 2
  • 22
  • 29
  • 4
    This doesn't work as you cannot do Fragment operations during onLoadFinished - see http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onLoadFinished%28android.content.Loader%3CD%3E,%20D%29 – Valentin Galea Dec 06 '12 at 21:24
  • Hi, you are right, I`ve got one more idea in mind - to use a `Handler` to update GUI. Look at post with updated example. – Michal Dec 07 '12 at 08:30