NOTE: attach of thread 'Binder_3' failed 的調試和解決

        近來一直還是在做Camera的應用調試,在調試過程中出現了這樣一個問題:

        因爲目前在做的Camera應用需要做到後臺開啓並保持錄像的功能,因此所有的Camera操作都選擇了在另外一個獨立的Service中完成,包括Camera對象的初始化,拍照參數的設置,預覽參數的設置,錄像的參數設置等等都在Service中完成。之所以選擇Service顯而易見也是爲了能保持後臺錄像的功能。那麼說到Service的話就必須說到Service的開啓和關閉了,一般的用法都會推薦 

                         context.startService(Intent)和stopService; 或者

                        context.bindService()和context.unbindService()

                       但是這兩種方式分別會有各自的優點,恰好我所需要達到的目的是兩者結合才能實現的,於是我的選擇是兩者結合來用。

                       我的調用順序爲先StartService,然後bindService。然後在退出Activity的同時去判斷是否正在錄像,如果正在錄像則轉爲後臺錄像模式。否則直接finish Activity釋放Service,按這個思路做完功能還算正常,但是出現一個問題。

                      首先講下程序框架,首先是主Activity會有預覽界面以及三個button分別爲拍照,錄像和文件預覽。其中文件預覽爲單獨的一個Activity來查看錄像文件和拍照的圖片文件。問題就出在錄像過程中跳轉到文化間預覽的Activity然後再回退到主Activity,此時錄像正常。接着我停止錄像試圖退出應用,然後問題出現了,我是直接操作的BACK鍵去退出應用,並且Back鍵的處理爲釋放服務finish程序。代碼如下

                    

	                Intent exitIntent = new Intent(getApplicationContext(),CameraService.class);
			stopService(exitIntent);
                        unBindPlayerService();CameraActivity.this.finish();


                      開始看似沒有什麼問題,但是Activity在響應的時候卻出現了回退到了停止錄像前也就是剛從文件預覽界面回來時的畫面,並且畫面不再刷新。緊接着我試圖繼續back來退出應用,同樣失敗了。最終看了很多遍log後,感覺從文件預覽界面回退時的操作應該有問題,於是看代碼,回退到主Activity的代碼如下

                                                           

 	public void toPreviewUI(){
		Intent intent = new Intent(this, CameraActivity.class);
		intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		startActivity(intent);
		this.finish();
	       }
                       最後問題鎖定在回退時的Flags設置,不應該採用FLAG_ACTIVITY_NEW_TASK,而是採用FLAG_ACTIVITY_CLEAR_TOP

                       簡單的說明下兩者的區別,

                      FLAG_ACTIVITY_NEW_TASK
                      設置此狀態,記住以下原則,首先會查找是否存在和被啓動的Activity具有相同的親和性的任務棧(即taskAffinity,注意同一個應用程序中的activity的親和性一樣,所  以下面的a情況會在同一個棧中,前面這句話有點拗口,請多讀幾遍),如果有,剛直接把這個棧整體移動到前臺,並保持棧中的狀態不變,即棧中的activity順序不變,如果沒有,則新建一個棧來存放被啓動的activity。

                      FLAG_ACTIVITY_CLEAR_TOP
                      我們知道Android的窗口類提供了歷史棧,我們可以通過stack的原理來巧妙的實現,這裏我們在D窗口打開A窗口時在Intent中直接加入標誌Intent.FLAG_ACTIVITY_CLEAR_TOP,再次開啓A時將會清除該進程空間的所有Activity。 

                     這樣解釋可能就可以說明問題了,我們開始的back是執行了回退到歷史棧中的一個Activity狀態了,所以界面不會再刷新,只有繼續back纔可能找到棧底的Activity並退出,但是問題又出現了。就是程序無法退出,找了好久log終於發現了這個地方

                    I/AndroidRuntime( 3808): NOTE: attach of thread 'Binder_3' failed

                     可以看到是以爲內Service的bind操作出現了問題,導致Service無法正常釋放,Acitivity無法finish。於是繼續研究Service的啓動和關閉相關的東西,期間查了不少資料也看過不少達人的blog最終找到了辦法解決。

                    上述兩種啓動Servidce的方法如果混合用的話最好是保證兩種方法操作的service對象統一,且均要進行停止service的操作纔可以完整的釋放service。同時bind的方法在所bind的Activity在finish的時候會自動的unbind釋放service。
              此處在代碼中有個差別是在啓動的時候
          getApplicationContext().startService(service);
bindPlayerService();
             是首先startserice然後bind的,但是後面的finish操作卻是如此
                stopService(exitIntent);
                unBindPlayerService();
              可以看到此處的調用直接是stopservice了,並未獲取context對象,經過驗證恰好是這個地方造成了後面service釋放的異常。可能此處不會導致前面說的finish後回到之前正在錄像的界面不刷新,但是造成了後面back鍵無響應程序無法退出的問題。 因此改爲
getApplicationContext().stopService(exitIntent);
unBindPlayerService();
              跟開啓服務的操作保持一致,此時服務釋放異常解決。重點卻是一個操作對象的不統一造成的,至於更深層次的原因現在暫時無法得知,只能等以後有能力再來做研究了。到此問題解決。耗了3天的問題終於搞定,着實不易。

               

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章