Can't Access My Service Methods - android

i'm at my wits end, following the examples on the android devguide to creating a bound service here: http://developer.android.com/guide/topics/fundamentals/bound-services.html
i created a bound service to play media files however, every time i try to access any of it's public methods from my activity, i get the force close error with a NullPointerException on logcat.
MediaService.java
public class MediaService extends Service {
private MediaPlayer mediaPlayer;
private SeekBar seeker;
private Boolean curRdy;
private Boolean paused;
private Cursor cursor;
private int columIndex;
private int position;
public class LocalBinder extends Binder {
MediaService getService() {
return MediaService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
mediaPlayer = new MediaPlayer();
curRdy = false;
paused = false;
}
#Override
public IBinder onBind(Intent intent) {
return (IBinder) new LocalBinder();
}
PlayerTab.java
public class PlayerTab extends Activity {
private Intent intent;
private SeekBar seeker;
private MediaService serv;
private ServiceConnection servCon = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
serv = ((MediaService.LocalBinder) service).getService();
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
//-----
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.player);
intent = new Intent(PlayerTab.this, MediaService.class);
seeker = (SeekBar) findViewById(R.id.seeker);
}
#Override
protected void onStart() {
super.onStart();
startService(intent);
bindService(intent, servCon, Context.BIND_AUTO_CREATE);
serv.loadPlayerSeeker(seeker);
}
serv.loadPlayerSeeker() is one of the public methods in MediaService, when ever i try to access it or any of the other methods, it just fails. the service will create and start just fine, it just doesn't seem bounded to the PayerTab activity properly.

You can't call serv.loadPlayerSeeker(seeker); until AFTER public void onServiceConnected(ComponentName className, IBinder service) { is invoked.

Related

Bind Service and listen for variable changes in the service in main activity

I am trying to test out a simple service using Android's accelerometer but I'm not sure where to go from here. What I want it to do is to detect movement using the service and for the main activity to detect every time there is a change in the boolean variable 'moving' that is in the service.
Not shown here is my manifest in which I already put in the code for the service.
Here is my main activity.
public class MainActivity extends AppCompatActivity {
private boolean mBound = false;
private accelService mService = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, accelService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
accelService.LocalBinder binder = (accelService.LocalBinder) service;
mService = binder.getService();
showMessage("Service Bound");
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
private void showMessage(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
Here is my Service.
public class accelService extends Service implements SensorEventListener {
private boolean moving = false;
private final IBinder mBinder = new LocalBinder();
private SensorManager sensorManager;
public int onStartCommand(Intent intent, int flags, int startId) {
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION),
SensorManager.SENSOR_DELAY_NORMAL);
return START_STICKY;
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
public void onSensorChanged(SensorEvent event) {
setMoving(true);
}
public boolean isMoving() {
return moving;
}
public void setMoving(boolean moving) {
this.moving = moving;
}
class LocalBinder extends Binder {
accelService getService() {
return accelService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
You already have a "getService()" that the MainActivity can call, right? Ok.
You have to create a new Interface in the Service class that acts as a Callback:
class accelService extends Service {
interface myCallback {
void onCalled(int parameter);
}
}
Then in your "LocalBinder" you add a new method and a variable:
class LocalBinder extends Binder {
private myCallback mListener = null;
accelService getService() {....} //<!-- the one you already have
void addListener(myCallback listener) { //<!-- the new one that sets the listener/callback
myCallback = listener;
}
}
At this point from your MainActivity you can call:
binder.addListener(new myCallback(){
Toast.makeText(context, "Test", Toast.LONG).show()
});
as you do with "getService()".
Finally you have to call
mBinder.onCalled(123456789)
somewhere in the Service to execute Toast...show() procedure.
In this way you can pass variables from Service to MainActivity while this last one is bounded to the Service.

Resume music using Service when we Resume the application

I'm developing an application, which plays music in the background by using service.
Music stops when we hit back app will be paused and but, music is not resuming when I get back to the application.
public class backService extends Service implements ComponentCallbacks2 {
private MediaPlayer mp;
SharedPreferences sharedpreferences;
public Boolean musicSwitch;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
if (mp != null){
mp.stop();
mp.release();
}
}
#Override
public void onCreate() {
super.onCreate();
sharedpreferences = getSharedPreferences(mypreference,
Context.MODE_PRIVATE);
musicSwitch = sharedpreferences.getBoolean("music", true);
if(musicSwitch){
mp = MediaPlayer.create(this, R.raw.all);
mp.setLooping(true);
mp.start();
}
}
#Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
if(mp != null){
mp.pause();
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I want the application to resume music when we get back to the application, I have tried using onResume method, but there is no onResume method in services.
TIA
1) You need to create foreground service to prevent it from killing by OS
How can we prevent a Service from being killed by OS?
2) You can bind service (bindService(serviceIntent)) and use Binder interface
https://developer.android.com/guide/components/bound-services.html#Binder
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
Activity:
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
unbindService(mConnection);
mBound = false;
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
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;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
}
}
3) Then, in your activity onResume you can call method from your Binder to control music

Service: starting a bound service

I'm kind of confused with bound services. I read Can anybody explain what is difference between unbound and bound service in android this post and based on that I'm trying out a sample. I created a Service and binding it to My activity as shown below
public class MyService extends Service {
private static final String TAG = "MyService";
MyBinder mMyBinder = new MyBinder();
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: ");
// start long running operation
return super.onStartCommand(intent, flags, startId);
}
#Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind: ");
return super.onUnbind(intent);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind: ");
return mMyBinder;
}
public class MyBinder extends Binder {
public MyService getService(){
return MyService.this;
}
}
}
Activity is
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
MyService.MyBinder mMyBinder;
private Connect mConn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MyService.class);
mConn = new Connect();
bindService(intent, mConn, BIND_AUTO_CREATE);
}
public class Connect implements ServiceConnection {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected: ");
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected: ");
}
}
}
The service 'onStartCommand' is not called when I call bindService(intent, mConn, BIND_AUTO_CREATE);
should I call startService after binding? binding will not start the service?
If I already have a service which is started using startService and running , and I'm bindind the same service in some other activity, what happens if activity goes out of scope?

Pass an arraylist of strings from activity to service in Android

I've made a functional android application that implements MediaPlayer and I know it's late now but better now than never, I want to implement a service to be able to play media while multitasking on other applications.
Is there a way how can I pass for example an ArrayList of String from activity to the service ? What I have found were information about Custom Objects that are passed through parcelable which I think is not needed.
For example, how I've started my transition:
public class PlayerService extends Service implements MediaPlayer.OnPreparedListener{
private static final String ACTION_PLAY = "action.PLAY";
private static final String ACTION_PAUSE = "action.PAUSE";
private MediaPlayer mediaPlayer = null;
#Override
public void onCreate() {
mediaPlayer = new MediaPlayer();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(ACTION_PLAY)) {
try {
if(mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.reset();
mediaPlayer.setDataSource(musicUrl.get(position));
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
// setCurrentSong(myDataList.get(position));
// morphButton.setState(MorphButton.MorphState.START);
//
// setHighlight(myDataList.get(currentPosition));
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onPrepared(MediaPlayer mp) {
}
}
As you can see, I need to get from an ArrayList the music URL to prepare de MediaPlayer
In your activity, where you bind to the service you can add an ArrayList<String> via the intent:
ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
Intent i = new Intent(this, BLEDiscoveryService.class);
i.putStringArrayListExtra("list", stringList);
bindService(new Intent(this, MyService.class), serviceConnection, BIND_AUTO_CREATE);
And in your service's onBind() you can retrieve it from the passed intent.
public class LocalBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
#Override
public void onCreate() {
super.onCreate();
binder = new LocalBinder();
}
#Override
public IBinder onBind(Intent intent) {
ArrayList<String> stringList = intent.getStringArrayListExtra("list");
return binder;
}

Android can't bind to service

New to android, trying to figure out Services. I'm trying to bind a service to an activity, I'm following the examples in the documentation, but I keep getting a NullPointerException on the line marked below(appService.playSong(title)). Checking it in the debugger reveals that appService is indeed null.
public class Song extends Activity implements OnClickListener,Runnable {
protected static int currentPosition;
private ProgressBar progress;
private TextView songTitle;
private MPService appService;
private ServiceConnection onService = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder rawBinder) {
appService = ((MPService.LocalBinder)rawBinder).getService();
}
public void onServiceDisconnected(ComponentName classname) {
appService = null;
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song);
Intent bindIntent = new Intent(Song.this,MPService.class);
bindService(bindIntent,onService,
Context.BIND_AUTO_CREATE);
Bundle b = getIntent().getBundleExtra("songdata");
String title = b.getString("song title");
// ...
appService.playSong(title); // nullpointerexception
// ...
}
Here's the relevant part of the service:
package org.example.music;
// imports
public class MPService extends Service {
private MediaPlayer mp;
public static int currentPosition = 0;
public List<String> songs = new ArrayList<String>();
public static String songTitle;
private static final String MEDIA_PATH = new String("/mnt/sdcard/");
#Override
public void onCreate() {
super.onCreate();
mp = new MediaPlayer();
songs = Music.songs;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
public class LocalBinder extends Binder {
MPService getService() {
return MPService.this;
}
}
private final IBinder binder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public void playSong(String songPath) {
try {
mp.reset();
mp.setDataSource(songPath);
mp.prepare();
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer arg0) {
nextSong();
}
});
songTitle = songPath.substring(12,songPath.length()-4);
} catch (IOException e) {
Log.v(getString(R.string.app_name),e.getMessage());
}
}
public void nextSong() {
if (++currentPosition >= songs.size()) {
currentPosition = 0;
}
String song = MEDIA_PATH+songs.get(currentPosition);
playSong(song);
}
public void prevSong() {
if (--currentPosition<0) {
currentPosition=songs.size()-1;
}
String song = Music.MEDIA_PATH+songs.get(currentPosition);
playSong(song);
}
public int getSongPosition() {
return mp.getCurrentPosition();
}
public MediaPlayer getMP() {
return mp;
}
}
I have registered the service in AndroidManifest.xml and set android:enabled="true". Do you see any obvious mistakes here?
There are two kinds of binds you can make local and remote. Local is only for use by your application and remote if for use by any application that implements certain interface.
You should start with local binding.
Local binding tutorial.
Remote binding tutorial.
My solution without bind:
public class MyActivity extends Activity{
#Override
public void onCreate(Bundle savedInstanceState){
...
Intent it = new Intent(MyService.ACTIVITY_START_APP);
it.setClass(getApplicationContext(), MyService.class);
startService(it);
}
...
#Override
protected void onResume() {
super.onResume();
registerBroadcastReceiver();
}
#Override
protected void onPause() {
super.onPause();
this.unregisterReceiver(this.receiver);
}
...
private BroadcastReceiver receiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(MyService.BROADCAST_INIT)) {
//do your stuff here after init
}
}
};
private void registerBroadcastReceiver(){
IntentFilter filter = new IntentFilter();
filter.addAction(HMyService.BROADCAST_INIT);
this.registerReceiver(receiver, filter);
}
}
Your service:
public class MyService extends Service{
public static final String BROADCAST_INITIAL_DATA = "org.myapp.BROADCAST_INIT";
public static final String ACTIVITY_START_APP = "org.myapp.ACTIVITY_START_APP";
#Override
public int onStartCommand (Intent intent, int flags, int startId){
super.onStartCommand(intent, flags, startId);
if(intent.getAction().equals(ACTIVITY_START_APP)){
//do your initialization
//inform the client/GUI
Intent i = new Intent();
i.setAction(BROADCAST_INIT);
sendBroadcast(i);
}else{
//some other stuff like handle buttons
}
}
}
good luck.
You are assuming that the bindService() will connect to the service synchronously, but the connection will be available only after onCreate() finshed.
The framework runs onCreate() on the UI thread and bindService() just makes a note to connect to the service later. Connecting to a service will always be done on the UI thread, so this can only happen after onCreate was executed. You can't even count on the connection being set up right after onCreate(). It will happen sometime after that :). Also, the framework might disconnect the service on it's will, though it should only happen in low memory conditions.
So, move the code which works with appService from onCreate() to onServiceConnected() and it's gonna work.
From a quick glance it looks like you are trying to access your service before the binding has completed. You have to make sure onServiceConnected has fired before trying to call any methods on your service.
Example:
Intent bindIntent = new Intent(Song.this,MPService.class);
bindService(bindIntent,onService, Context.BIND_AUTO_CREATE);
//Wait until service has bound
while(appService == null){
Thread.sleep(100);
}
appService.playSong(title);
This example isn't the best but it demonstrates that you have to wait until the binding has completed before trying to access the service.

Categories

Resources