2012-06-04 46 views
1

我對Android開發和StackOverflow都很新,我希望我不會問一個以前曾經問過的愚蠢問題,但我找不到任何東西。當使用向上按鈕onRestoreInstanceState不叫

我正在製作一個應用程序,該應用程序在連接到藍牙設備時啓動(初始未綁定)服務,並且應該只在我告訴它斷開連接或斷開連接時停止。 服務啓動後,主要活動會綁定到它,並在調用onDestroy()時解除綁定。當onStart被調用並且mIsBound爲true時,它也重新綁定。 mIsBound布爾值與onRestoreInstanceState()一起存儲。

*誤連接可能是mIsBound,但你的想法

當我重新打開應用程序通常,從多任務菜單或通過服務圖標mIsBound仍設置爲正確的值一個更好的名字。屏幕方向不是問題,當通過後退按鈕打開輔助活動並返回到主要活動時,所有操作仍然順利。 但是,當我在輔助活動中使用向上按鈕時,mIsBound值會丟失,並且不會調用onRestoreInstanceState()。

我需要這個來確定服務是否已經運行,因爲如果它不是,我調用bindService()它將啓動而不需要它,當它停止但仍然綁定時,我會得到錯誤。

服務:

public class BluetoothService extends Service { 

@Override 
public IBinder onBind(Intent intent) { 
    return mBinder; 

} 

public class LocalBinder extends Binder { 
    BluetoothService getService() { 
     return BluetoothService.this; 
    } 
} 


private void connectionLost() { 
Log.e(TAG, "connection lost"); 
disconnect(); 
} 


public synchronized void disconnect() { 
    Log.d(TAG, "disconnect"); 
    stopSelf(); 
} 


private void showNotification(String s) { 

    // Set the icon, scrolling text and timestamp 
    Notification notification = new Notification(R.drawable.ic_launcher, s, 
      System.currentTimeMillis()); 

    // The PendingIntent to launch our activity if the user selects this notification 
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, 
      new Intent(this, LedAndIrControlActivity.class), 0); 

    // Set the info for the views that show in the notification panel. 
    notification.setLatestEventInfo(this, s, s, contentIntent); 

    // Send the notification. 
    startForeground(NOTIFICATION, notification); 
} 

mainActivity:

public class MainActivity extends Activity { 

private static boolean mIsBound = false; 
private BluetoothService Com; 

@Override 
public void onStart() { 
    super.onStart(); 
    if(mIsBound){ 
     doBindService(); 
} 

@Override 
public void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
    Log.i(TAG, "onSaveInstanceState"); 
    outState.putBoolean("mIsBound", mIsBound); 
} 

public void onRestoreInstanceState(Bundle savedInstanceState) { 
    super.onRestoreInstanceState(savedInstanceState);   
    Log.i(TAG, "onRestoreInstanceState"); 
    mIsBound = savedInstanceState.getBoolean("mIsBound"); 
    if(mIsBound){ 
     doBindService(); 
    } 
} 

protected void onDestroy() { 
    super.onDestroy(); 
    Log.i(TAG, "onDestroy"); 
    doUnbindService(); 
} 

public boolean onOptionsItemSelected(MenuItem item) { 
    Intent serverIntent = null; 
    switch (item.getItemId()) { 
    case android.R.id.home: 
     return true; 
    case R.id.item1: 
     // Launch the DeviceListActivity to see devices and do scan 
     serverIntent = new Intent(this, DeviceListActivity.class); 
     startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE); 
     startService(new Intent(this, BluetoothService.class)); 
     doBindService(); 
     return true; 
    case R.id.item2: 
     // Disconnect device 
     Com.disconnect(); 
     doUnbindService(); 
     return true; 
    case R.id.item3: 
      serverIntent = new Intent(this, SecondaryActivity.class); 
      //serverIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
      startActivity(serverIntent); 
     return true;  
    default: 
     return super.onOptionsItemSelected(item); 
    }  
} 

void doBindService() { 
    Log.d(TAG, "doBindService"); 
    // Establish a connection with the service. We use an explicit 
    // class name because we want a specific service implementation that 
    // we know will be running in our own process (and thus won't be 
    // supporting component replacement by other applications). 
    bindService(new Intent(getBaseContext(), //Binding.this 
      BluetoothService.class), mConnection, Context.BIND_AUTO_CREATE); 
    mIsBound = true; 
} 

void doUnbindService() { 
    if (mIsBound) { 
     Log.d(TAG, "doUnbindService"); 
     // Detach our existing connection. 
     unbindService(mConnection); 
     mIsBound = false; 
    } 
    Com = null; 
} 


private ServiceConnection mConnection = new ServiceConnection() { 

    public void onServiceConnected(ComponentName className, IBinder service) { 
     // This is called when the connection with the service has been 
     // established, giving us the service object we can use to 
     // interact with the service. Because we have bound to a explicit 
     // service that we know is running in our own process, we can 
     // cast its IBinder to a concrete class and directly access it. 
     Com = ((BluetoothService.LocalBinder)service).getService(); 
     invalidateOptionsMenu(); 
     Log.i(TAG, "Service connected"); 

     // Tell the user about this for our demo. 
     Toast.makeText(getBaseContext(), "local_service_connected",//Binding.this 
       Toast.LENGTH_SHORT).show(); 
    } 

    public void onServiceDisconnected(ComponentName className) { 
     // This is called when the connection with the service has been 
     // unexpectedly disconnected -- that is, its process crashed. 
     // Because it is running in our same process, we should never 
     // see this happen. 
     Com = null; 
     Toast.makeText(getBaseContext(), "local service_disconected",//Binding.this 
       Toast.LENGTH_SHORT).show(); 
    } 
}; 

secondaryActivity:

public class SecondaryActivity extends Activity {  


@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    Intent serverIntent = null; 
    switch (item.getItemId()) { 
    case android.R.id.home: 
     // app icon in action bar clicked; go home 
     serverIntent = new Intent(this, MainActivity.class); 
     serverIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
     startActivity(serverIntent); 
     return true; 
    default: 
     return super.onOptionsItemSelected(item); 
    } 
} 

我的問題是我怎麼能確保該mIsBound值總是恢復? 我發現使用SharedPreferences是一個選項,但似乎並不像這樣做的正確方法。

有關如何綁定到服務的任何其他建議(如果它已正常運行),也是值得讚賞的!

謝謝!

UPDATE:

我想到的其他方式來解決問題,那就是簡單地檢查是否真正的服務已在運行,然後(重新)綁定。 這樣做的方式在這裏解釋: How to check if a service is running on Android?

我仍然沒有放棄相信這是這樣做的正確或最好的方式,但它會爲現在要做的。 如果您對此有評論,我們將不勝感激。

+0

當您在第二個活動中的按鈕操作之後返回主活動時,主活動是否會調用onCreate?我看到你正在使用意向標誌,並且從我的經驗來看,我已經看到了使用它們的意外結果。如果正在調用onCreate,則不會調用restoreInstance,因爲實際上您正在獲取新實例! – Mike

+0

是的,當我按下輔助活動中的向上按鈕時,具有和不具有意圖標誌設置的onCreate被調用。 你知道如何使用這個按鈕並返回到現有的intent實例嗎? – ZeroDay

+0

經過一些測試,我相信這是onCreate在onRestore之前被調用的預期行爲,所以我的第一條評論可能是無關緊要的....作爲另一種途徑,在您的主要活動中,當onRestoreInstanceState未被調用但您期望它時,是onCreate非null的savedInstanceState包?如果出現這種情況,您可以使用您在onRestore – Mike

回答

1

我與你的帖子的主題相同的問題(當使用向上按鈕onRestoreInstanceState不叫),但出於不同的原因比你的身體描述。由於我沒有發現任何其他帖子回覆,我會在這裏發佈我的解決方案,以解決這個特定的問題。

問:當使用向上按鈕onRestoreInstanceState不叫

答:按HOME(導航UP)按鈕的操作欄上確實不行爲也可以通過按後退按鈕。前者不會調用父級活動的onRestoreInstanceState(),並且按後退按鈕可以。

如果您想要完成與後退按鈕相同的行爲,可以通過覆蓋子活動中的onNavigateUp()方法並從中調用onBackPressed()來完成。

在子活動:

@Override 
public boolean onNavigateUp() { 
    onBackPressed(); 
    return true; 
} 

我不知道的返回值,true似乎是工作的罰款,並滿足文檔:「真,如果向上導航成功完成,該活動結束,否則爲假「