4

音楽ストリーミングアプリを作成しています。Android の MediaPlayer ガイドに従って、サービスから MediaPlayer を制御しています。これはすべて正常に機能し、再生を制御するために MediaController を追加しようとしています。そのために、Service に MediaController.MediaPlayerControl を実装させ、Activity を Service にバインドしてから、ServiceConnection の Service コンテキストを使用して Activity から MediaController をインスタンス化します。

Player.java

public class Player extends Activity implements OnClickListener, OnItemClickListener, MediaController.MediaPlayerControl {
    private MediaController mediaController;
    private ServiceConnection mConnection = new ServiceConnection() {    
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
            showMediaController();
        }    
        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_player);

        startService(
            new Intent(this, PlayerService.class)
            .setAction("com.limastreamer.action.NEXTSHOW"));

        bindService(
            new Intent(this, PlayerService.class),
            mConnection,
            Context.BIND_AUTO_CREATE);
    }

    public void showMediaController() {
        if (mBound) {
            mediaController = new MediaController(this);
            mediaController.setAnchorView(
                findViewById(R.id.player)
                );
            mediaController.setMediaPlayer(mService);
            mediaController.setEnabled(true);
            mediaController.show(0);
        }
    }
}

PlayerService.java

public class PlayerService extends Service implements MediaController.MediaPlayerControl {
    private MediaPlayer mMediaPlayer;

    public class LocalBinder extends Binder {
        PlayerService getService() {
            return PlayerService.this;
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        String action = intent.getAction();
        if (action.equals("com.limastreamer.action.NEXTSHOW")) {
            if (mMediaPlayer == null)
            {
                mMediaPlayer = new MediaPlayer();
                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                mMediaPlayer.setLooping(false);         
            }
            try
            {
                mMediaPlayer.reset();
                mMediaPlayer.setDataSource(url);
                mMediaPlayer.prepareAsync(); // prepare async to not block main thread
            }
            catch (Exception ex)
            {
                Toast.makeText(getApplicationContext(), "Failed to prepare MediaPlayer", Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    public boolean canPause() {
        return true;
    }

    @Override
    public boolean canSeekBackward() {
        return true;
    }

    @Override
    public boolean canSeekForward() {
        return true;
    }

    @Override
    public int getBufferPercentage() {
        return 0;
        }

    @Override
    public int getCurrentPosition() {
        if (mMediaPlayer != null && mMediaPlayer.isPlaying())
            return mMediaPlayer.getCurrentPosition();
        else
            return 0;
    }

    @Override
    public int getDuration() {
        if (mMediaPlayer != null && mMediaPlayer.isPlaying())
            return mMediaPlayer.getDuration();
        else
            return 0;
    }

    @Override
    public boolean isPlaying() {
        if (mMediaPlayer != null)
            return mMediaPlayer.isPlaying();
        else
            return false;
    }

    @Override
    public void pause() {
        if (mMediaPlayer != null)
            mMediaPlayer.pause();
    }

    @Override
    public void seekTo(int msec) {
        if (mMediaPlayer != null)
            mMediaPlayer.seekTo(msec);
    }

    @Override
    public void start() {
        if (mMediaPlayer != null)
            mMediaPlayer.start();       
    }
}

R.id.player は、私の xml レイアウトのルート要素を参照します。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/player"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".Player" >

mediaController.show();例外を除いて、アプリの爆弾を呼び出すと:Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?

SO に関する他の質問 (たとえば) を見ると、これはここで間違ったコンテキストを使用していることが原因のようです:mediaController = new MediaController(this);つまり、Activity コンテキスト以外のものを使用しています。しかし、私が知る限り、Activity コンテキストを使用しています。

私はもう試した:

  1. レイアウト内の他のビューをアンカー ビューとして使用する (アクティビティのメイン ビューを使用できるとドキュメントに記載されていても)
  2. ここに示すように、MediaController をフラグメントに入れ、コンテキストとして getActivity() を使用する
  3. プログラムでインスタンス化する代わりに、MediaController を xml レイアウトに配置します。
  4. VideoView をアンカー ビューとして設定します (VideoView でのみ機能すると言う人もいます)。
  5. VideoView を拡張して MediaPlayerControl を実装する新しいクラスを作成し、そのクラスで MediaController をインスタンス化し、初期化時にクラスに渡された保存済みコンテキストをコンテキストおよびthisアンカー ビューとして使用します。
4

1 に答える 1

1

アクティビティは MediaPlayer.OnPreparedListener を実装し、サービスの mediaPlayer の onPreparedListener をプレーヤー アクティビティに設定する必要があります。

public class MyMediaPlayer extends Activity implements 
MediaController.MediaPlayerControl,MediaPlayer.OnPreparedListener {
...
public void onCreate(Bundle savedInstanceState) {
...
    //this mediaPlayer is the reference of your media player inside your service
    mediaPlayer.setOnPreparedListener(this);
...
}
...
}

また、アクティビティを作成した少し後にサービスを開始する必要があります

 Intent in=new Intent(MainPlayer.this,MyMediaPlayer.class);
        startActivity(in);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //START YOUR SERVICE TO PREPARE YOUR PLAYER

これは私にとってはうまくいきます。

于 2015-09-01T08:39:38.230 に答える