How-To: Refresh action like Gmail App

When building an application, heavy stuff like network communication and complex calculations should be done in a separate thread. If that heavy stuff is triggered by a user, you should display something to let the user know that his action is registered and that it takes some time to finish. Most common thing to do is to show a little animation, maybe accompanied with a short text like “Loading…”.

On Android tablets with the action bar, a common action is the refresh functionality. When the refresh is triggered, a progress indicator replaces the static refresh image; displaying the progress in the same place as the button was.

So lets look at how to replace the refresh action with a progress indicator.

How-To

First, the action must be created and placed in the action bar. This is done by implementing the onCreateOptionsMenu  method:

MainActivity.java

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
  // a title for if the action is placed in the overflow menu
  String refreshActionTitle = "Refresh";

  // create a new menu item and add it to the menu. Here, the item is not placed in a group; has an id based on the title and placed at index zero.
  MenuItem refreshItem = menu.add(Menu.NONE, refreshActionTitle.hashCode(), 0, refreshActionTitle);

  // TODO: get the image from the resources
  Drawable refreshImage = new BitmapDrawable;

  // set the refresh image
  refreshItem.setIcon(refreshImage);
}

Now we need to handle the on click action. This is done by implementing the onOptionsItemSelected  method:

MainActivity.java

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
  String refreshActionTitle = "Refresh";

  if (item.getItemId() == refreshActionTitle.hashCode())
  {
    showProgressIndicatorInAction(item);

    Runnable background = new Runnable()
    {
      @Override
      public void run()
      {
        doYourWorkHere();
        hideProgressIndicatorInAction(item);
      }
    };

    new Thread(background).start();
  }
}

public void showProgressIndicatorInTool(MenuItem refreshItem)
{
  // place the animation in a container, centered.
  final FrameLayout container = new FrameLayout(this);
  // the default width of an action is 80 dimension pixels.
  container.setLayoutParams(new FrameLayout.LayoutParams(ScreenUtilities.convertDimensionPixelsToPixels(80),
      LayoutParams.WRAP_CONTENT, Gravity.CENTER));
  container.setPadding(0, 0, ScreenUtilities.convertDimensionPixelsToPixels(20), 0);

  ProgressBar progressBar = new ProgressBar(this);
  int dp = ScreenUtilities.convertDimensionPixelsToPixels(40);
  progressBar.setLayoutParams(new FrameLayout.LayoutParams(dp, dp, Gravity.CENTER));
  container.addView(progressBar);

  runOnUiThread(new Runnable()
  {
    @Override
    public void run()
    {
      item.setActionView(container);
    }
  });
}

@Override
public void hideProgressIndicatorInAction(MenuItem refreshItem)
{
  runOnUiThread(new Runnable()
  {
    @Override
    public void run()
    {
      item.setActionView(null);
    }
  });
}
ScreenUtilities.java

public final static int convertDimensionPixelsToPixels(float dimensionPixels)
{
  final float scale = getResources().getDisplayMetrics().density;
  return (int) (dimensionPixels * (scale) + 0.5f);
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s