10

私はアンドロイドアプリを作っています。ユーザーがaをチェックすると常にバックグラウンドで実行されるサービスを作成しています。ユーザーがチェックするcheckboxと停止する必要がunckeckあります。したがって、ボックスをチェックすると機能し、「サービス開始」トーストも表示されますがuncheckcheckbox「サービスが停止しました」というトーストが表示されますが、サービスが開始されたときに開始された音の再生は停止しません。その音を止める唯一の方法は、携帯電話の電源を切ってから入れることです。

サービスを開始および停止するための私のJavaコードは次のとおりです

public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();

    this.registerReceiver(this.batteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

    return START_STICKY;
}
public void onDestroy() {
    super.onDestroy();
    Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}

ここに私のxmlファイルがあります

<CheckBoxPreference
    android:title="Enable/Disable Alarm"
    android:defaultValue="true"
    android:key="cbAlarm"
    android:summary="Enable or disable alarm" />

ここに私のlogcatがあります

05-06 09:13:53.230: D/dalvikvm(5351): GC_EXTERNAL_ALLOC freed 39K, 50% free  2725K/5379K, external 0K/0K, paused 124ms
05-06 09:13:53.355: D/dalvikvm(5351): GC_EXTERNAL_ALLOC freed 21K, 49% free 2779K/5379K, external 504K/518K, paused 18ms
05-06 09:13:53.420: D/CLIPBOARD(5351): Hide Clipboard dialog at Starting input: finished by someone else... !
05-06 09:13:57.975: I/MediaPlayer(5351): uri is:content://media/internal/audio/media/44
05-06 09:13:57.975: I/MediaPlayer(5351): inside  getAudioFilePath: content://media/internal/audio/media/44
05-06 09:13:57.980: I/MediaPlayer(5351): The actual path is:/system/media/audio/ringtones/S_A_cricket_chirps.ogg
05-06 09:13:57.980: I/MediaPlayer(5351): path is: /system/media/audio/ringtones/S_A_cricket_chirps.ogg
05-06 09:13:57.980: I/MediaPlayer(5351): file path found for DRM file:path is: /system/media/audio/ringtones/S_A_cricket_chirps.ogg
05-06 09:13:57.980: E/MediaPlayer-JNI(5351): setDataSource: outside path in JNI is ?x@
05-06 09:14:20.525: E/ActivityThread(5351): Service com.zafar.test.BatteryService has leaked IntentReceiver com.zafar.test.BatteryService$1@40536548 that was originally registered here. Are you missing a call to unregisterReceiver()?
05-06 09:14:20.525: E/ActivityThread(5351): android.app.IntentReceiverLeaked: Service com.zafar.test.BatteryService has leaked IntentReceiver com.zafar.test.BatteryService$1@40536548 that was originally registered here. Are you missing a call to unregisterReceiver()?
05-06 09:14:20.525: E/ActivityThread(5351):     at android.app.LoadedApk$ReceiverDispatcher.<init>(LoadedApk.java:756)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:551)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:866)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.app.ContextImpl.registerReceiver(ContextImpl.java:853)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.app.ContextImpl.registerReceiver(ContextImpl.java:847)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:318)
05-06 09:14:20.525: E/ActivityThread(5351):     at com.zafar.test.BatteryService.onStartCommand(BatteryService.java:35)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2043)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.app.ActivityThread.access$2800(ActivityThread.java:117)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:998)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.os.Handler.dispatchMessage(Handler.java:99)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.os.Looper.loop(Looper.java:130)
05-06 09:14:20.525: E/ActivityThread(5351):     at android.app.ActivityThread.main(ActivityThread.java:3691)
05-06 09:14:20.525: E/ActivityThread(5351):     at java.lang.reflect.Method.invokeNative(Native Method)
05-06 09:14:20.525: E/ActivityThread(5351):     at java.lang.reflect.Method.invoke(Method.java:507)
05-06 09:14:20.525: E/ActivityThread(5351):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
05-06 09:14:20.525: E/ActivityThread(5351):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
05-06 09:14:20.525: E/ActivityThread(5351):     at dalvik.system.NativeStart.main(Native Method)
05-06 09:14:37.810: D/CLIPBOARD(5351): Hide Clipboard dialog at Starting input: finished by someone else... !

助けてください。私はどこで間違いを犯していますか。

編集

private BroadcastReceiver batteryInfoReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
        int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);

        if(plugged == 2) {

                SharedPreferences getAlarms = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
                String alarms = getAlarms.getString("ringtone", "default ringtone");
                //getting uri from MediaStore via filepath i.e. content://media/internal/audio/media/29
                Uri uri = Uri.parse(alarms);

                mMediaPlayer = new MediaPlayer();
                try {
                    mMediaPlayer.setDataSource(context, uri);
                    final AudioManager audioManager = (AudioManager) context
                            .getSystemService(Context.AUDIO_SERVICE);
                    if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
                        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
                        mMediaPlayer.prepare();
                        mMediaPlayer.start();
                    }
                } catch (IOException e) {
                    //System.out.println("OOPS");
                    e.getStackTrace();
                }
        } else if(plugged == 0) {
            mMediaPlayer.stop();
        }

    }
};
4

3 に答える 3

7

必ず終了unregisterReceiver前にお電話くださいonDestroy。サービスのコンテキストが無効になると、登録されているすべてのインテント レシーバーが動作をonDestroy停止します。Android は、「リークされたインテント レシーバー」例外で、アプリの動作が正しくないことを警告します。

受話器が呼ばれなくなったので、音楽は止まりません。onDestroy から戻る前に mMediaPlayer.stop が呼び出されるようにする必要があります。このすべての機能を個別のメソッドに抽出することをお勧めします。これにより、アプリケーションの作成がはるかに簡単になります。

private void startMusic(int level);
private void stopMusic();

また、エラーが原因で 2 つのプラグイン == 2 インテントを続けて受け取った場合は、mMusicPlayer がリークしないように注意してください。呼び出し元の追加知識に頼るよりも、防御的な方法でコードを記述する方が常に優れています。

コード内での例外処理も非常に危険です。音楽の開始に失敗した場合、音楽を停止したいときに null ポインター例外が発生することがあります。

お役に立てれば。

于 2012-05-06T07:29:03.467 に答える
1

@Override アノテーションを見逃している可能性があります

@Override
public void onDestroy() {
    unregisterReceiver(batteryInfoReceiver);
    super.onDestroy();
}
于 2012-12-19T00:27:27.917 に答える
0

少し遅いかもしれませんが、 onDestroy() メソッドが呼び出される直前に unregisterReceiver() を呼び出す必要があるようです。これで私の問題は解決しました。

于 2015-11-06T05:07:27.590 に答える