Android中Activity頻繁進入再退出時程式崩潰的解決方案

風的王子發表於2013-09-02
最近在對一款開發中的遊戲進行壓力測試時會出現崩潰的問題,具體場景是 在進入一個Activity時立即按返回鍵退出該Activity再迅速進入該Activity,進入退出的時間間隔越短越容易發生崩潰,後來列印日誌發現,由於Activity進入需要載入資源,退出需要釋放資源,這兩個操作都需要一定的時間,照以上場景進行壓力測試就會出現 Activity在資源還沒載入完之前然後程式就會去釋放資源,這樣就會出現空指標而崩潰;另一種情況是程式載入資源比較多,這樣耗費的時間會比較久,同樣釋放資源也會比較久,在立即退出Activity再迅速進入該Activity的時候就會出現Activity的資源還沒來得及釋放,然後就再次載入了一遍資源,這樣就會出現記憶體溢位異常。

解決問題一定要從根源出發,這樣才能確保問題被徹底解決。上述問題的根源就是 由於使用者操作太快導致資源在未被載入完之前又開始釋放,以及資源會被重複載入兩次。從問題根源出發,我們只要保證資源在載入完成之前確保資源不會被釋放,以及資源不會被重複載入,這樣問題就可以迎刃而解了。

解決方案有兩種:一是加Loading頁面,強制使用者等待,這種方式在很多比較大型的遊戲裡很常見。二,是設定標誌位在Activity資源載入完成之前禁止使用者退出Activity, 這個適用於一些資源不太多,沒有Loading頁面的的情況,本質上也是強制使用者等待(一些小的遊戲常常沒有loading頁面 ,資源載入也載入也比較快,所以常常忽略了壓力測試)

第一種方案,相信做遊戲的朋友們都很熟悉,這裡就不細講了。

第二中方案,這裡給出個一個框架,如下:

public class Test1 extends Activity

{

public static final int MSG_INIT_COMPLETE = 1;

public static final int MSG_DELAYED = 200;

private boolean isResume;

 

@Override

protected void onCreate(Bundle savedInstanceState)

{

 

// TODO Auto-generated method stub

super.onCreate(savedInstanceState);

initRes();

isResume = false;

mHandler.sendEmptyMessageDelayed(MSG_INIT_COMPLETE, MSG_DELAYED);

 

}

 

public Handler mHandler = new Handler()

{

 

@Override

public void handleMessage(Message msg)

{

 

// TODO Auto-generated method stub

super.handleMessage(msg);

switch (msg.what)

{

 

case MSG_INIT_COMPLETE:

isResume = true;

break;

 

}

}

};

protected void onDestroy()

{

 

// TODO Auto-generated method stub

super.onDestroy();

recycleRes();

}

 

@Override

public boolean onKeyDown(int keyCode, KeyEvent event)

{

 

// TODO Auto-generated method stub

if (keyCode == KeyEvent.KEYCODE_BACK)

{

if (isResume)

{

startActivity(new Intent(this,Test2.class));

finish();

}

else

return false;

}

return super.onKeyDown(keyCode, event);

}

}

以上程式碼框架是防止Test1的資源被載入完成之前開始釋放資源,即在資源載入完成之前遮蔽返回鍵事件。為了保險起見,在不影響使用者體驗的前提下大家可以把MSG_DELAYED的值再設定的大些。

public class Test extends Activity implements OnClickListener

{

 

public static final int MSG_INIT_COMPLETE = 1;

public static final int MSG_DELAYED = 200;

private boolean isResume;

 

@Override

protected void onCreate(Bundle savedInstanceState)

{

 

// TODO Auto-generated method stub

super.onCreate(savedInstanceState);

isResume = false;

mHandler.sendEmptyMessageDelayed(MSG_INIT_COMPLETE, MSG_DELAYED);

 

}

 

public Handler mHandler = new Handler()

{

 

@Override

public void handleMessage(Message msg)

{

 

// TODO Auto-generated method stub

super.handleMessage(msg);

switch (msg.what)

{

 

case MSG_INIT_COMPLETE:

isResume = true;

break;

 

}

}

};

 

@Override

public void onClick(View v)

{

 

// TODO Auto-generated method stub

case TAG_GOTO_TEST1:

if(isResume)

{

startActivity(this,test1.class);

finish();

}

break;

 

}

}

這段程式碼是防止Test1的資源在釋放完之前再次進入Test1造成記憶體溢位,同樣,在不影響使用者體驗的前提下進入Test1的延遲時間可以再長久一些。

-------------------------------------------------------------------------------------

本文出自http://labs.easymobi.cn/?p=4386

相關文章