android.content.Context.getSystemService(java.lang.String)'对空对象引用错误的大问题

时间:2018-03-14 19:00:27

标签: android service android-mediaplayer mediacontroller mediabrowserservicecompat

我正在尝试在Android中构建一个音乐应用程序,虽然我有时觉得新手可笑。我已经研究了很多,尽力了解MediaPlayer,MediaBrowserCompat / MediaBrowserServiceCompat,MediaController和Services如何工作,数十个遗憾的旧教程如何构建一个。

我最大的问题是,他们中的大多数都倾向于使用IBinder功能和意图来绑定和启动musicPlaybackService,而google的文档使用了这些MediaBrowser和MediaBrowserService API,这两种方法对我来说都是新的,老实说非常困难和压倒性。

到目前为止我学到了很多,但很难。我发现的两个稍好的教程是 https://www.sitepoint.com/a-step-by-step-guide-to-building-an-android-audio-player-app/https://code.tutsplus.com/tutorials/background-audio-in-android-with-mediasessioncompat--cms-27030他们使用第一种和第二种方法。我的应用程序版本是我通过整理我学到的所有部分而设法制作的。

我自己设法解决了很多错误和问题,但是我遇到了一个N​​ullPointer异常,我根本就不知道如何解决。调试器在这个问题上也很奇怪,每次错误都来自程序的另一个地方时,感觉差不多;有时它会在我放置的断点处停止,然后使用完全相同的代码和断点再次运行调试器,它会跳过它们并直接进入运行时错误。

这是我的Manifest.xml:

public class MediaPlaybackService extends MediaBrowserServiceCompat implements
    MediaPlayer.OnCompletionListener,

    AudioManager.OnAudioFocusChangeListener {

public static final String COMMAND_EXAMPLE = "command_example";
public static boolean isServiceStarted = false;

/*public int audioIndex;
public ArrayList<Audio> audioList;
public Audio activeAudio;*/

private MediaPlayer gesMediaPlayer;
private MediaSessionCompat gesMediaSession;
private int pausedPosition;

//-------------------------------------Lifecycle methods--------------------------------------//

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

    Log.d("onCreate: ", "Service created");
    initMediaPlayer();
    initMediaSession();
    callStateListener();
    registerNoisyReceiver();

    // Set an initial PlaybackState with ACTION_PLAY, so media buttons can start the player
    PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder()
            .setActions(
                        PlaybackStateCompat.ACTION_PLAY |
                            PlaybackStateCompat.ACTION_PLAY_PAUSE);
    gesMediaSession.setPlaybackState(playbackStateBuilder.build());
}
@Override
public void onDestroy() {
    super.onDestroy();
    if (gesMediaPlayer != null) {
        gesMediaPlayer.stop();
        gesMediaPlayer.release();
    }

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

    removeAudioFocus();
    unregisterReceiver(becomingNoisyReceiver);

    //clear cached playlist
    //new StorageUtils(getApplicationContext()).clearCachedAudioPlaylist();
    NotificationManagerCompat.from(this).cancel(1);
    stopSelf();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d("onStartCommand: ", "Service has been started");
    MediaButtonReceiver.handleIntent(gesMediaSession, intent);
    return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
    if( gesMediaPlayer != null ) {
        gesMediaPlayer.release();
    }
}

//----------------------------------------Initialisers----------------------------------------//

private void initMediaPlayer() {
    gesMediaPlayer = new MediaPlayer();
    gesMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
    gesMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    gesMediaPlayer.setVolume(1.0f, 1.0f);

    /*try {
        //sets songPath as data source for media player
        //gesMediaPlayer.setDataSource(songPath);

        //sets current song as data source for media player
        gesMediaPlayer.setDataSource(activeAudio.getData());
    } catch (IOException e) {
        e.printStackTrace();
        stopSelf();
    }
    gesMediaPlayer.prepareAsync();*/
}
private void initMediaSession() {
    ComponentName mediaButtonReceiver = new ComponentName(getApplicationContext(), MediaButtonReceiver.class);
    gesMediaSession = new MediaSessionCompat(getApplicationContext(), "GESMediaService",
                                                mediaButtonReceiver, null);

    gesMediaSession.setCallback(mediaSessionCallbacks);
    gesMediaSession.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
            MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS );

    //this is for pre-Lollipop media button handling on those devices
    Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
    mediaButtonIntent.setClass(this, MediaButtonReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
    gesMediaSession.setMediaButtonReceiver(pendingIntent);

    // Set the session's token so that client activities can communicate with it.
    setSessionToken(gesMediaSession.getSessionToken());
}
private void registerNoisyReceiver() {
    //Handles headphones coming unplugged. cannot be done through a manifest receiver
    IntentFilter noisyFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
    registerReceiver(becomingNoisyReceiver, noisyFilter);
}
private void initMediaSessionMetadata() {
    MediaMetadataCompat.Builder metadataBuilder = new MediaMetadataCompat.Builder();

    //Notification icon in card
    metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
    metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));

    //lock screen icon for pre lollipop
    metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
    metadataBuilder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Display Title");
    metadataBuilder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Display Subtitle");
    metadataBuilder.putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, 1);
    metadataBuilder.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, 1);

    gesMediaSession.setMetadata(metadataBuilder.build());
}
//-----------------------------------Media Playback functions---------------------------------//

//TODO: read about the AssetFileDescriptor, and the ResultReceiver

private MediaSessionCompat.Callback mediaSessionCallbacks = new MediaSessionCompat.Callback() {
    @Override
    public void onPlay() {
        super.onPlay();
        if(!requestAudioFocus()) {
            //failed to gain focus
            return;
        }
        //check if service is started, not only bound
        if(!isServiceStarted){
            startService(new Intent(getApplicationContext(), MediaPlaybackService.class));
        }

        gesMediaSession.setActive(true);
        setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING);
        showPlayingNotification();
        gesMediaPlayer.start();
    }
    @Override
    public void onPause() {
        super.onPause();

        if( gesMediaPlayer.isPlaying() ) {
            gesMediaPlayer.pause();
            setMediaPlaybackState(PlaybackStateCompat.STATE_PAUSED);
            showPausedNotification();
        }
    }
    @Override
    public void onPlayFromMediaId(String mediaId, Bundle extras) {
        super.onPlayFromMediaId(mediaId, extras);

        try {
            AssetFileDescriptor afd = getResources().openRawResourceFd(Integer.valueOf(mediaId));
            if( afd == null ) {
                Log.d("afd: ", "afd in onPlayFromMediaId is null");
                return;
            }

            try {
                gesMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());

            } catch( IllegalStateException e ) {
                gesMediaPlayer.release();
                initMediaPlayer();
                gesMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
            }

            afd.close();
            initMediaSessionMetadata();

        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        try {
            gesMediaPlayer.prepare();
        } catch (IOException e) {
            e.printStackTrace();
            Log.d("onPlayFromId: ", "mediaPlayer failed to prepare");
        }

        //Work with extras here if you want
    }
    @Override
    public void onCommand(String command, Bundle extras, ResultReceiver cb) {
        super.onCommand(command, extras, cb);
        if( COMMAND_EXAMPLE.equalsIgnoreCase(command) ) {
            //Custom command here
        }
    }
    @Override
    public void onSeekTo(long pos) {
        super.onSeekTo(pos);
    }
};

private void setMediaPlaybackState(int state) {
    PlaybackStateCompat.Builder playbackstateBuilder = new PlaybackStateCompat.Builder();
    if( state == PlaybackStateCompat.STATE_PLAYING ) {
        playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE |
                                        PlaybackStateCompat.ACTION_PAUSE);
    } else {
        playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE |
                                        PlaybackStateCompat.ACTION_PLAY);
    }
    playbackstateBuilder.setState(state, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 0);
    gesMediaSession.setPlaybackState(playbackstateBuilder.build());
}


//-------------------------------Audio Focus and Calls Handling-------------------------------//

//Handle incoming phone calls
private boolean ongoingCall = false;
private PhoneStateListener phoneStateListener;
private TelephonyManager telephonyManager;
private AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

@Override
public void onAudioFocusChange(int focusChange) {
    switch( focusChange ) {
        case AudioManager.AUDIOFOCUS_LOSS: {
            // Lost focus for an unbounded amount of time:
            // stop playback and release media player
            if( gesMediaPlayer.isPlaying() ) {
                gesMediaPlayer.stop();
            }
            /*gesMediaPlayer.release();
            gesMediaPlayer = null;*/
            break;
        }
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: {
            // Lost focus for a short time; Pause only and do not
            // release the media player as playback is likely to resume
            if (gesMediaPlayer.isPlaying()) {
                gesMediaPlayer.pause();
            }
            break;
        }
        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: {
            // Lost focus for a short time (ex. notification sound)
            // but it's ok to keep playing at a temporarily attenuated level
            if( gesMediaPlayer != null ) {
                gesMediaPlayer.setVolume(0.2f, 0.2f);
            }
            break;
        }
        case AudioManager.AUDIOFOCUS_GAIN: {
            //Invoked when the audio focus of the system is updated.
            if( gesMediaPlayer != null ) {
                if( !gesMediaPlayer.isPlaying() ) {
                    gesMediaPlayer.start();
                }
                gesMediaPlayer.setVolume(1.0f, 1.0f);
            }
            break;
        }
    }
}
private boolean requestAudioFocus() {
    AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    int result = audioManager.requestAudioFocus(this,
            AudioManager.STREAM_MUSIC,
            AudioManager.AUDIOFOCUS_GAIN);
    return result == AudioManager.AUDIOFOCUS_GAIN;
}
private boolean removeAudioFocus() {
    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
            audioManager.abandonAudioFocus(this);
}
private void callStateListener() {
    // Get the telephony manager
    telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    //Starting listening for PhoneState changes
    phoneStateListener = new PhoneStateListener() {
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            switch (state) {
                //if at least one call exists or the phone is ringing
                //pause the MediaPlayer
                case TelephonyManager.CALL_STATE_OFFHOOK:
                case TelephonyManager.CALL_STATE_RINGING:
                    if (gesMediaPlayer != null && gesMediaPlayer.isPlaying()) {
                        gesMediaPlayer.pause();
                        pausedPosition = gesMediaPlayer.getCurrentPosition();
                        ongoingCall = true;
                    }
                    break;
                case TelephonyManager.CALL_STATE_IDLE:
                    // Phone idle. Start/resume playing.
                    if (gesMediaPlayer != null) {
                        if (ongoingCall) {
                            ongoingCall = false;
                            gesMediaPlayer.seekTo(pausedPosition);
                            gesMediaPlayer.start();
                        }
                    }
                    break;
            }
        }
    };
    // Register the listener with the telephony manager
    // Listen for changes to the device call state.
    telephonyManager.listen(phoneStateListener,
            PhoneStateListener.LISTEN_CALL_STATE);
}
private BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if( gesMediaPlayer != null && gesMediaPlayer.isPlaying() ) {
            gesMediaPlayer.pause();
        }
    }
};
//------------------------------------Less important methods----------------------------------//

@Nullable
@Override
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) {
    if(TextUtils.equals(clientPackageName, getPackageName())) {
        return new BrowserRoot(getString(R.string.app_name), null);
    }

    return null;
}

//Not important for general audio service, required for class
@Override
public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
    result.sendResult(null);
}

然后这是我的MainActivity.java

class Postlist extends React.Component {
    state = {
        posts: [],
        comments: []
    };

    componentDidMount() {
        axios.get(`https://jsonplaceholder.typicode.com/posts`).then(res => {
            const posts = res.data;
            this.setState({ posts });
        });

        axios.get(`https://jsonplaceholder.typicode.com/comments`).then(res => {
            const comments = res.data;
            this.setState({ comments });
        });
    }

    render() {
        return (
            <div className="container">
                <div className="jumbotron-div col s12">
                    <ul className="collection">
                        {this.state.posts.map(post =>
                            (
                                <div>
                                    <li
                                        key={post.id}
                                        className="collection-item left-align red lighten-3"
                                    >
                                        <h5>User ID: {post.id}</h5>
                                        <p>Post: {post.body}</p>
                                    </li>
                                    <div className="jumbotron-div col s12">
                                        <ul className="collection">
                                            {
                                                this.state.comments.map(comment => (
                                                    <li
                                                        key={comment.id}
                                                        className="collection-item left-align purple lighten-2"
                                                    >
                                                        <p>User ID: {comment.id}</p>
                                                        <p>Post: {comment.body}</p>
                                                    </li>
                                                )
                                                )
                                            }
                                        </ul>
                                    </div>
                                </div>
                            ))
                        }
                    </ul>
                </div>
            </div>
        );
    }
}

ReactDOM.render(
    <Postlist name="World" />,
    document.getElementById('container')
);

然后是playbackService.java

<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

}

我为整个代码道歉,但此时我不知道我在做什么错误或在哪里看。特别是因为该应用程序确实在以前的版本中工作。如果你们在我的代码中看到任何特定内容,那么任何建议都会很受欢我尝试尽可能地捕获异常,但同时我不知道我应该在哪里放置try-catch构造。我正在尝试学习 谢谢任何人!

0 个答案:

没有答案