对服务的引用变为null

时间:2016-09-01 11:19:52

标签: android

我有一个启动并绑定到服务的活动。我在手机的“开发者选项”中启用了“不要保持活动”选项来测试此功能。

当我第一次运行应用程序时,活动和服务都会启动。我可以毫无问题地使用该应用程序。然后我按下主页按钮,活动和服务都立即被杀死。然后我再次启动应用程序,活动正常启动,服务启动并正常绑定,服务实例正常保存在musicService变量中。然后我使用试图在musicService上调用方法的活动,它因为musicService为空而崩溃。

我正在启动服务并在我的活动的onStart中绑定它:

@Override
protected void onStart() {
    super.onStart();
    initMusicService();
}

private void initMusicService() {

    LocalBroadcastManager.getInstance(this).registerReceiver(onMediaPlayerPlayingReceiver,
            new IntentFilter("MEDIA_PLAYER_PLAYING"));

    if (musicServiceIntent == null) {

        musicServiceIntent = new Intent(this, MusicService.class);
        bindService(musicServiceIntent, musicServiceConnection, 0);
        startService(musicServiceIntent);

    }

}

然后我在连接时保存对服务的引用:

private ServiceConnection musicServiceConnection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {

        MusicBinder binder = (MusicBinder) service;
        musicService = binder.getService();
       ...

    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

        tabPagerAdapter.getNowPlayingFragment().unbindController();

    }
};

这是我活动的onDestroy方法:

@Override
protected void onDestroy() {

    unbindService(musicServiceConnection);
    stopService(musicServiceIntent);
    musicService = null;

    super.onDestroy();

}

这是logcat中的错误:

09-01 07:41:25.393: E/AndroidRuntime(20592): FATAL EXCEPTION: main
09-01 07:41:25.393: E/AndroidRuntime(20592): java.lang.NullPointerException
09-01 07:41:25.393: E/AndroidRuntime(20592):    at com.zezo.music.MusicPlayerActivity$2.onReceive(MusicPlayerActivity.java:101)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at android.support.v4.content.LocalBroadcastManager.executePendingBroadcasts(LocalBroadcastManager.java:297)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at android.support.v4.content.LocalBroadcastManager.access$000(LocalBroadcastManager.java:46)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at android.support.v4.content.LocalBroadcastManager$1.handleMessage(LocalBroadcastManager.java:116)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at android.os.Handler.dispatchMessage(Handler.java:99)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at android.os.Looper.loop(Looper.java:137)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at android.app.ActivityThread.main(ActivityThread.java:5103)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at java.lang.reflect.Method.invokeNative(Native Method)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at java.lang.reflect.Method.invoke(Method.java:525)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
09-01 07:41:25.393: E/AndroidRuntime(20592):    at dalvik.system.NativeStart.main(Native Method)

我在重新启动活动后使用断点,并且看到onServiceConnected被调用,musicService = binder.getService();运行且musicService不为空。

在同一项活动中:

public void play(Song song) {

    if (song != null && musicService.audioFocusGranted()) {
        musicService.playSong(song);
        Toast.makeText(this, "Playing.", Toast.LENGTH_SHORT).show();
    }

}

private BroadcastReceiver onMediaPlayerPlayingReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context c, Intent i) {

        if (i.getAction() != "MEDIA_PLAYER_PLAYING")
            return;

        Song song = musicService.getCurrentSong();

       ...

    }
};

重新启动后,play方法中的musicService不为null,分配给它的服务工作正常,但onReceive中的服务为null。而且musicService是活动实例的成员,因此它在两个方法中应该具有相同的值。不知怎的,就好像它首先被分配但是然后在调用之间被取消分配或者被分配到一个活动实例中,但是以某种方式在同一活动的被破坏的实例中被调用。

清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zezo.music"
    android:versionCode="155"
    android:versionName="1.55">

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" />

<!-- Soft input delete key not working bug above target 13 and above min 8. -->
<uses-sdk
    android:minSdkVersion="16"
    android:targetSdkVersion="23" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/MyTheme">
    <activity
        android:name="com.zezo.music.MusicPlayerActivity"
        android:configChanges="orientation|screenSize"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:screenOrientation="fullSensor"
        android:windowSoftInputMode="stateHidden">

        <meta-data
            android:name="android.app.searchable"
            android:resource="@xml/searchable" />

        <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
        </intent-filter>

        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>

    <service android:name="com.zezo.music.MusicService">
        <intent-filter>
            <action android:name="com.zezo.zezomusicplayer.MusicService.BIND" />

            <category android:name="android.intent.category.DEFAULT" />

            <action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
            <action android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" />
            <action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
        </intent-filter>
    </service>

    <receiver
        android:name="com.zezo.music.MediaButtonReceiver"
        android:enabled="true">
        <intent-filter android:priority="2147483647">
            <action android:name="android.intent.action.MEDIA_BUTTON" />
        </intent-filter>
    </receiver>

</application>

2 个答案:

答案 0 :(得分:1)

问题是绑定到Service是异步的,并且您试图使用与绑定无关的BroadcastReceiver。这就是为什么当您致电bindService()时提供ServiceConnection。调用onServiceDisconnected()后,您需要清除Binder引用,因为它已不存在(尽管这不是您当前的问题。)

使用此代码解决此问题的最简单方法是在调用onServiceConnected()之前不注册接收器。您还可以添加一些媒体状态跟踪,并在接收器中仅调用服务(如果它是非空的)并在onServiceConnected()检查以查看您是否有可用的状态信息需要立即传递给服务

答案 1 :(得分:1)

Activity应注册BroadcastReceivers的唯一原因是以某种方式对当前活动使用事件,以通知用户事件。如果已调用onPause(),则活动不再位于前台,因此无法更新用户。

您应该在onStart()onStop()注册和取消注册您的接收者。 onDestroy()不能保证被调用,即使活动不再打开,您也可以继续接收广播很长时间。