2010-12-21 43 views
2

我想弄清楚爲什麼我的服務從我的應用程序泄漏。開始新活動後,Android服務連接泄露

我得到的官方錯誤是服務沒有再註冊。

這是什麼工作: 我創建一個服務,創建一個監聽器,當監聽器被觸發時,服務意圖啓動另一個活動。新的活動開始並做它的事情。

問題: 當我回到主屏幕給我關閉服務的選項時,我得到了前面說過的導致IllegalArgumentException的錯誤(當我嘗試解除不是服務的綁定註冊)。

任何幫助將不勝感激。這是我的服務的代碼。這是我所包含的一切,因爲這似乎是問題所在,但如果您需要更多的信息,請告訴我。

在此先感謝,這裏是代碼。

import java.lang.ref.WeakReference; 
import java.util.List; 

import android.app.Service; 
import android.content.Context; 
import android.content.Intent; 
import android.hardware.Sensor; 
import android.hardware.SensorEvent; 
import android.hardware.SensorEventListener; 
import android.hardware.SensorManager; 
import android.os.Binder; 
import android.os.IBinder; 
import android.util.Log; 
import android.widget.Toast; 


public class AccelService extends Service 
{ 
public static boolean listening = false; 
public boolean callMade = false; 
private static Sensor sensor; 
private static SensorManager ASensorManager; 


private SensorEventListener EventListener = 
    new SensorEventListener() { 

    private float x = 0; 
    private float y = 0; 
    private float z = 0; 
    private double max = 0; 
    private double force = 0; 

    public void onAccuracyChanged(Sensor sensor, int accuracy) {} 

    public void onSensorChanged(SensorEvent event) 
    { 

     x = event.values[0]; 
     y = event.values[1]; 
     z = event.values[2]; 
     force = Math.sqrt(x*x+y*y+z*z); 
     Log.i("LocalService", "Event happened: " + force); 


     if (force > Main.dropValue) 
     { 
      onDrop(force); 
     } 
    } 
}; 

public void startListener() 
{ 
    ASensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE); 
    List<Sensor> sensors = ASensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER); 
    if (sensors.size() > 0) 
    { 
     sensor = sensors.get(0); 
     listening = ASensorManager.registerListener(accelEventListener, sensor, SensorManager.SENSOR_DELAY_GAME); 

    } 
} 


public class AccelBinder<S> extends Binder 
{ 
    private WeakReference<S> mService; 

    public AccelBinder (S service) 
    { 
     mService = new WeakReference<S>(service); 
    } 

    public S getService() 
    { 
     return mService.get(); 
    } 
} 

public IBinder mBinder; 

@Override 
public void onCreate() 
{ 
    startListener(); 

    mBinder = new AccelBinder<AccelService>(this); 
} 

public boolean isListening() 
{ 
    return listening; 
} 

/*@Override 
public void onStart(Intent intent, int startId) 
{ 
    Log.i("LocalService", "Received start id " + startId + ": " + intent); 
}*/ 

@Override 
public int onStartCommand(Intent intent, int flags, int startId) 
{ 
    Log.i("LocalService", "Received start id " + startId + ": " + intent); 
    return AccelService.START_STICKY; 
} 

@Override 
public void onDestroy() 
{ 
    if (listening) 
     stopListening(); 
    mBinder = null; 

    super.onDestroy(); 
} 

public void onDrop(double force) 
{ 
    if (!callMade) 
    { 
     Toast.makeText(this, "Phone dropped: " + force, 5000).show(); 
     Intent i = new Intent(this,Next.class); 
     i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
     callMade = true; 
     //stopListening(); 
     //onDestroy(); 
     //SafetyNet.ctxt.unbindService(SafetyNet.AccelWatch); 
     this.startActivity(i); 
    } 
} 

public void stopListening() 
{  

    listening = false; 
    try { 
     if (ASensorManager != null && accelEventListener != null) 
     { 
      ASensorManager.unregisterListener(accelEventListener); 
     } 
    } catch (Exception e) {}   
} 

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

} 

回答

7

我對傳感器知之甚少,但您的服務看起來不錯。

如果AccelBinder是您的服務的內部類,使其成爲一個靜態的內部類,或者像我通常那樣,完全是一個單獨的類。靜態內部類沒有對外部類的引用。記住你會泄漏你的活頁夾。如果你的Binder是一個非靜態的內部類,它就有一個對你的服務的引用,所以也會泄漏。

我在猜測 - 就像真的瘋狂猜測 - 在沒有任何代碼的情況下,您的Activity生命週期的管理出現問題以及如何處理Binder對象。

事情要記住....

不要讓一個靜態引用您的Binder對象 - 他們都是一次性的 - 每次綁定時獲得一個新的。

保持您的綁定對稱於您的活動生命週期。如果您在onCreate()中綁定,則在onDestroy()中解除綁定(如果isFinishing()爲onPause)等。如果您不明白使用Sensor的手機的物理旋轉破壞了您的Activity,則從頭開始重新創建。

你似乎總是太喜歡「靜態」類變量。在Android中,靜態的東西往往會導致內存泄漏 - 如果你泄漏的東西有一個上下文 - 事情會變得很糟糕。如果您想在同一個類的實例之間保持狀態,請考慮使用首選項。

例如,

private static Sensor sensor; 
private static SensorManager ASensorManager; 

投擲這些遠使用之間。

確保您特別沒有在您的活動中保留對您服務的靜態引用。按照Android的本質,服務是單身人士,如果它仍在運行,每次綁定時都會得到相同的服務。請指望您的服務在某個時間點被操作系統殺死。寫下你的服務,以便它在重新啓動時可以工作。

這足以猜測一天。