2010-12-21 4 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

私はセンサについてよく分かりませんが、あなたのサービスはかなり見やすいです。

IF AccelBinderは、サービスの内部クラスであり、静的な内部クラスにするか、私が一般的にそうするように、別のクラスを完全に作成します。静的内部クラスは外部クラスへの参照を持ちません。バインダーが漏れることを忘れないでください。バインダーが非静的な内部クラスである場合、バインダーはサービスへの参照を持ち、リークも発生します。

あなたのアクティビティライフサイクルの管理に何か問題があり、Binderオブジェクトをどのように扱うかというコードがないと、私は推測しています。彼らは使い捨てである - - 新しいものにあなたが結合するたびに取得

あなたのバインダーオブジェクトへの静的な参照を保持しないでください....心に留めておくべき

物事。

アクティビティのライフサイクルに関してバインドを対称に保ちます。 onCreate()でバインドする場合は、onDestroy()(またはisFinishing()の場合はonPause)などでバインドを解除します。Sensorを使用して電話機を物理的に回転させると、アクティビティがゼロから再作成されることがわからない場合は特に重要です。

「静的な」クラス変数があまりにも好きなようです。 Androidでは、静的なものはメモリリークにつながる傾向があります。リークしたものがコンテキストを持っていると、状況が悪くなります。同じクラスのインスタンス間で状態を保持したい場合は、代わりに「環境設定」を使用することを検討してください。例えば

private static Sensor sensor; 
private static SensorManager ASensorManager; 

は、使用の間、これらを捨てます。

特に、あなたのアクティビティであなたのサービスへの静的な参照を保持していないことを確認してください。サービスはAndroidの性質上、シングルトンです。まだ実行している場合は、バインドするたびに同じサービスを取得します。ある時点であなたのサービスがOSによって殺されたことを数える。新たに再起動した場合は、サービスを作成してください。

これは、1日分の推測で十分です。

関連する問題