Android SurfaceView運行機制剖析--處理切換到後台再重新進入程式時的異常_Android

來源:互聯網
上載者:User

        有不少朋友都遇到過這種問題,程式執行時切換到後台,然後再重新進入會報異常,本文就這種問題全面講解下SurfaceView的運行機制,瞭解了這些原理你就能自己解決這些問題了。

       我們通常會通過單擊HOME按鍵或返回按鍵等操作切換到後台,之後可能會再次進入程式,這個時候就有可能報異常。這裡SurfaceView可能報的異常主要有兩點,如下:

       一、提交畫布異常。如下圖(模擬器錯誤提示,以及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是否為空白,因為當程式切入背景時候,canvas是擷取不到的!那麼canvas一旦為空白,提交畫布這裡就會出現參數異常的錯誤!

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

       這種異常只是在當你程式運行期間點擊Home按鈕後再次進入程式的時候報的異常,異常說咱們的線程已經啟動!為什麼返回按鈕就沒事?

       OK,下面我們就要來先詳細講解一下Android中Back和Home按鍵的機制!然後分析問題,並且解決問題!

       先看下面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介面老架構了不多說了,其中我在本類的構造、建立、狀態改變、消亡函數都加上列印!

       OK,下面看第一張圖:(剛運行程式)

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

       上圖的右邊部分是LogCat日誌。大家很清晰的看到,當第一次進入程式的時候,會先進入view建構函式、然後是建立view,然後是view狀態改變,OK,這個大家都知道!

       下面是我來點擊Home(手機上的小房子)按鍵,這時程式處於後台,然後重新進入程式的過程!

       上圖可以看出我們的線程還是一條,這裡主要觀察從點擊home到再次進入程式的過程,如下所述:

       點擊home 調用了view銷毀,然後進入程式會先進入view建立,最後是view狀態改變。

       上面的過程很容易理解,重要的角色上場了~Back 按鈕!點我點擊Back按鈕看看發生了什麼!

       先看左邊的Debug一欄,多了一條線程! 看LogCat發現比點擊Home按鍵多調用了一次建構函式!

       好了,從我們測試的程式來看,無疑,點擊Home 和 點擊 Back按鈕再次進入程式的時候,步驟是不一樣的,線程數量也變了!

       那麼這裡就能解釋為什麼我們點擊Back按鈕不異常,點擊Home會異常了!

       原因:因為點擊Back按鈕再次進入程式的時候先進入的是view建構函式裡,那麼就是說這裡又new了一個線程出來,並啟動!那麼而我們點擊Home卻不一樣了,因為點擊home之後再次進入程式不會進入建構函式,而是直接進入了view建立這個函數,而在view建立這個函數中我們有個啟動線程的操作,其實第一次啟動程式的線程還在運行,so~這裡就一定異常了,說線程已經啟動!

       有些童鞋會問,我們為何不把th = new Thread(this, “himi_Thread_one”);放在view建立函數中不就好了?!

       沒錯,可以!但是當你反覆幾次之後你發現你的程式中會多出很多條進程!(如下圖)

       雖然可以避免出現線程已經啟動的異常,很明顯這不是我們想要的結果!

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

       修改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) {        }      }    }  } 

        這裡修改的地方有以下幾點:

       1、我們都知道一個線程啟動後,只要run方法執行結束,線程就銷毀了,所以我增加了一個布爾值的成員變數 himi(備忘1),這裡可以控制我們的線程消亡的一個開關!(備忘4)

       2、在啟動線程之前,設定這個布爾值為ture,讓線程一直運行。

       3、在view銷毀時,設定這個布爾值為false,銷毀當前線程!(備忘3)

       OK,這裡圖和解釋夠詳細了,希望大家以後真正開發一款遊戲的時候,一定要嚴謹代碼,不要留有後患哈~

       以上就對Android SurfaceView運行機制詳細介紹,後續繼續補充相關知識,謝謝大家對本站的支援!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.