title: How to get an AlertDialog to work, while background is rendering, and not crash the app?
body: <p>Here is the source:</p>
  
  <pre><code>package ff.ff;
  
  import android.app.Activity;
  import android.app.AlertDialog;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.graphics.Canvas;
  import android.os.Bundle;
  import android.os.Looper;
  import android.util.Log;
  import android.view.SurfaceHolder;
  import android.view.SurfaceView;
  import android.view.Surface.OutOfResourcesException;
  
  public class Basic extends Activity {
      private Render view;
  
      public class Render extends SurfaceView implements Runnable {
  
  
          //TODO: Test if AlertDialog can be able to work while another
          //thread is running continuously.
          //
          // Failed miserably.
  
          //ERROR Received:
          /*
           * 07-08 17:34:51.035: E/AndroidRuntime(7356): FATAL EXCEPTION: Thread-12
           * 07-08 17:34:51.035: E/AndroidRuntime(7356): java.lang.RuntimeException: Main thread not allowed to quit
           * 07-08 17:34:51.035: E/AndroidRuntime(7356):  at android.os.MessageQueue.enqueueMessage(MessageQueue.java:191)
           * 07-08 17:34:51.035: E/AndroidRuntime(7356):  at android.os.Looper.quit(Looper.java:231)
           * 07-08 17:34:51.035: E/AndroidRuntime(7356):  at ff.ff.Basic$Render$1$1.run(Basic.java:45)
           * 07-08 17:34:51.035: E/AndroidRuntime(7356):  at java.lang.Thread.run(Thread.java:1027) 
           * 
           */
  
  
          private int r, g, b;
  
          private boolean running;
          private SurfaceHolder holder;
          private AlertDialog.Builder builder;
          private AlertDialog dialog;
  
          public Render(Context context) {
              super(context);
              holder = this.getHolder();
              r = g = b = 0;
              builder = new AlertDialog.Builder(context);
              builder.setTitle("Enter");
              builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                  @Override
                  public void onClick(DialogInterface dialog, int which) {
                      Log.d("Render Dialog", "Working...");
                      Log.d("Render Dialog", "Exiting the Looper loop...");
                      new Thread(new Runnable(){
                          public void run(){
                              Looper.getMainLooper().quit();
                          }
                      }).start();
                  }
              });
              dialog = builder.create();
          }
  
          public void setLoopFlag(boolean value) {
              running = value;
          }
  
          public void run() {
              boolean flag = false;
              while(running) {
                  if (holder.getSurface().isValid()) {
                      Canvas c = null;
                      try {
                          c = holder.getSurface().lockCanvas(null);
                      }
                      catch(IllegalArgumentException e) {
                          e.printStackTrace();
                      }
                      catch(OutOfResourcesException e) {
                          e.printStackTrace();
                      }
                      c.drawARGB(255, r, g, b);
                      r++;
                      g++;
                      b++;
                      if (r &gt; 250 || g &gt; 250 || b &gt; 250) {
                          r = 0;
                          g = 0;
                          b = 0;
                      }
                      if (!flag){
                          flag = true;
                          Looper.prepare();
                          dialog.show();
                          Looper.loop();
                      }
                      holder.getSurface().unlockCanvasAndPost(c);
                  }
              }
          }
      }
  
  
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          view = new Render(this);
          view.setLoopFlag(true);
          setContentView(view);
          Thread thread = new Thread(view);
          thread.setName("Render Thread");
          thread.start();
      }
  }
  </code></pre>
  
  <p>Do you know that when a game is finished, the game asks the player for a name, so that there would be a name and a score on a Scoreboard? Usually, it's like that. I have a game that renders all 3 objects onto the screen. When a certain condition was met, the game would show up a dialog, asking for a name and congratulates the player for finishing it.</p>
  
  <p>It is this simple task of popping up a dialog for the player's name that's causing a lot of headache. The source code provided is given above.</p>
  
  <p>When a thread is in a tight loop (such as a game loop), when a program wants to show a dialog to the user, what is usually the recommended way of doing this? And why is Looper.prepare() useful in such situation?</p>
  
  <p>I couldn't get the gist of this. :(</p>
  
  <hr>
  
  <p><strong>EDIT (MORE INFO):</strong></p>
  
  <p>I tried using AsyncTask, and it really confuses me even more. Not that I don't want to use AsyncTask, but how could a simple "Show a dialog while background is changing colors" job is becoming harder and harder to fix??</p>
  
  <p>Logcat:</p>
  
  <pre><code>07-08 20:20:02.445: E/AndroidRuntime(11085): FATAL EXCEPTION: AsyncTask #1
  07-08 20:20:02.445: E/AndroidRuntime(11085): java.lang.RuntimeException: An error occured while executing doInBackground()
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at android.os.AsyncTask$3.done(AsyncTask.java:200)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at java.lang.Thread.run(Thread.java:1027)
  07-08 20:20:02.445: E/AndroidRuntime(11085): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at android.os.Handler.&lt;init&gt;(Handler.java:121)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at android.app.Dialog.&lt;init&gt;(Dialog.java:122)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at android.app.AlertDialog.&lt;init&gt;(AlertDialog.java:63)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at android.app.AlertDialog.&lt;init&gt;(AlertDialog.java:59)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at android.app.AlertDialog$Builder.create(AlertDialog.java:786)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at ff.ff.Basic$DialogTask.doInBackground(Basic.java:112)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at ff.ff.Basic$DialogTask.doInBackground(Basic.java:1)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at android.os.AsyncTask$2.call(AsyncTask.java:185)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
  07-08 20:20:02.445: E/AndroidRuntime(11085):    ... 4 more
  07-08 20:20:03.276: E/msm8660.gralloc(11085): [unregister] handle 0x341330 still locked (state=c0000001)
  </code></pre>
  
  <p>Source:</p>
  
  <pre><code>package ff.ff;
  
  import android.app.Activity;
  import android.app.AlertDialog;
  import android.app.AlertDialog.Builder;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.graphics.Canvas;
  import android.os.AsyncTask;
  import android.os.Bundle;
  import android.os.Handler;
  import android.util.Log;
  import android.view.Surface.OutOfResourcesException;
  import android.view.SurfaceHolder;
  import android.view.SurfaceView;
  
  public class Basic extends Activity {
      private Render view;
  
      public class Render extends SurfaceView implements Runnable {
  
  
          //TODO: Test if AlertDialog can be able to work while another
          //thread is running continuously.
          //
          // Failed miserably.
  
          //ERROR Received:
          /*
           * 07-08 17:34:51.035: E/AndroidRuntime(7356): FATAL EXCEPTION: Thread-12
           * 07-08 17:34:51.035: E/AndroidRuntime(7356): java.lang.RuntimeException: Main thread not allowed to quit
           * 07-08 17:34:51.035: E/AndroidRuntime(7356):  at android.os.MessageQueue.enqueueMessage(MessageQueue.java:191)
           * 07-08 17:34:51.035: E/AndroidRuntime(7356):  at android.os.Looper.quit(Looper.java:231)
           * 07-08 17:34:51.035: E/AndroidRuntime(7356):  at ff.ff.Basic$Render$1$1.run(Basic.java:45)
           * 07-08 17:34:51.035: E/AndroidRuntime(7356):  at java.lang.Thread.run(Thread.java:1027) 
           * 
           */
  
  
          private int r, g, b;
  
          private boolean running;
          private SurfaceHolder holder;
          private DialogTask task;
  
          public Render(Context context) {
              super(context);
              holder = this.getHolder();
              task = new DialogTask(context);
              r = g = b = 0;
          }
  
          public void setLoopFlag(boolean value) {
              running = value;
          }
  
          public void run() {
              boolean flag = false;
              while(running) {
                  if (holder.getSurface().isValid()) {
                      Canvas c = null;
                      try {
                          c = holder.getSurface().lockCanvas(null);
                      }
                      catch(IllegalArgumentException e) {
                          e.printStackTrace();
                      }
                      catch(OutOfResourcesException e) {
                          e.printStackTrace();
                      }
                      c.drawARGB(255, r, g, b);
                      r++;
                      g++;
                      b++;
                      if (r &gt; 250 || g &gt; 250 || b &gt; 250) {
                          r = 0;
                          g = 0;
                          b = 0;
                      }
                      if (!flag){
                          flag = true;
                          Void[] v = new Void[1];
                          v[0] = null;
                          task.execute(v);
                      }
                      holder.getSurface().unlockCanvasAndPost(c);
                  }
              }
          }
      }
  
      public class DialogTask extends AsyncTask&lt;Void, Void, Void&gt;{
  
          private Context context;
          private boolean exit;
  
          public DialogTask(Context c){
              context = c;
              exit = false;
          }
  
          @Override
          protected Void doInBackground(Void... params) {
              AlertDialog.Builder builder = new AlertDialog.Builder(context);
              builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                  @Override
                  public void onClick(DialogInterface dialog, int which) {
                      exit = true;
                  }
              });
              builder.setTitle("Enter...");
              AlertDialog dialog = builder.create();
              dialog.show();
              return null;
          }
  
      }
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          view = new Render(this);
          view.setLoopFlag(true);
          setContentView(view);
          Thread thread = new Thread(view);
          thread.setName("Render Thread");
          thread.start();
      }
  }
  </code></pre>
  
  <hr>
  
  <p>EDIT #2 (runOnUIThread() and onTouchEvent(MotionEvent e) lockups, source code given below:</p>
  
  <pre><code>public class Basic extends Activity {
      Render view;
      public class Render extends SurfaceView implements Runnable {
          private Activity activity;
          private SurfaceHolder holder;
          private boolean running;
          public Render(Activity a){
              super(a);
              activity = a;
              holder = this.getHolder();
              running = true;
          }
  
          public void run(){
              int r = 0;
              while (running){
                  if (holder.getSurface().isValid()){
                      Canvas canvas = holder.lockCanvas();
                      canvas.drawARGB(255, r, 255, 255);
                      r++;
                      if (r &gt; 255)
                          r = 0;
                      holder.unlockCanvasAndPost(canvas);
                  }
              }   
          }
  
          public void start(){
              new Thread(this).start();
          }
  
          public boolean onTouchEvent(MotionEvent event){
              activity.runOnUiThread(new Runnable(){
                  public void run(){
                      AlertDialog.Builder builder = new AlertDialog.Builder(activity);
                      builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
  
                          @Override
                          public void onClick(DialogInterface dialog, int which) {
                              Log.d("Activity", "It worked also......");  
                          }
                      });
                      AlertDialog dialog = builder.create();
                      dialog.show();
                  }
              });
              return false;
          }
  
          public void stop(){
              running = false;
              boolean r = true;
              while(r){
                  try {
                      Thread.currentThread().join();
                      r = false;
                  }
                  catch(InterruptedException e) {
                      r = true;
                  }
              }
          }
      }
  
  
      public void onCreate(Bundle b){
          super.onCreate(b);
          view = new Render(this);
          this.setContentView(view);
      }
  
      public void onPause(){
          super.onPause();
          view.stop();
      }
  
      public void onResume(){
          super.onResume();
          view.start();
      }
  }
  </code></pre>
  
  <hr>
  
  <p><strong>EDIT #3 (I think this is the final EDIT of the day)</strong></p>
  
  <p>Here is the "workaround" I've gotten so far. All credits goes to Nate for his help.</p>
  
  <pre><code>package ff.ff;
  
  import android.app.Activity;
  import android.app.AlertDialog;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.graphics.Canvas;
  import android.os.Bundle;
  import android.util.Log;
  import android.view.MotionEvent;
  import android.view.SurfaceHolder;
  import android.view.SurfaceView;
  
  
  public class Basic extends Activity {
      private AlertDialog dialog;
      private AlertDialog.Builder builder;
      private BackgroundColors view;
  
      public class BackgroundColors extends SurfaceView implements Runnable {
          private Thread thread;
          private boolean running;
          private SurfaceHolder holder;
  
          public BackgroundColors(Context context) {
              super(context);
          }
  
          public void run() {
              int r = 0;
              while (running){
                  if (holder.getSurface().isValid()){
                      Canvas canvas = holder.lockCanvas();
                      if (r &gt; 250)
                          r = 0;
                      r += 10;
                      canvas.drawARGB(255, r, 255, 255);
                      holder.unlockCanvasAndPost(canvas);
                  }
              }
          }
  
          public void start() {
              running = true;
              thread = new Thread(this);
              holder = this.getHolder();
              thread.start();
          }
  
          public void stop() {
              running = false;
              boolean retry = true;
              while (retry){
                  try {
                      thread.join();
                      retry = false;
                  }
                  catch(InterruptedException e) {
                      retry = true;
                  }
              }
          }
  
          public boolean onTouchEvent(MotionEvent e){
              dialog.show();
              return false;
          }
      }
  
      public void onCreate(Bundle b) {
          super.onCreate(b);
          view = new BackgroundColors(this);
          this.setContentView(view);
          builder = new AlertDialog.Builder(this);
          builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
              @Override
              public void onClick(DialogInterface dialog, int which) {
                  Log.d("Basic", "It worked");
              }
          });
          dialog = builder.create();
      }
  
      public void onPause(){
          super.onPause();
          view.stop();
      }
  
      public void onResume(){
          super.onResume();
          view.start();
      }
  }
  </code></pre>