multithreading - Android Game Thread Crashing on Draw() -


i have implemented basic game loop in android "conway's game of life" implementation. works pretty occasionally, crashes. me looks draw() called when view no longer valid (sometimes when home pressed or when options pressed).

so did research , discovered not implementing onpause()/onresume() correctly. have tried correct still crashing intermittently. not time, enough.

i have been working on longer care admit @ point , hoping knows more i, @ , tell me if i'm doing wrong, maybe life-cycle problem or something.

here code (note have removed non-related methods brevity):

// here main android activity public class mainactivity extends activity implements onsharedpreferencechangelistener {     game gameview;      string mspeed, malivecolor, mdeadcolor, mboardsize;      @override     public void oncreate(bundle savedinstancestate)      {         super.oncreate(savedinstancestate);          string deviceid = secure.getstring(getcontentresolver(), secure.android_id);           sharedpreferences prefs = preferencemanager.getdefaultsharedpreferences(this);          mspeed = prefs.getstring("sim_speed", "fast");         int ispeed = 0;          if(mspeed.equals("warp speed"))             ispeed = 50;         if(mspeed.equals("fast"))             ispeed = 250;         if(mspeed.equals("medium"))             ispeed = 500;         if(mspeed.equals("slow"))             ispeed = 1000;         if(mspeed.equals("really slow"))             ispeed = 2500;          // create game object         gameview = new game(this, ispeed);          // register preference change listener         prefs.registeronsharedpreferencechangelistener(this);          // , set remembered preferences         string bs = prefs.getstring("sim_board_size", "large");         gameview.setboardsize(bs);          malivecolor = prefs.getstring("alive_color", "yellow");                    gameview.setcolor(malivecolor, "alive");          mdeadcolor = prefs.getstring("dead_color", "blue");             gameview.setcolor(mdeadcolor, "dead");          setcontentview(gameview);     }      @override protected void onpause()  {     //gameview.issimrunning = false;     gameview.thread.onpause();      super.onpause(); }  @override protected void onresume()  {     //gameview.issimrunning = true;     gameview.thread.onresume();     //gameview.initview();      super.onresume(); }         // handle updates preferences     public void onsharedpreferencechanged(sharedpreferences prefs, string key)     {         if(key.equals("sim_speed"))         {             mspeed = prefs.getstring("sim_speed", "fast");              if(mspeed.equals("warp speed"))                 gameview.setspeed(50);             if(mspeed.equals("fast"))                 gameview.setspeed(250);             if(mspeed.equals("medium"))                 gameview.setspeed(500);             if(mspeed.equals("slow"))                 gameview.setspeed(1000);             if(mspeed.equals("really slow"))                 gameview.setspeed(5000);         }          if(key.equals("sim_board_size"))         {             mboardsize = prefs.getstring("sim_board_size", "large");              gameview.setboardsize(mboardsize);         }          if(key.equals("alive_color"))         {             malivecolor = prefs.getstring("alive_color", "yellow");              gameview.setcolor(malivecolor, "alive");         }          if(key.equals("dead_color"))         {             mdeadcolor = prefs.getstring("dead_color", "blue");              gameview.setcolor(mdeadcolor, "dead");         }     }      @override     public boolean oncreateoptionsmenu(menu menu)     {         // create menu inflater         menuinflater inflater = getmenuinflater();          // generate menu xml menu resource file         inflater.inflate(r.menu.main_menu, menu);          return true;     } }  // here surfaceview class public class game extends surfaceview implements surfaceholder.callback {     long lastupdate = 0;     long sleeptime=0;      public int                 num_cols = 51;     public int                 max_cols = 51;     public int                 num_rows = 81;     public int                 max_rows = 81;      public long                gmdelay = 0;     private int                grid_cell_size = 9;      public boolean [][]        current_life   = new boolean [max_cols][max_rows];     private boolean [][]       successor_gen  = new boolean [max_cols][max_rows];      public boolean             issimrunning = false;     public boolean             isthreadstarted = false;      paint dead_paint = new paint();     paint alive_paint = new paint();     paint background = new paint();      private gamethread thread;     surfaceholder surfaceholder;     context context;      public game(context context, int dly)      {         super(context);          dead_paint.setstrokewidth(0);         dead_paint.setcolor(color.blue);          alive_paint.setstrokewidth(0);         alive_paint.setcolor(color.yellow);          background.setstrokewidth(0);         background.setcolor(color.black);                  gmdelay = dly;          initview();         initlifearray();     }      public void setspeed(long s)     {         gmdelay = s;          initview();          thread.delay = s;     }      public void setboardsize(string s)     {         thread.state = 2;         issimrunning = false;          if(s.equals("small"))             num_cols = 10;         else if(s.equals("medium"))             num_cols = 25;         else if(s.equals("large"))             num_cols = 51;          thread.state = 1;         issimrunning = true;          initview();     }      public void setcolor(string color, string type)     {         int c = 0;          // violet, white , orange          if(color.equals("black"))             c = color.black;         else if(color.equals("blue"))             c = color.blue;         else if(color.equals("green"))             c = color.green;         else if(color.equals("purple"))             c = color.rgb(109, 6, 108);         else if(color.equals("orange"))             c = color.rgb(255, 157, 30);         else if(color.equals("red"))             c = color.red;         else if(color.equals("yellow"))             c = color.yellow;         else if(color.equals("white"))             c = color.white;         else             c = color.yellow;          if(type.equals("alive"))             alive_paint.setcolor(c);         else             dead_paint.setcolor(c);     }      @override     public boolean ontouchevent(motionevent event)     {         if(event != null)         {             int x = (int) event.getx()/grid_cell_size;             int y = (int) event.gety()/grid_cell_size;              int max_x = current_life.length;              if(x < max_x)             {                 int max_y = current_life[x].length;                  if(y < max_y)                     current_life[x][y] = true;             }              return true;               }          return super.ontouchevent(event);     }      void initview()     {         // initialize our screen holder         surfaceholder holder = getholder();         holder.addcallback(this);          // initialize our thread class. call made start later         thread = new gamethread(holder, context, new handler(), this);         setfocusable(true);     }      public void draw(canvas canvas)      {               int x = canvas.getwidth();             int y = canvas.getheight();              canvas.drawrect(0, 0, x, y, background);              grid_cell_size = (int) math.ceil((double) (x / num_cols) * 1.0);             int gap = grid_cell_size - 1;              for(int col = 0; col < num_cols; col++)               {                 for(int row = 0; row < num_rows; row++)                  {                     if(current_life[col][row])                         canvas.drawrect(col*grid_cell_size, row*grid_cell_size, col*grid_cell_size+gap, row*grid_cell_size+gap,   alive_paint);                     else                         canvas.drawrect(col*grid_cell_size, row*grid_cell_size, col*grid_cell_size+gap, row*grid_cell_size+gap,   dead_paint);                 }             }      }      // these methods overridden surfaceview super class. automatically called      // when surfaceview created, resumed or suspended.     @override      public void surfacechanged(surfaceholder arg0, int format, int width, int height)     {      }      @override      public void surfacedestroyed(surfaceholder arg0)     {     }      @override      public void surfacecreated(surfaceholder arg0)      {     if (!isthreadstarted) {         thread.start();         isthreadstarted = true;     }       thread.onresume();      }   }  // finally, have thread class public class gamethread extends thread  {     // flag hold game state     // private static final string tag = gamethread.class.getsimplename();     private game game;     private surfaceholder msurfaceholder;      //for consistent rendering     private long sleeptime;     public long delay=250;      //state of game (running or paused).     int state = 1;     public final static int running = 1;     public final static int paused = 2;     private object mpauselock = new object();       private boolean mpaused = false;      public gamethread(surfaceholder surfaceholder, context context, handler handler, game g)     {         super();          //data screen         msurfaceholder = surfaceholder;          delay = g.gmdelay;          this.game = g;     }  public void onpause()  {     state = 2;      synchronized (mpauselock) {         mpaused = true;     } }  public void onresume() {     state = 1;      synchronized (mpauselock) {         mpaused = false;         mpauselock.notifyall();     } }      @override     public void run()      {         while (state == running  && ! mpaused)          {             delay = this.game.gmdelay;              //time before update             long beforetime = system.nanotime();              // update simulation 1 generation             game.createnextgeneration();              canvas c = null;              try              {                 //lock canvas nothing else can use                 c = msurfaceholder.lockcanvas(null);                  synchronized(msurfaceholder)                  {                     //if(game.issimrunning)                         game.draw(c);                 }             }                           {                 // in if exception thrown                 // during above, don't leave surface in inconsistent state                 if (c != null)                  {                     msurfaceholder.unlockcanvasandpost(c);                 }             }              synchronized (mpauselock) {                 while (mpaused) {                     try {                         mpauselock.wait();                     } catch (interruptedexception e) {                     }                 }             }              // sleep time. time required sleep keep game consistent             // starts specified delay time (in milliseconds) subtracts actual             // time took update , render game. allows simulation render smoothly.             this.sleeptime = delay-((system.nanotime()-beforetime)/1000000l);              try              {                 //actual sleep code                 if(sleeptime>0)                 {                     thread.sleep(sleeptime);                 }             }             catch (interruptedexception ex)              {                 logger.getlogger(gamethread.class.getname()).log(level.severe, null, ex);             }         }     } } 

i have solved issue checking see if canvas null in draw() before performing operations.

thanks suggestions , comments!!


Comments

Popular posts from this blog

c++ - Creating new partition disk winapi -

Android Prevent Bluetooth Pairing Dialog -

VBA function to include CDATA -