2

サービスがアプリケーションからリークしている理由を突き止めようとしています。

私が得ている公式のエラーは、サービスが登録されていないということです。

何が機能するかは次のとおりです。リスナーを作成するサービスを作成します。リスナーが別のアクティビティを開始するインテントのサービスセットをトリガーすると、リスナーが作成されます。新しい活動が始まり、その役目を果たします。

問題: サービスをオフにするオプションを提供するメイン画面に戻ると、前述のエラーが表示され、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;
}

}
4

1 に答える 1

7

センサーについてはよくわかりませんが、サービスはかなり良さそうです。

IF AccelBinder がサービスの内部クラスである場合は、それを静的な内部クラスにするか、私が通常行うように、完全に別のクラスにします。静的内部クラスには、外部クラスへの参照がありません。バインダーが漏れることを忘れないでください。Binder が静的ではない内部クラスの場合、Service への参照が含まれているため、これもリークします。

コードがない場合、Activity ライフサイクルの管理と Binder オブジェクトの処理方法に問題があると推測しています。

心に留めておくべきこと....

Binder オブジェクトへの静的参照を保持しないでください。それらは使い捨てです。バインドするたびに新しい参照を取得してください。

アクティビティのライフサイクルに関してバインディングを対称に保ちます。onCreate() でバインドする場合、onDestroy() (または isFinishing() の場合は onPause ) でバインド解除します。これは、センサーを搭載した電話の物理的な回転によってアクティビティが破棄され、最初から再作成されることを理解していない場合に特に重要です。 .

あなたは「静的な」クラス変数が好きすぎるようです。Android では、静的なことがメモリ リークにつながる傾向があります。また、リークしたものが Context を持っている場合は、事態が悪化します。同じクラスのインスタンス間で状態を維持したい場合は、代わりに Preferences を使用することを検討してください。

例えば、

private static Sensor sensor;
private static SensorManager ASensorManager;

使用の合間にこれらを捨ててください。

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

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

于 2010-12-21T10:07:55.570 に答える