Android Programming In Java - Simple Animation
Written by Mike James   
Monday, 11 June 2018
Article Index
Android Programming In Java - Simple Animation
runOnUiThread

 

The UI thread creates the UI and to avoid problems of synchronization only the UI thread can interact with the UI. That is, only the UI thread can access the UI. This is a fairly common approach to implementing a UI and not at all unique to Android. 

So what happens is that the Timer tries to run its TimerTask and this in turn runs the update function, but using the thread the Timer runs on rather than the UI thread.  Everything is fine until the last instruction of update, which attempts to use a method that belongs to an ImageView object and this it cannot do because it is not the UI thread. Hence the error message.

At this point many Android programmers give up and try a completely different approach. Some of these approaches do have advantages, see the Handler class for example for a good alternative. However, the Android framework provides a method for just such a situation: 

runOnUiThread(Runnable);

This is a method of the Activity object and you can use it from any thread that has access to the Activity object's methods to run a function on the UI thread. If the thread happens to be the UI thread then no harm done, the function is just called. If it isn't the UI thread then the call will be deferred until the UI thread is available and then the function will be run. As always the function shouldn't keep the UI thread busy for too long or the UI will become sluggish or even freeze completely. 

The Java Runnable is an Interface that has a single run method that is the function that is executed on the UI thread – this means it is a SAM (Single Abstract Method) and we can use a lambda to simplify the code, but first let’s use another anonymous class:

runOnUiThread(
 new Runnable() {
  @Override 
  public void run() {
   update();
  }
 }
);

This ensures that update is run on the UI thread. 

Putting this all together gives:

timer.schedule(
 new TimerTask(){ 
  @Override
  public void run() {
   runOnUiThread(
    new Runnable() {
     @Override
     public void run() {
      update();
     }
    }
  );
 }
},0,10 );

This looks like a mess of nesting and curly braces, but you should be able to follow the logic. If you want to make things look simpler, we can use a lambda for the Runnable SAM:

timer.schedule(
  new TimerTask() {
    @Override
    public void run() {
      runOnUiThread(() -> update());
  } }, 0, 10);

As the lambda is function that returns a result it can be written as an expression lambda and you don’t need brackets.

Now when you run the program you will see the red ball bounce slowly and smoothly around the screen. How good the animation is depends what you run it on. On the emulator is can be slow and irregular; on a real device it should be fine: 

 bounce

Animation complete with a trail to show how the ball moves

 

Now you know at least one way to allow a non-UI thread interact with the UI. There are so many ways to implement animation that this is just one of many starting points, but with an understanding of this one the others will seem easier. If you wanted to use this approach, the structure of this demonstration program could be improved. For example, the ball really should be a Ball class complete with its position and velocity properties and its update method. This way you gain the benefits of object-orientation and you can animate lots of balls around the screen with very little extra effort.

Listing

The complete listing of the animation program is:

package com.example.mikejames.myapplication;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
    private int width = 800, height = 800;
    private float x = 463, y = 743,
                 vx = 1, vy = 1, r = 30;
    private Canvas c;
    private Paint paint;
    private ImageView imageview;
    @Override
    protected void onCreate(
             Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Bitmap b = Bitmap.createBitmap(width,
                                       height,
                       Bitmap.Config.ARGB_8888);
        c = new Canvas(b);
        c.drawColor(Color.WHITE);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        imageview =
        (ImageView) findViewById(R.id.imageView);
        imageview.setImageBitmap(b);
        Timer timer = new Timer();
        timer.schedule(
                new TimerTask() {
                   @Override
                   public void run() {
                    runOnUiThread(() -> update());
                   }
                }, 0, 10);
    }
    void update() {
        paint.setColor(Color.WHITE);
        c.drawCircle(x, y, r, paint);
        x = x + vx;
        y = y + vy;
        if (x + r >= width) vx = -vx;
        if (x - r <= 0) vx = -vx;
        if (y + r >= height) vy = -vy;
        if (y - r <= 0) vy = -vy;
        paint.setColor(Color.RED);
        c.drawCircle(x, y, r, paint);
        imageview.invalidate();
    }
}

There is so much to learn about graphics it is difficult to pick out things you need to know. If you want to find out more about how the standard UI works you need to look into the OnDraw event and how to create your own View object that render graphics. You need to find out about Android's vector graphics using shapes and path. You need to know about the different types of animation that are available and eventually you need to learn about OpenGL and its support for hardware accelerated 2D and 3D graphics. 

 

Summary

  • The subject of Android graphics is huge and there is always more than one way to approach any task. This chapter is a first look at what you might call UI-based graphics.

  • The Bitmap is the basic graphics object. It consists of a rectangle of pixels that can be set to any color.

  • The ImageView is a general purpose UI component that can be used to display a range of graphics objects including a Bitmap.

  • You can draw on a Bitmap using a Canvas object which has a large number of different drawing methods.

  • The color and drawing style used by many of the Canvas methods is determined by the properties of a Paint object.

  • The Canvas object also supports transformations which can be used to modify where a graphic is drawn, its size, rotation, etc.

  • Transformations can be used to standardize the drawing of graphics objects at the origin.

  • Transformations can also be used to change the default pixel coordinate system to anything you want to use.

  • Simple animation is possible using nothing but a Bitmap, Canvas and an ImageView.

  • Only the UI thread can modify the UI.

  • The Android Timer can be used to animate 2D graphics, but you have ensure that it runs the code on the UI thread using the runOnUIThread method.

 

androidJavaSmallAndroid Programming In Java:
Starting With an App
Third Edition

Is now available in paperback and ebook.

Available from Amazon.

 

 

  1. Getting Started With Android Studio 3
  2. The Activity And The UI
  3. Building The UI and a Calculator App
  4. Android Events
         Extract: Using Lambdas
  5. Basic Controls
  6. Layout Containers
  7. The ConstraintLayout
        Extract: Guidelines and Barriers
  8. UI Graphics A Deep Dive
        Extract: Programming the UI ***NEW
  9. Menus & The Action Bar
  10. Menus, Context & Popup
  11. Resources
  12. Beginning Bitmap Graphics
        Extract: Simple Animation
  13. Staying Alive! Lifecycle & State
  14. Spinners
  15. Pickers
  16. ListView And Adapters

If you are interested in creating custom template also see:

Custom Projects In Android Studio

Androidgears

 

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

espbook

 

Comments




or email your comment to: comments@i-programmer.info



Last Updated ( Monday, 30 July 2018 )