欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android SurfaceView運(yùn)行機(jī)制剖析--處理切換到后臺(tái)再重新進(jìn)入程序時(shí)的異常

 更新時(shí)間:2016年08月22日 10:36:59   投稿:lqh  
本文主要介紹Android SurfaceView運(yùn)行機(jī)制,這里整理了詳細(xì)的資料來講解SurfaceView的運(yùn)行原理,并附示例代碼參考,有需要的小伙伴可以參考下

        有不少朋友都遇到過這種問題,程序執(zhí)行時(shí)切換到后臺(tái),然后再重新進(jìn)入會(huì)報(bào)異常,本文就這種問題全面講解下SurfaceView的運(yùn)行機(jī)制,了解了這些原理你就能自己解決這些問題了。

       我們通常會(huì)通過單擊HOME按鍵或返回按鍵等操作切換到后臺(tái),之后可能會(huì)再次進(jìn)入程序,這個(gè)時(shí)候就有可能報(bào)異常。這里SurfaceView可能報(bào)的異常主要有兩點(diǎn),如下:

       一、提交畫布異常。如下圖(模擬器錯(cuò)誤提示,以及Logcat Detail)

Java代碼

public void draw() {  
  try {  
    canvas = sfh.lockCanvas();  
    if (canvas != null) {  
      canvas.drawColor(Color.WHITE);  
      canvas.drawBitmap(bmp, bmp_x, bmp_y, paint);  
    }  
  } catch (Exception e) {  
    Log.v("Himi", "draw is Error!");  
  } finally {//備注1  
    if (canvas != null)//備注2  
      sfh.unlockCanvasAndPost(canvas);  
  }  
} 

      先看備注1這里,之前的文章中我給大家解釋過為什么要把 sfh.unlockCanvasAndPost(canvas); 寫在finally中,主要是為了保證能正常的提交畫布。

       今天主要說說備注2,這里一定要判定下canvas是否為空,因?yàn)楫?dāng)程序切入后臺(tái)的時(shí)候,canvas是獲取不到的!那么canvas一旦為空,提交畫布這里就會(huì)出現(xiàn)參數(shù)異常的錯(cuò)誤!

       二、線程啟動(dòng)異常。如下圖(模擬器錯(cuò)誤提示,以及Logcat Detail)

       這種異常只是在當(dāng)你程序運(yùn)行期間點(diǎn)擊Home按鈕后再次進(jìn)入程序的時(shí)候報(bào)的異常,異常說咱們的線程已經(jīng)啟動(dòng)!為什么返回按鈕就沒事?

       OK,下面我們就要來先詳細(xì)講解一下Android中Back和Home按鍵的機(jī)制!然后分析問題,并且解決問題!

       先看下面MySurfaceViewAnimation.java的類中的代碼:

Java代碼

public class MySurfaceViewAnimation extends SurfaceView implements Callback, Runnable {  
  private Thread th;  
  private SurfaceHolder sfh;  
  private Canvas canvas;  
  private Paint paint;  
  private Bitmap bmp;  
  private int bmp_x, bmp_y;  
  public MySurfaceViewAnimation(Context context) {  
    super(context);  
    this.setKeepScreenOn(true);  
    bmp = BitmapFactory.decodeResource(getResources(), R.drawable.himi_dream);  
    sfh = this.getHolder();  
    sfh.addCallback(this);  
    paint = new Paint();  
    paint.setAntiAlias(true);  
    this.setLongClickable(true);  
    th = new Thread(this, "himi_Thread_one");  
    Log.e("Himi", "MySurfaceViewAnimation");  
  }  
  public void surfaceCreated(SurfaceHolder holder) {  
    th.start();  
    Log.e("Himi", "surfaceCreated");  
  }  
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {  
    Log.e("Himi", "surfaceChanged");  
  }  
  public void surfaceDestroyed(SurfaceHolder holder) {  
    Log.e("Himi", "surfaceDestroyed");  
  }  
  public void draw() {  
    try {  
      canvas = sfh.lockCanvas();  
      if (canvas != null) {  
        canvas.drawColor(Color.WHITE);  
        canvas.drawBitmap(bmp, bmp_x, bmp_y, paint);  
      }  
    } catch (Exception e) {  
      Log.v("Himi", "draw is Error!");  
    } finally {//備注1  
      if (canvas != null)//備注2  
        sfh.unlockCanvasAndPost(canvas);  
    }  
  }  
  public void run() {  
    while (true) {  
      draw();  
      try {  
        Thread.sleep(100);  
      } catch (Exception ex) {  
      }  
    }  
  }  
} 

  以上是我們常用的自定義SurfaceView,并且使用Runnable接口老框架了不多說了,其中我在本類的構(gòu)造、創(chuàng)建、狀態(tài)改變、消亡函數(shù)都加上打印!

       OK,下面看第一張圖:(剛運(yùn)行程序)

        上圖的左邊部分是Dubug。這里顯示我們有一條線程在運(yùn)行,名字叫”himi_Thread_one”。

       上圖的右邊部分是LogCat日志。大家很清晰的看到,當(dāng)?shù)谝淮芜M(jìn)入程序的時(shí)候,會(huì)先進(jìn)入view構(gòu)造函數(shù)、然后是創(chuàng)建view,然后是view狀態(tài)改變,OK,這個(gè)大家都知道!

       下面是我來點(diǎn)擊Home(手機(jī)上的小房子)按鍵,這時(shí)程序處于后臺(tái),然后重新進(jìn)入程序的過程!

       上圖可以看出我們的線程還是一條,這里主要觀察從點(diǎn)擊home到再次進(jìn)入程序的過程,如下所述:

       點(diǎn)擊home 調(diào)用了view銷毀,然后進(jìn)入程序會(huì)先進(jìn)入view創(chuàng)建,最后是view狀態(tài)改變。

       上面的過程很容易理解,重要的角色上場了~Back 按鈕!點(diǎn)我點(diǎn)擊Back按鈕看看發(fā)生了什么!

       先看左邊的Debug一欄,多了一條線程! 看LogCat發(fā)現(xiàn)比點(diǎn)擊Home按鍵多調(diào)用了一次構(gòu)造函數(shù)!

       好了,從我們測試的程序來看,無疑,點(diǎn)擊Home 和 點(diǎn)擊 Back按鈕再次進(jìn)入程序的時(shí)候,步驟是不一樣的,線程數(shù)量也變了!

       那么這里就能解釋為什么我們點(diǎn)擊Back按鈕不異常,點(diǎn)擊Home會(huì)異常了!

       原因:因?yàn)辄c(diǎn)擊Back按鈕再次進(jìn)入程序的時(shí)候先進(jìn)入的是view構(gòu)造函數(shù)里,那么就是說這里又new了一個(gè)線程出來,并啟動(dòng)!那么而我們點(diǎn)擊Home卻不一樣了,因?yàn)辄c(diǎn)擊home之后再次進(jìn)入程序不會(huì)進(jìn)入構(gòu)造函數(shù),而是直接進(jìn)入了view創(chuàng)建這個(gè)函數(shù),而在view創(chuàng)建這個(gè)函數(shù)中我們有個(gè)啟動(dòng)線程的操作,其實(shí)第一次啟動(dòng)程序的線程還在運(yùn)行,so~這里就一定異常了,說線程已經(jīng)啟動(dòng)!

       有些童鞋會(huì)問,我們?yōu)楹尾话裻h = new Thread(this, “himi_Thread_one”);放在view創(chuàng)建函數(shù)中不就好了?!

       沒錯(cuò),可以!但是當(dāng)你反復(fù)幾次之后你發(fā)現(xiàn)你的程序中會(huì)多出很多條進(jìn)程?。ㄈ缦聢D)

       雖然可以避免出現(xiàn)線程已經(jīng)啟動(dòng)的異常,很明顯這不是我們想要的結(jié)果!

       那么下面給大家介紹最合適的解決方案:

       修改MySurfaceViewAnimation.java:

Java代碼

public class MySurfaceViewAnimation extends SurfaceView implements Callback, Runnable {  
  private Thread th;  
  private SurfaceHolder sfh;  
  private Canvas canvas;  
  private Paint paint;  
  private Bitmap bmp;  
  private int bmp_x, bmp_y;  
  private boolean himi; //備注1  
  public MySurfaceViewAnimation(Context context) {  
    super(context);  
    this.setKeepScreenOn(true);  
    bmp = BitmapFactory.decodeResource(getResources(), R.drawable.himi_dream);  
    sfh = this.getHolder();  
    sfh.addCallback(this);  
    paint = new Paint();  
    paint.setAntiAlias(true);  
    this.setLongClickable(true);  
    Log.e("Himi", "MySurfaceViewAnimation");  
  }  
  public void surfaceCreated(SurfaceHolder holder) {  
    himi = true;  
    th = new Thread(this, "himi_Thread_one");//備注2  
    th.start();  
    Log.e("Himi", "surfaceCreated");  
  }  
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {  
    Log.e("Himi", "surfaceChanged");  
  }  
  public void surfaceDestroyed(SurfaceHolder holder) {  
    himi = false;//備注3  
    Log.e("Himi", "surfaceDestroyed");  
  }  
  public void draw() {  
    try {  
      canvas = sfh.lockCanvas();  
      if (canvas != null) {  
        canvas.drawColor(Color.WHITE);  
        canvas.drawBitmap(bmp, bmp_x, bmp_y, paint);  
      }  
    } catch (Exception e) {  
      Log.v("Himi", "draw is Error!");  
    } finally {  
      if (canvas != null)  
        sfh.unlockCanvasAndPost(canvas);  
    }  
  }  
  public void run() {  
    while (himi) {//備注4  
      draw();  
      try {  
        Thread.sleep(100);  
      } catch (Exception ex) {  
      }  
    }  
  }  
} 

        這里修改的地方有以下幾點(diǎn):

       1、我們都知道一個(gè)線程啟動(dòng)后,只要run方法執(zhí)行結(jié)束,線程就銷毀了,所以我增加了一個(gè)布爾值的成員變量 himi(備注1),這里可以控制我們的線程消亡的一個(gè)開關(guān)?。▊渥?)

       2、在啟動(dòng)線程之前,設(shè)置這個(gè)布爾值為ture,讓線程一直運(yùn)行。

       3、在view銷毀時(shí),設(shè)置這個(gè)布爾值為false,銷毀當(dāng)前線程?。▊渥?)

       OK,這里圖和解釋夠詳細(xì)了,希望大家以后真正開發(fā)一款游戲的時(shí)候,一定要嚴(yán)謹(jǐn)代碼,不要留有后患哈~

       以上就對(duì)Android SurfaceView運(yùn)行機(jī)制詳細(xì)介紹,后續(xù)繼續(xù)補(bǔ)充相關(guān)知識(shí),謝謝大家對(duì)本站的支持!

相關(guān)文章

最新評(píng)論