Отображение метода обратного вызова для сервиса в Android - PullRequest
0 голосов
/ 10 января 2019

Я занимаюсь разработкой сервиса проигрывателя фоновой музыки с уведомлением в Android. При выполнении кода отображается ошибка метода CallBack из класса обслуживания.

Может кто-нибудь, пожалуйста, помогите мне решить эту ошибку? Заранее спасибо.

Вот мой код MainActivity:

public class MainActivity extends AppCompatActivity implements NotificationService.Callbacks {
MediaPlayer mediaPlayer;
Intent serviceIntent;
NotificationService notificationService;
LinearLayout customMediaController;
Button playPauseButton, forwardButton, rewindButton;
SeekBar seekBar;
TextView timer;
ProgressBar loader;
ProgressBar progressBar;
Handler handler = new Handler();
RemoteViews notificationLayout;
PendingIntent pendingIntent;
NotificationManagerCompat notificationManager;
final Integer CALL = 0x2;
TelephonyManager telephonyManager;
PhoneStateListener phoneStateListener;
AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    startBindService();//start background service to control music while app is running in background
    initialiseAllView();//iniatialise all UI part
    handler.postDelayed(runnable, 1000);//update progress of song
    setNotification();// show controllers in notification bar
    callHandler();//to handle phone calls in between
    audioHandler();// to handle another app playing song in between
}

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        if (mediaPlayer != null) {
            if (mediaPlayer.isPlaying()) {
                playPauseButton.setBackgroundResource(R.drawable.ic_pause_circle_outline_black_24dp);
            } else {
                playPauseButton.setBackgroundResource(R.drawable.ic_play_circle_outline_black_24dp);
            }
            updateTimer();
        }
        handler.postDelayed(runnable, 1000);
    }
};
//callback of controllers from notification bar
@Override
public void updateClient(final MediaPlayer mediaPlayer) {
    this.mediaPlayer = mediaPlayer;
    if (this.mediaPlayer != null) {
        seekBar.setMax(this.mediaPlayer.getDuration());
        this.mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
            @Override
            public void onBufferingUpdate(MediaPlayer mp, int percent) {
                progressBar.setSecondaryProgress(percent);
            }
        });
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                seekMediaPlayer(seekBar);
            }
        });
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                mp.seekTo(0);
                mp.start();
            }
        });
    }
}

public void onForwardButtonClick(View view) {
    if (mediaPlayer != null) {
        mediaPlayer.seekTo(mediaPlayer.getCurrentPosition() + 2000);
        seekBar.setProgress(mediaPlayer.getCurrentPosition() + 2000);
    }
}

public void onRewindButtonClick(View view) {
    if (mediaPlayer != null) {
        mediaPlayer.seekTo(mediaPlayer.getCurrentPosition() - 2000);
        seekBar.setProgress(mediaPlayer.getCurrentPosition() - 2000);
    }
}

public void onPlayPauseClick(View view) {
    if (mediaPlayer != null) {
        if (mediaPlayer.isPlaying()) {
            pauseMusic();
        } else {
            playMusic();
        }
    }
}

public void playMusic() {
    if (mediaPlayer != null) {
        mediaPlayer.start();
        playPauseButton.setBackgroundResource(R.drawable.ic_pause_circle_outline_black_24dp);
        notificationLayout.setImageViewResource(R.id.playnotify, R.drawable.ic_pause_black_24dp);
        updateNotification();
    }
}

public void pauseMusic() {
    if (mediaPlayer != null) {
        mediaPlayer.pause();
        playPauseButton.setBackgroundResource(R.drawable.ic_play_circle_outline_black_24dp);
        notificationLayout.setImageViewResource(R.id.playnotify, R.drawable.ic_play_arrow_black_24dp);
        updateNotification();
    }
}

private void seekMediaPlayer(SeekBar seekBar) {
    mediaPlayer.seekTo(seekBar.getProgress());
}

private ServiceConnection mConnection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName className,
                                   IBinder service) {
        NotificationService.LocalBinder binder = (NotificationService.LocalBinder) service;
        notificationService = binder.getServiceInstance();
        notificationService.registerClient(MainActivity.this);
    }

    @Override
    public void onServiceDisconnected(ComponentName arg0) {

    }
};

public void startBindService() {
    serviceIntent = new Intent(MainActivity.this, NotificationService.class);
    serviceIntent.putExtra("Hello","Hello");
    serviceIntent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
    startService(serviceIntent);
    bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
}

public void initialiseAllView() {
    customMediaController = findViewById(R.id.customMediaController);
    progressBar = findViewById(R.id.progressBar);
    loader=findViewById(R.id.progress);
    playPauseButton = findViewById(R.id.bttn);
    forwardButton = findViewById(R.id.forward);
    rewindButton = findViewById(R.id.rewind);
    timer = findViewById(R.id.timer);
    seekBar = findViewById(R.id.seekBar);
}

public void updateNotification() {
    Notification customNotification = new NotificationCompat.Builder(this, "notify")
            .setSmallIcon(R.drawable.ic_music_note_black_24dp)
            .setStyle(new NotificationCompat.DecoratedCustomViewStyle())
            .setCustomContentView(notificationLayout)
            .setOngoing(true)
            .setContentIntent(pendingIntent)
            .build();
    notificationManager = NotificationManagerCompat.from(this);
    notificationManager.notify(1, customNotification);
}

public void setNotification() {
    notificationLayout = new RemoteViews(getPackageName(), R.layout.notification);
    Intent notificationIntent = new Intent(this, MainActivity.class);
    notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    pendingIntent = PendingIntent.getActivity(this, 0,
            notificationIntent, 0);
    Intent playIntent = new Intent(this, NotificationService.class);
    playIntent.setAction(Constants.ACTION.PLAY_ACTION);
    PendingIntent pendingPlayIntent = PendingIntent.getService(this, 0,
            playIntent, 0);
    notificationLayout.setOnClickPendingIntent(R.id.playnotify, pendingPlayIntent);
    Intent rewindIntent = new Intent(this, NotificationService.class);
    rewindIntent.setAction(Constants.ACTION.PREV_ACTION);
    PendingIntent pendingRewindIntent = PendingIntent.getService(this, 0,
            rewindIntent, 0);
    notificationLayout.setOnClickPendingIntent(R.id.rewindnotify, pendingRewindIntent);
    Intent forwardIntent = new Intent(this, NotificationService.class);
    forwardIntent.setAction(Constants.ACTION.NEXT_ACTION);
    PendingIntent pendingForwardIntent = PendingIntent.getService(this, 0,
            forwardIntent, 0);
    notificationLayout.setOnClickPendingIntent(R.id.forwardnotify, pendingForwardIntent);
}

public void callHandler() {
    int permissionGranted = askForPermission(Manifest.permission.READ_PHONE_STATE, CALL);
    if (permissionGranted == 1) {
        phoneStateListener = new PhoneStateListener() {
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                if (state == TelephonyManager.CALL_STATE_RINGING) {
                    //Incoming call: Pause music
                    pauseMusic();
                } else if (state == TelephonyManager.CALL_STATE_IDLE) {
                    //Not in call: Play music
                    if (mediaPlayer != null && !mediaPlayer.isPlaying())
                        playMusic();
                } else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
                    //A call is dialing, active or on hold
                    pauseMusic();
                }
                super.onCallStateChanged(state, incomingNumber);
            }
        };
        telephonyManager = (TelephonyManager) this
                .getSystemService(Context.TELEPHONY_SERVICE);
        if (telephonyManager != null) {
            telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
        }
    }
}

public void audioHandler() {
    onAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
        @Override
        public void onAudioFocusChange(int focusChange) {
            switch (focusChange) {
                case AudioManager.AUDIOFOCUS_LOSS:
                    pauseMusic();
                    break;
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                    pauseMusic();
                    break;
            }
        }
    };
    AudioManager audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
    // Request audio focus for play back
    if (audioManager != null) {
        audioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
    }
}

public void updateTimer() {
    int currentPosition = mediaPlayer.getCurrentPosition();
    if(currentPosition!=0)
    {
        loader.setVisibility(View.GONE);
    }
    seekBar.setProgress(currentPosition);
    int t = currentPosition / 1000;
    int min = t / 60;
    int sec = t % 60;
    if (min < 10) {
        if (sec < 10) {
            String string = "0" + min + ":0" + sec;
            timer.setText(string);
        } else {
            String string = "0" + min + ":" + sec;
            timer.setText(string);
        }
    }
    if (min >= 10) {
        if (sec < 10) {
            String string = min + ":0" + sec;
            timer.setText(string);
        } else {
            String string = min + ":" + sec;
            timer.setText(string);
        }
    }
}

private int askForPermission(String permission, Integer requestCode) {
    if (ContextCompat.checkSelfPermission(MainActivity.this, permission) != PackageManager.PERMISSION_GRANTED) {
        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, permission)) {
            //This is called if user has denied the permission before
            //In this case I am just asking the permission again
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, requestCode);
        }
    } else {
        return 1;
    }
    return 0;
}

@Override
protected void onDestroy() {
    super.onDestroy();
    stopService(serviceIntent);
    if (telephonyManager != null) {
        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
    }

}

}

Вот мой код класса обслуживания:

public class NotificationService extends Service {
Callbacks activity;
MediaPlayer mediaPlayer;
RemoteViews notificationLayout;
NotificationManagerCompat notificationManager;
private final IBinder mBinder = new LocalBinder();
PendingIntent pendingIntent;
String url = "https://www.betezda.com/songs/English/audio/God%20is%20here.mp3"; // your URL here

@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

//returns the instance of the service
public class LocalBinder extends Binder {
    public NotificationService getServiceInstance() {
        return NotificationService.this;
    }
}

//Here Activity register to the service as Callbacks client
public void registerClient(Activity activity) {
    this.activity = (Callbacks) activity;
}

@Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
    if (mediaPlayer == null) {
        mediaPlayer = new MediaPlayer();
        String hello = intent.getExtras().getString("Hello");
        Toast.makeText(getApplicationContext(), hello, Toast.LENGTH_LONG).show();

        mediaPlayer = MediaPlayer.create(this, R.raw.cheshta);
        mediaPlayer.start();

        activity.updateClient(mediaPlayer);

       /* mediaPlayer.prepareAsync();
        mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                mediaPlayer.start();
                activity.updateClient(mediaPlayer);
            }
        });
        mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                return false;
            }
        });*/

        handleNotification(intent);
    } else {
        handleNotification(intent);

    }

    return Service.START_STICKY;
}

private void handleNotification(Intent intent) {
    if (intent.getAction() != null) {
        switch (intent.getAction()) {
            case Constants.ACTION.STARTFOREGROUND_ACTION:
                showNotification();
                break;
            case Constants.ACTION.PLAY_ACTION:
                if (mediaPlayer.isPlaying()) {
                    mediaPlayer.pause();
                    notificationLayout.setImageViewResource(R.id.playnotify, R.drawable.ic_play_arrow_black_24dp);
                    updateNotification();

                } else {
                    mediaPlayer.start();
                    notificationLayout.setImageViewResource(R.id.playnotify, R.drawable.ic_pause_black_24dp);
                    updateNotification();
                }

                break;
            case Constants.ACTION.PREV_ACTION: {
                int pos = mediaPlayer.getCurrentPosition();
                mediaPlayer.seekTo(pos - 2000);
                break;
            }
            case Constants.ACTION.NEXT_ACTION: {
                int pos = mediaPlayer.getCurrentPosition();
                mediaPlayer.seekTo(pos + 2000);
                break;
            }
        }
    }
}

private void showNotification() {
    notificationLayout = new RemoteViews(getPackageName(), R.layout.notification);
    Intent notificationIntent = new Intent(this, MainActivity.class);
    notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    pendingIntent = PendingIntent.getActivity(this, 0,
            notificationIntent, 0);
    Intent playIntent = new Intent(this, NotificationService.class);
    playIntent.setAction(Constants.ACTION.PLAY_ACTION);
    PendingIntent pendingPlayIntent = PendingIntent.getService(this, 0,
            playIntent, 0);
    notificationLayout.setOnClickPendingIntent(R.id.playnotify, pendingPlayIntent);
    Intent rewindIntent = new Intent(this, NotificationService.class);
    rewindIntent.setAction(Constants.ACTION.PREV_ACTION);
    PendingIntent pendingRewindIntent = PendingIntent.getService(this, 0,
            rewindIntent, 0);
    notificationLayout.setOnClickPendingIntent(R.id.rewindnotify, pendingRewindIntent);
    Intent forwardIntent = new Intent(this, NotificationService.class);
    forwardIntent.setAction(Constants.ACTION.NEXT_ACTION);
    PendingIntent pendingForwardIntent = PendingIntent.getService(this, 0,
            forwardIntent, 0);
    notificationLayout.setOnClickPendingIntent(R.id.forwardnotify, pendingForwardIntent);
    updateNotification();
}

@Override
public void onDestroy() {
    super.onDestroy();
    notificationManager.cancel(1);
}

public void updateNotification() {
    Notification customNotification = new NotificationCompat.Builder(this, "notify")
            .setSmallIcon(R.drawable.ic_music_note_black_24dp)
            .setStyle(new NotificationCompat.DecoratedCustomViewStyle())
            .setCustomContentView(notificationLayout)
            .setOngoing(true)
            .setContentIntent(pendingIntent)
            .build();
    notificationManager = NotificationManagerCompat.from(this);
    notificationManager.notify(1, customNotification);
}

public interface Callbacks {
    void updateClient(MediaPlayer mediaPlayer);
}

}

И это показывает ошибку

    java.lang.RuntimeException: Unable to start service NotificationService@870853f with Intent { act=startforeground cmp=newmediaplayer/.NotificationService (has extras) }: java.lang.NullPointerException: Attempt to invoke interface method 'void NotificationService$Callbacks.updateClient(android.media.MediaPlayer)' on a null object reference
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3335)
    at android.app.ActivityThread.-wrap21(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1578)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6123)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
 Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void NotificationService$Callbacks.updateClient(android.media.MediaPlayer)' on a null object reference
    at NotificationService.onStartCommand(NotificationService.java:53)
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3318)
    at android.app.ActivityThread.-wrap21(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1578) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6123) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757) 

Показывает ошибку Activity.updateClient (mediaPlayer); в классе обслуживания. Метод обратного вызова не получает активность.

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Переместите весь код, который у вас есть в onStartCommand(), на registerClient(). Сбой происходит, потому что в onStartCommand() переменная activity равна null, потому что registerClient() еще не был вызван. Просто отложите настройку MediaPlayer, пока клиент фактически не вызовет registerClient().

0 голосов
/ 10 января 2019

Вы должны сделать нулевую проверку в методе NotificationService класса *1001*. как ваш сервис начинается сначала, а затем вы регистрируете свой обратный вызов на ваш сервис поэтому ваш onStartCommand метод запускается при запуске вашего сервиса, там он нашел ваш обратный вызов с именем activity, ноль. добавьте эту строку кода в ваш onStartCommand.

if(activity!=null)
activity.updateClient(mediaplayer);
...