由于BindService和StartService,Android服务启动2次

时间:2018-02-09 13:05:55

标签: android android-service audio-player android-music-player

我一直在研究音乐播放器应用。我正在使用一项服务来运行MediaPlayer。从片段中我使用startService(Intent)启动服务,然后将其绑定到我的活动。至少那是我打算做的。问题是我的应用程序在被终止后再次尝试启动服务,并且由于应用程序已经终止,该服务会抛出异常。

E/ActivityThread: Activity com.veloxigami.myapplication.MainActivity has leaked ServiceConnection com.veloxigami.myapplication.MainFragment$1@d8b488c that was originally bound here
android.app.ServiceConnectionLeaked: Activity com.veloxigami.myapplication.MainActivity has leaked ServiceConnection com.veloxigami.myapplication.MainFragment$1@d8b488c that was originally bound here.

我的onStartCommand()被调用了2次。虽然我已按照this link中建议的START_NOT_STICKY返回onStartCommand()来停止崩溃邮件。我想了解这里的实际问题是什么。

我的项目可以在我的GitHub上找到,如果有人想检查代码。 Music-Player-App

我在MainActivity中使用片段来处理服务。下面的代码是我在MainFragment和MediaPlayerService之间工作的地方。

MainFragment

 private ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        MediaPlayerService.LocalBinder binder = (MediaPlayerService.LocalBinder) service;
        playerService = binder.getService();
        serviceBound = true;

        Toast.makeText(getActivity(), "Media Player Active", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        serviceBound = false;
    }
};


public void playAudio(int audioIndex) {
        currentFile = audioIndex;
        if (!serviceBound) {

        // storage = new DataStorage(getActivity());
       /* storage.storeAudio(playlist);
        storage.storeAudioIndex(audioIndex);*/
        serviceBound = true;
        Log.v("TAG", "Creating new instance");
        Intent playerIntent = new Intent(getActivity(), MediaPlayerService.class);
        getActivity().startService(playerIntent);
        getActivity().bindService(playerIntent, serviceConnection, Context.BIND_AUTO_CREATE);
    } else {

        //storage = new DataStorage(getActivity());
        /*storage.storeAudio(playlist);
        storage.storeAudioIndex(audioIndex);*/

        Intent broadcastIntent = new Intent(Broadcast_PLAY_NEW_AUDIO);
        Log.v("TAG", "Broadcasting");
        getActivity().sendBroadcast(broadcastIntent);
    }



    Intent playingBroadcast = new Intent(Broadcast_PLAY_BTN_CHANGE);
    getActivity().sendBroadcast(playingBroadcast);

    Intent nextPlayingBroadcastMain = new Intent(Broadcast_SONG_TEXT_CHANGE);
    getActivity().sendBroadcast(nextPlayingBroadcastMain);
}

MediaPlayerService

private void initMediaPlayer(){
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setOnBufferingUpdateListener(this);
    mediaPlayer.setOnCompletionListener(this);
    mediaPlayer.setOnErrorListener(this);
    mediaPlayer.setOnInfoListener(this);
    mediaPlayer.setOnPreparedListener(this);
    mediaPlayer.setOnSeekCompleteListener(this);

    mediaPlayer.reset();



    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

    try{
        mediaPlayer.setDataSource(currentMedia.getData());
        currentFileIndex = MainFragment.currentFile;
        MainActivity.durationText.setText(currentMedia.getDuration());
        Toast.makeText(getApplicationContext(),"Playlist Size: "+MainFragment.playlist.size() +"\nSong No.: "+(currentFileIndex+1) ,Toast.LENGTH_SHORT).show();
    } catch (IOException e) {
        e.printStackTrace();
        stopSelf();
    }
    mediaPlayer.prepareAsync();
}

@Override
public void onCreate() {
    super.onCreate();

    callStateListener();

    registerAudioOutputChange();

    register_playNewAudio();

    registerStopMediaBroadcast();

    registerUpdatePlaylistReceiver();

    registerPlayButtonBroadcast();

    registerPrevButtonBroadcast();

    registerNextButtonBroadcast();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    try{
        playList = new ArrayList<>();
        playList = MainFragment.playlist;
        currentMedia = MainFragment.playlist.get(MainFragment.currentFile);
    }catch (NullPointerException e){
        e.printStackTrace();
        stopSelf();
    }

    if(requestAudioFocus() == false)
        stopSelf();

    if (currentMedia.getData() != null && currentMedia.getData() !="") {
        initMediaPlayer();
    }
    return START_NOT_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();

    if (mediaPlayer!=null){
        stopMedia();
        mediaPlayer.release();
    }
    removeAudioFocus();

    if(phoneStateListener != null){
        telephonyManager.listen(phoneStateListener,PhoneStateListener.LISTEN_NONE);
    }


    unregisterReceiver(audioOutputChange);
    unregisterReceiver(playNewAudio);
    unregisterReceiver(stopMediaBroadcast);
    unregisterReceiver(updatePlaylistReceiver);
    unregisterReceiver(playButtonBroadcast);
    unregisterReceiver(prevButtonBroadcast);
    unregisterReceiver(nextButtonBroadcast);

    //new DataStorage(getApplicationContext()).clearCachedAudioPlaylist();
}

1 个答案:

答案 0 :(得分:2)

您的代码中的任何位置都没有unbindService调用。因此,每当Activity被销毁时,系统都会检测到它仍然绑定到ServiceConnection并且已经泄露。在Fragment中调用bindService时仍然如此。由于片段不从Activity或Context继承,因此它们本身没有上下文引用,因此它们必须使用其父Activity上下文。记住在拥有组件被销毁时,总是调用unbindService,它是片段,活动,甚至是另一个服务。将服务绑定到其他服务并不是闻所未闻...... 如果您不希望在所有客户端解除绑定时销毁绑定服务,则需要添加特殊逻辑以确定服务是否应临时转换为已启动服务,以便操作系统不会将其终止,并停止服务当客户重新绑定它时。