11

MediaPlayer を使用してフォアグラウンド サービスでオーディオ ファイルを再生しています。ユーザーがフォアグラウンド サービスに関連付けられた通知をタップすると、次のようにインテントを使用してアクティビティを起動します。

Intent audioPlayIntent = new Intent(context, AudioPlayActivity.class);
audioPlayIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
audioPlayIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, audioPlayIntent, 0);

次に、このアクティビティがサービスにバインドされ、MediaController がユーザーに表示されます。

サービスのバインディング コードは次のとおりです。

public class AudioPlayerServiceBinder extends Binder{

    public AudioPlayerService getAudioService(){
        return AudioPlayerService.this; //this class is declared in AudioPlayerService.java, so it has access to the Service instance.
    }

}

..そしてアクティビティで、onStartこのメソッドへの呼び出しがあります:

private void bindAudioService()
    {
        Intent i = new Intent(this, AudioPlayerService.class);
        serviceConnection = new AudioServiceConnection();
        bindService(i, serviceConnection, 0);
    }

以下の mediaController.show(5000) 行で例外が発生します。

private class AudioServiceConnection implements ServiceConnection{

    AudioPlayerServiceBinder audioServiceBinder;
@Override
        public void onServiceConnected(ComponentName name, IBinder serviceBinder)
        {
            serviceConnected = true;
            Log.i(TAG, "Connected to audio player service.");
            audioServiceBinder = ((AudioPlayerServiceBinder) serviceBinder);
            AudioPlayActivity.this.audioService = audioServiceBinder.getAudioService();
            mediaController.show(5000);
        }

例外は次のとおりです。

android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
at android.view.ViewRoot.setView(ViewRoot.java:527)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.view.Window$LocalWindowManager.addView(Window.java:424)
at android.widget.MediaController.show(MediaController.java:304)
at android.widget.MediaController.show(MediaController.java:249)
at com.myapp.AudioPlayActivity$AudioServiceConnection.onServiceConnected(AudioPlayActivity.java:295)

次の方法で同じ例外を再作成できます。

  1. 通知をクリックしてアクティビティを開く
  2. 戻るボタンを押してアクティビティを閉じます。
  3. 通知をクリックして、アクティビティの新しいバージョンを開きます。

これにより、mediaController が何らかの形でリークしており、元の Activity インスタンスに表示されようとしていると考えるようになりました。ただし、me​​diaController はアクティビティの onCreate() 内でインスタンス化され、アクティビティ自体にのみ関連付けられているため、それが発生する理由は見つかりませんでした。(その後、アクティビティはコマンドをサービスに渡す処理を行います)。

4

5 に答える 5

1

問題はこの行にあると思います。

AudioPlayActivity.this.audioService = audioServiceBinder.getAudioService();

詳細については、こちらをご覧ください。回答だけでなく、その中のすべてのコメントをお読みください。

于 2013-09-03T06:22:15.373 に答える
0

あなたが言及した手順から、手順1で作成された以前のアクティビティのリークされたインスタンスで呼び出されているようです。サービスがオンデマンド(バインドされたサービス)の場合は、 /でそれぞれonConnected()バインド/バインド解除する必要があります。onResume()onPause()

インスタンスのリークを確認するには、以下を配置します。

log.i("LEAKTEST", "Connected to instance " + this.toString());

内部onConnected()

ここで、シナリオを再作成し、logcat のオブジェクト ID に注意してください。「@1246464」のようになります。アクティビティが開始されるたびに、新しいオブジェクト ID で 1 回だけ呼び出されることを確認します。

于 2013-09-03T06:54:25.873 に答える
0

内部AudioPlayActivity's onCreate(Bundle):

を使用する代わりにsetContentView(int)、レイアウトを膨張させます (すでにこれを行っている場合はスキップしてください)。

Viewグローバル変数を宣言します。

View mContentView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mContentView = getLayoutInflater().inflate(R.layout.your_activitys_layout, null);       

    // initialize widgets
    Button b = (Button) mContentView.findViewById(...);

    ....
    ....

    // Finally
    setContentView(mContentView);
}

次のように変更AudioServiceConnectionします。

private class AudioServiceConnection implements ServiceConnection{

    AudioPlayerServiceBinder audioServiceBinder;
    @Override
    public void onServiceConnected(ComponentName name, IBinder serviceBinder)
    {
        serviceConnected = true;
        Log.i(TAG, "Connected to audio player service.");
        audioServiceBinder = ((AudioPlayerServiceBinder) serviceBinder);
        AudioPlayActivity.this.audioService = audioServiceBinder.getAudioService();

        mContentView.post(new Runnable() {

            @Override
            public void run() {
                mediaController.show(5000);
            }
        });
    }

これでWindowManager$BadTokenException.

質問を完全に誤解していた場合はお詫び申し上げます。

于 2013-09-03T06:25:44.800 に答える