3

In my new app I need to show a animation while doing some processing(e.g sending data to the server, reading data from a web service, etc).

Something like this:

enter image description here

This is what I used to do when I wanted to implement something similar:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >   

    <RelativeLayout
        android:id="@+id/sincronizarSpinnerLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone" >

        <ProgressBar
            android:id="@+id/pbHeaderProgress"
            style="@android:style/Widget.ProgressBar.Inverse"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true" >
        </ProgressBar>
    </RelativeLayout>


    <RelativeLayout>

      <!--Main content here-->

    </RelativeLayout>  

</LinearLayout>

As you can see I have two nested relative layouts. The first layout is invisible (android:visibility="gone") by default and I only make it visible when I start a Service, AsyncTask or asynchronous technique.

Although I have used this method in the past, now that my main layouts (the ones that should go inside the second relative layout) are more complicated, I'm not sure it'd be a good idea to make things even more complicated by adding another nesting level to my activity.

  1. Is there any way I can avoid having to add another layout to all of my activities that need to display a spinner animation? Perhaps there's some kind of pattern or good practice I'm not aware of.

  2. Do I really need to worry about adding another nesting level to my activity, knowing that I already have two or three levels?

Thanks.

eddy
  • 4,373
  • 16
  • 60
  • 94

4 Answers4

4

You can simply use ProgressDialog and use setCanceledOnTouchOutside(false) so user cannot touch outside while your AsyncTask is working.

Here is my structure code that I use almost in my project that use AsyncTask. You can apply to your project:

public class DownloadTask extends AsyncTask<Void, Void, Void> {
    private ProgressDialog mProgressDialog;

    private Context mContext;

    public DownloadTask(Context context) {
        this.mContext = context;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        mProgressDialog = ProgressDialog.show(mContext, "Downloading", "Downloading Data ...");
        mProgressDialog.setCanceledOnTouchOutside(false); // main method that force user cannot click outside
        mProgressDialog.setCancelable(true);
        mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dlg) {
                DownloadTask.this.cancel(true);
            }
        });
    }

    @Override
    protected Void doInBackground(Void... params) {
        // do some background work here

    }

    @Override
    protected void onPostExecute(Void result) {
        if (this.isCancelled()) {
            result = null;
            return;
        }

        if (mProgressDialog != null) {
            mProgressDialog.dismiss();
        }

    }
}

Hope this help :)

hqt
  • 29,632
  • 51
  • 171
  • 250
1

I'd change your structure to this -

<frame layout>
<spinner center in parent/>
<realtive layout>
<main content/>
</realtive layout>
</frame layout>

Does that make sense? Its ok to wrap the main content in a frame layout to add the progress spinner

Also, you can use the <include> tag to keep the xml files cleaner. https://developer.android.com/training/improving-layouts/reusing-layouts.html

Shmuel
  • 3,916
  • 2
  • 27
  • 45
  • Yes, I totally forgot about . That's a great idea!!! :) By you mean ? – eddy Jan 27 '16 at 18:27
  • yah, frame layout. it is more efficient then linear or realtive layouts. – Shmuel Jan 27 '16 at 18:29
  • I think it never occurred to me to use FrameLayout, because I always thought that it should always have a single child. But since only one view will be visible at a time(either the spinner or the relative layout) I guess that won't be a problem. – eddy Jan 27 '16 at 18:53
1

This all depends on your use case.

While displaying a loading indicator in the background is a good thing to do when loading a list, it might be irritating to hide everything and display a progress bar after clicking 'Submit' on a button.

So yes, one way is to use code like yours. You should although try optimizing your layouts, e.g. make use of FrameLayout where appropriate. But this is not the topic here.

Another way to block user interaction would be to display a progress dialog which can be further customized with a message:

// you can also set title / message
new ProgressDialog.Builder(this).setCancelable(false).show();

Also, you can just disable your UI elements. And enable them again after finishing your time consuming operations using

view.setEnabled(false); // disable view while doing work
David Medenjak
  • 33,993
  • 14
  • 106
  • 134
  • But even the youtube app does that when it needs to load your subscriptions :(. So you would recommend using a ProgressDialog? TBH I only used that class when I used AsyncTasks for everything. Nowadays I try to stay away from AsyncTasks at all costs. – eddy Jan 27 '16 at 18:33
  • @eddy *It depends on your use case.* I listed 3 options, including the progressBar like the layout you show. You should pick whatever suits your use case best, and there is no general right or wrong since it is a design choice – David Medenjak Jan 27 '16 at 18:35
  • Would `ProgressDialog` remain visible even if I leave the activity? When I use the approach described in my question,in the event `onResume()` I always check if my service is still running and change the `visibility` of the indicator accordingly. Would I be able to do something similar with `ProgressDialog`? – eddy Jan 27 '16 at 18:40
  • @eddy you would need to keep the instance of the dialog and cancel it when finishing, or leaving the activity. – David Medenjak Jan 27 '16 at 18:48
  • In another answer I got, a user mentioned that in my case it'd be better to use `FrameLayout`. You also mentioned that. Would I improve performance if I used `FrameLayout` instead? – eddy Jan 27 '16 at 18:48
  • @eddy Yes, this is one of the ways to improve your layout. you should read on some tutorials about layouts and when to use them. – David Medenjak Jan 27 '16 at 18:51
-1

Check this out. Android does it for you, all you need is to make it "indeterminate" so it spins in an infinite loop until you call it off.

<RelativeLayout
android:id="@+id/loadingPanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" >

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminate="true" />

</RelativeLayout>

Show it like so:

loadingPanel.setVisibility(View.VISIBLE);

and when done hide it:

loadingPanel.setVisibility(View.GONE);

Community
  • 1
  • 1
Frank B.
  • 204
  • 5
  • 17