Binding Service doesn't call onBind and onServiceConnected - java

So I'm building my MusicPlayer and so I create a service to manage everything. I call ContextWrapper.bindService() and this should call onServiceConnected and onBind right? But this isn't the case for me.
Please tell me if I got anything wrong there.
Here is my code:
This is my method to bind a Activity to the service (MusicUtils.java) . In my Activity it looks like this: MusicUtils.bindToService(this, this);
public static final ServiceToken bindToService(final Context context,
final ServiceConnection callback) {
Activity realActivity = ((Activity)context).getParent();
if (realActivity == null) {
realActivity = (Activity)context;
}
final ContextWrapper contextWrapper = new ContextWrapper(realActivity);
contextWrapper.startService(new Intent(contextWrapper, MediaPlayerService.class));
final ServiceBinder binder = new ServiceBinder(callback);
Intent intent = new Intent().setClass(contextWrapper, MediaPlayerService.class);
if (contextWrapper.bindService(intent, binder, Context.BIND_AUTO_CREATE)) {
mConnectionMap.put(contextWrapper, binder);
Log.e("MusicUtils","Bound");
return new ServiceToken(contextWrapper);
}
return null;
}
This is my ServiceBinder:
public static final class ServiceBinder implements ServiceConnection {
private final ServiceConnection mCallback;
public ServiceBinder(final ServiceConnection callback) {
mCallback = callback;
}
#Override
public void onServiceConnected(final ComponentName className, final IBinder service) {
mService = IMusicSlideService.Stub.asInterface(service);
if (mCallback != null) {
mCallback.onServiceConnected(className, service);
}
}
#Override
public void onServiceDisconnected(final ComponentName className) {
if (mCallback != null) {
mCallback.onServiceDisconnected(className);
}
mService = null;
}
}
And this is my onBind(MediaPlayerService.java) :
#Override
public IBinder onBind(Intent intent) {
Log.e("Service", "onBind");
return mBinder;
}
If you need something please tell me!
Thanks!!!

I use code below and all works fine.
Intent intent = new Intent(mContext, Connector.class);
mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
May be your problem is in using ContextWrapper?
Or try to change new Intent().setClass(contextWrapper, MediaPlayerService.class); to new Intent(contextWrapper, MediaPlayerService.class);

Related

Android: How do I implement a service in the foreground or background depending on a condition?

I'm developing an app that is going to require 2 services:
HostService - A foreground service that manages music playback using the Spotify app-remote SDK. It is necessary to run this service in the foreground as I need to detect playState changes and manage playback constantly. However, this service ONLY needs to run if a condition is met, we'll call that condition isHost. This service will be bound to a SessionActivity that displays the music playing and manages playback.
ApiService - A service that continuously polls a separate web API for updates. This must also run in the foreground if the isHost condition is met as the updates may influence the music playback. However, if the user is not a host, this can be a background process that only needs to poll while the user is actively using a particular Activity. I'm not sure if this service should also be bound to the activity or not.
My question is, how should I go about setting up the ApiService differently depending on this condition? I've started to implement these services below but I'm not entirely sure what I have done makes sense. Additionally, am I doing the right thing by using an event handler the way I am? I don't fully understand Intents and I'm not sure if I should be using broadcast messages and such instead.
SessionActivity.java
class SessionActivity extends AppCompatActivity implements HostEventHandler, ApiEventHandler {
private boolean isHost;
private String data;
private String UID;
private ApiService api;
private HostService host;
private boolean hostBound;
private boolean apiBound;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_session);
isHost = getIntent().getBooleanExtra("isHost", false);
data = getIntent().getStringExtra("data");
UID = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
}
private ServiceConnection hostConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(Constants.TAG, "Bound to HostService");
HostService.LocalBinder binder = (HostService.LocalBinder) service;
host = (HostService) binder.getService()
host.registerEventHandler(this);
hostBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.e(Constants.TAG, "onServiceDisconnected");
hostService = null;
}
};
private ServiceConnection apiConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(Constants.TAG, "Bound to ApiService");
HostService.LocalBinder binder = (ApiService.LocalBinder) service;
api = (ApiService) binder.getService()
api.registerEventHandler(this);
apiBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.e(Constants.TAG, "onServiceDisconnected");
apiService = null;
}
};
protected void onStart() {
super.onStart();
Log.d(Constants.TAG, "Binding to services...");
Intent intent = new Intent(this, ApiService.class);
intent.putExtra("data", data);
intent.putExtra("user", Constants.UID);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
if (isHost) {
Intent intent = new Intent(this, HostService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
{
}
#Override
protected void onStop() {
super.onStop();
unbindService(apiConnection);
apiBound = false;
if (isHost) {
unbindService(hostService);
hostBound = false;
}
}
// HostEventHandler and ApiEventHandler methods...
}
HostService.java
public class HostService extends Service {
private final IBinder binder = new LocalBinder();
private HostEventHandler handler;
public class LocalBinder extends Binder {
HostService getService() {
return HostService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
Log.d(Constants.TAG, "onBind");
return binder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotificationChannel();
Intent notificationIntent = new Intent(this, SessionActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText("Foreground service is running...")
.setSmallIcon(R.drawable.logo)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
connect(); // This connects to spotify
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
disconnect();
}
public registerEventHandler(HostEventHandler handler) {
this.handler = handler;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
ApiService.java
public class ApiService extends Service {
private final IBinder binder = new LocalBinder();
private ApiEventHandler handler;
private final Timer timer;
private boolean connected = false;
private String data;
private String UID;
private ApiState state;
public class LocalBinder extends Binder {
HostService getService() {
return ApiService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
Log.d(Constants.TAG, "onBind");
return binder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!connected) {
data = intent.getStringExtra("data");
UID = intent.getStringExtra("user");
connect();
}
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
disconnect();
}
public void registerEventHandler(ApiEventHandler handler) {
this.handler = handler;
}
public ApiState getState() {
return state;
}
private void connect() {
if (connected) return;
class Updater extends TimerTask {
#Override
public void run() {
state = fetchUpdatedState(); // This will implement the web request
handler.onStateUpdate(state);
Log.d(Constants.TAG, "Polling API...");
timer.schedule(new Updater(), Constants.REFRESH_DELAY);
}
}
timer.schedule(new Updater(), Constants.REFRESH_DELAY);
connected = true;
}
}

How to show the Bluetooth Le Device connected/Disconnected status constantly

I am trying to develop an application where the user can know the status of his/her Bluetooth Le device once he/she launches the app and the connection status is updated in text view in Home Fragment.I have tried to implement it by sending Broadcast from Ble service and catching it in onResume of Home fragment and subsequently updating it in status text view. The status does gets updated but if I change the fragment and come back to the home fragment the text view to show the status gets blank although the Bluetooth Le device is connected.How can I resolve this problem so that the status shows connected all through out if the device is connected and disconnected if it is disconnected?
Any Kind of guidance will be highly appreciated.
here are the code segments I have used to implement the above
In Bleservice.java
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
In HomeFragment.java
public class HomeFragment extends Fragment
{
private BroadcastReceiver mReceiver;
#Override
protected void onResume() {
super.onResume();
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (Bleservice.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
updateConnectionState(R.string.connected);
} else if (Bleservice.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
}
}
};
getActivity().registerReceiver(mReceiver,makeGattUpdateIntentFilter());
}
private void updateConnectionState(final int resourceId) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
tv_connected_disconnected.setText(resourceId);
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
getActivity().unregisterReceiver(mReceiver);
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Bleservice.ACTION_GATT_CONNECTED);
intentFilter.addAction(Bleservice.ACTION_GATT_DISCONNECTED);
return intentFilter;
}
Connect to your BleService by bindService. Check out example with Activity and Service.
private BleService mBluetoothLeService;
private boolean isConnected;
#Override
protected void onStart() {
super.onStart();
Intent bindIntent = new Intent(this, BleService.class);
startService(bindIntent);
bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
registerServiceReceiver(); //register here your mGattCallback that get actions from BleService
}
#Override
protected void onStop() {
super.onStop();
unbindService(mServiceConnection);
mBluetoothLeService = null;
LocalBroadcastManager.getInstance(this).unregisterReceiver(mGattUpdateReceiver);
}
In method bindService you need to pass a ServiceConnection that manage Service Lifecycle.
// Code to manage Service lifecycle.
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BleService.LocalBinder) service).getService();
isConnected = (mBluetoothLeService.getConnectionState() != BleService.STATE_CONNECTED)
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
In Service you need to declare Binder.
private final IBinder mBinder = new LocalBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalBinder extends Binder {
public BleService getService() {
return BleService.this;
}
}
public int getConnectionState() {
return mConnectionState;
}
So now, after binding to BleService, you can get a connection state.

is it possible to communicate with a Service by calling it's methods?

as mentioned here and as all developers do, there are several ways for an Activity to communicate with a Service. the most popular ways are using Intent data and binding. is it possible to communicate with a service simply by calling it's methods ? if it is possible, is it a good way?
Yes, you just have to return service instance from the binder. Take a look at this article for an example of how to do this.
Extracted from the article linked above (look for the line: int num = mService.getRandomNumber();).
LocalService.java
public class LocalService extends Service {
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
LocalService getService() {
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public int getRandomNumber() {
return 5;
}
}
BindingActivity.java
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
/** 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;
// Call the method from service
int num = mService.getRandomNumber();
}
};
}

Android: Service won't bind

Im trying to create bound service. As a test I created service which plays music:
public class MusicService extends Service {
private final IBinder myBinder = new LocalBinder();
MediaPlayer player;
#Override
public IBinder onBind(Intent arg0) {
return myBinder;
}
#Override
public void onCreate() {
super.onCreate();
player = MediaPlayer.create(this,R.raw.teardrop);
player.setLooping(true); // Set looping
player.setVolume(100,100);
player.start();
}
#Override
public void onDestroy() {
player.stop();
player.release();
}
public class LocalBinder extends Binder {
public MusicService getService() {
return MusicService.this;
}
}
}
And when I bind it from Activity nothing happens:
public class MainActivity extends TabSwipeActivity {
boolean isBound = false;
MusicService myService;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Some code
Intent intent = new Intent(this, MusicService.class);
bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
if(isBound){
Toast.makeText(this, "success", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "bind failed", Toast.LENGTH_SHORT).show();
}
}
private ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,IBinder service) {
LocalBinder binder = (LocalBinder) service;
myService = binder.getService();
isBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
}
Service is registred in manifest:
<service android:name=".MusicService" />
Bind failed appears and nothing happens
EDIT: bindService() returns false
EDIT2: when I add complete name in manifest eg. com.mypackage.mypackage2.MusicService
bind Service() returned true. But onServiceConnected() is never called.
Next question is: When I create service which implements LocationListener, what should I use to send message to activity everytime when onLocationChanged()?
I already know the solution. I extends TabActivity made by actionBarSherlock instead of Activity. This is known issue:
getApplicationContext().bindService();
fix that.

communicate to service from activity

I'm trying to communicate with a service. I found this Android Guide.
I did like in the first example but i have an error:
"java.lang.RuntimeException: Unable to bind to service
com.example.internetcall.MyService#41763970 with Intent {
cmp=com.example.internetcall/.MyService }:
java.lang.NullPointerException: println needs a message".
This is the Activity:
public class StartService extends Activity{
String telephoneNumber;
TextView statusTextView, numberTextView;
MyService myService;
Boolean myBound;
ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
Log.i("bnf","qui");
LocalBinder binder = (LocalBinder) arg1;
myService = binder.getService();
myBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
myBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.start_service_layout);
statusTextView = (TextView) this.findViewById(R.id.statusTextView);
numberTextView = (TextView) this.findViewById(R.id.numberTextView);
Intent i = this.getIntent();
telephoneNumber = i.getStringExtra("number");
numberTextView.setText(telephoneNumber);
if(isMyServiceRunning()){
statusTextView.setText("Online");
statusTextView.setTextColor(Color.GREEN);
}else{
statusTextView.setText("Offline");
statusTextView.setTextColor(Color.RED);
}
Intent intent = new Intent(this, MyService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
//SupportClass.myService.setNumber(telephoneNumber);
}
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if ("com.example.internetcall.MyService".equals(service.service.getClassName().toString())) {
return true;
}
}
return false;
}
}
and this is MyService:
public class MyService extends Service{
MyWebSocket mws;
private final IBinder mBinder = new LocalBinder();
Boolean onCall;
String telephoneNumber;
String myTelephoneNumber = null;
#Override
public IBinder onBind(Intent arg0) {
Log.i("bnf",arg0.getStringExtra("number"));
return mBinder;
}
public class LocalBinder extends Binder {
MyService getService() {
Log.i("bnf","localbinder");
// Return this instance of LocalService so clients can call public methods
return MyService.this;
}
}
Does someone know a solution for this problem?
if i did some grammar error i sorry but i don't know english very well.
Your exception occurs at Log.i("bnf",arg0.getStringExtra("number")); arg0.getStringExtra("number") is null. You did not pass the string "number" in your intent to bind the service.

Categories