1

これは私を夢中にさせています。加速度計を監視するローカル サービスを作成しました。サービスが機能する場合と機能しない場合があります。このサービスはランダムに自分自身を登録解除し続けているようです。

サービスは、電話で一定レベルの動きがあった後に反応します。問題は、サービスを開始すると、すぐに正しく終了できることです。ただし、電話を振った後 (サービスの動作をオフに設定) は何も起こらず、サービスをオフにしようとするとエラーが発生します。私を本当に混乱させているのは、動きを検出するコードにブレークコードを入れており、動きの後に呼び出されるコードが実行されていないことです。

どんな助けでも大歓迎です。これがサービスとそのマネージャーのコードです。

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

    private static SensorEventListener accelEventListener = 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);
            if (force > max)
                max = force;

            if (force > AccelManager.dropValue)                
                AccelManager.onDrop(force);                
        } 
    };

private static void startListener() {
    ASensorManager = (SensorManager) CONTEXT.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);
        AccelManager.setListening(listening);
    }
} 

private final IBinder mBinder = new AccelBinder();

public class AccelBinder extends Binder {
    AccelService getService() {
        return AccelService.this;
    }
}

public void onCreate() {
    CONTEXT = this;
    startListener();
}

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();
        super.onDestroy();
    }

    public static void stopListening() {  
        AccelManager.setListening(false);
        try {
            if (ASensorManager != null && accelEventListener != null)
                ASensorManager.unregisterListener(accelEventListener);            
        } catch (Exception e) {}     
    }

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

これがマネージャークラスです。

public class AccelManager extends Activity {

    public static Boolean isListening = false;
    private static Boolean callMade = false;
    public static Context ctxt;
    public static int dropValue = 100;
    private static Intent i;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    public void setContext(Context context) {
        ctxt = context;
        i = getIntent();
    }


    public void activateService(Boolean check) {
        if (check)
            doBindService();
        else {
            if (isListening) {
                if (AccelWatch != null) {
                    AccelWatch.stopSelf();
                    doUnbindService();
                }
            }
        }    
    }

    public static void onDrop(double force){
        if (!callMade) {
            Toast.makeText(ctxt, "Phone dropped: " + force, 5000).show();
            Intent i = new Intent(ctxt,DropDetected.class);
            AccelWatch.stopSelf();
            doUnbindService();
            callMade = true;
            ctxt.startActivity(i);
        }
    }

    private void doBindService() {
        if (!isListening) {
            i = new Intent(ctxt,AccelService.class);
            ctxt.bindService(i, AccelConnection, ctxt.BIND_AUTO_CREATE);
        }
    }

    private static void doUnbindService() {
        if (isListening)         
            ctxt.unbindService(AccelConnection);
    }    

    public void setDropValue(int drop) {
        dropValue = drop;
    }

    public boolean isRunning(){
        return AccelWatch.isListening();
    }

    public static void setListening(Boolean listen){
        isListening = listen;
    }

    private static AccelService AccelWatch;

    private static ServiceConnection AccelConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service)     {
            AccelWatch = ((AccelService.AccelBinder)service).getService();
            AccelWatch.startService(i);

            Toast.makeText(ctxt, "The service is binded.",Toast.LENGTH_SHORT).show();
        }

        public void onServiceDisconnected(ComponentName className) {
            AccelWatch = null;
            Toast.makeText(ctxt, "The service was disconnected.",Toast.LENGTH_SHORT).show();
        }
    };
}
4

2 に答える 2

4

まず、永続的に実行される Service を作成しようと考えている場合は、そうしないことを検討する必要があります。常に実行されているサービスは、バッテリーの寿命に非常に悪いです。

それはさておき、私は取り除くことをお勧めします

    AccelWatch.startService(i); 

onServiceConnected()

サービスにバインドすると、サービスが自動的に開始されonServiceConnected()、非同期コールバックが取得されます。そのため、その行でサービスを効果的に再起動しようとしている可能性があります。

これは絶対にしないでください

    private static Context CONTEXT;

その後、

    CONTEXT = this;

サービスの寿命ではなく、アプリケーションの寿命のために静的参照が存在するため、サービス(およびそこで行ったアクティビティも)をリークすることを保証しました。コンテキストが必要な場合は、「this」を使用してください。あなたはすでにサービス/アクティビティの中にいます。

あなたのサービスをリークする別のソースはここにあります....

public class AccelBinder extends Binder {
     AccelService getService() {
         return AccelService.this;
     }
 }

この内部クラスは静的ではありません。Java では、これは内部クラスが外部クラスへの参照を持つことを意味します。Android にはバグ (Issue 6426) があり、システムが常にバインダーをリークします。バインダーがサービスへの参照を持っている場合 (非静的内部クラスがそうであるように)、サービスもリークします。

ServiceonStart()このバージョンを使用しているデバイスは 7% 未満であるため、バージョン 5 (Android 1.6) 以降は非推奨です。少なくともサービスが機能するようになるまでは削除することをお勧めします。これについて考える必要がないようにします。

あなたがそれをどのように進めるかを見てください。サービスを永続化するのは非常に簡単です。最初は少し調整するだけです (ライフサイクルなど)。

これらの問題はよくあることなので、ちょっとしたガイダンスを提供するために、ここにブログを書くことにしました。

http://www.ozdroid.com/#!BLOG/2010/12/19/How_to_make_a_local_Service_and_bind_to_it_in_Android

この例では、- ではなく Service を使用するバインディング メソッドを使用していonStart()ますが、初心者向けに少し文脈を整理してみました。

于 2010-12-19T09:27:05.190 に答える
0

いくつかのログを追加して、サービスの登録解除の原因を確認し、logcat ビューでサービスの例外があるかどうかを確認できます。

于 2010-12-17T09:15:26.173 に答える