i have a problem with bindService. In my Activity i have the following code:
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
mService = IPrimary.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName className) {
mService = null;
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.login);
mApi = new ApiRequest(SIGNIN_METHOD);
boolean isConnected = bindService(new Intent(IPrimary.class.getName()),
mConnection, Context.BIND_AUTO_CREATE);
But isConnected is equals to false every time.
In my manifest file i have:
<service android:name=".DownloaderService">
<intent-filter>
<action android:name=".IPrimary" />
si i don't understand the problem. In logcat appears:
I/ActivityManager( 52): Displayed activity com.touristeye.code/.LogIn: 485918 ms (total 913151 ms)
Thank you
Expand that action:name to be the full value in the <action> element. It may be that the dot-prefix shorthand only works for the component element (e.g., <service>).
You shouldn't do that:
boolean isConnected = bindService(new Intent(IPrimary.class.getName()), mConnection, Context.BIND_AUTO_CREATE);
Please put the code when you handle service in private ServiceConnection mConnection = new ServiceConnection() {} ... I calls back and you have the service to handle there
We're not sure when the service is actually bond until we got callback from ServiceConnection
Here is the flow
Create your intent to call a service. You can either startService() or BindService() with BIND_AUTO_CREATE
Once the service is bond, it will create a tunnel to talk with it clients which is the IBinder
Interface. This is used by your AIDL Interface implementation and return the IBinder in
private final MyServiceInterface.Stub mBinder = new MyServiceInterface.Stub() {
public int getNumber() {
return new Random().nextInt(100);
}
};
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(this, "Service OnBind()", Toast.LENGTH_LONG).show();
return mBinder;
}
Once it returns the mBinder, ServiceConnection that you created in the client will be called back and you will get the service interface by using this
mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mService = MyServiceInterface.Stub.asInterface(service);
};
Now you got the mService interface to call and retreive any service from that
Related
I'm stuck in a problem with a service binding that is giving me nuts.
I got an activity that is binding a service, and is frequent that the user go in and out of that activity.
The problem comes when the user goes out first time of the activity this one unBinds the service and when is going in again, do not binds again.
The activity calls the binding service this way:
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, CService.class);
intent.putExtra("id_local", (String) getIntent().getExtras().get("id_local"));
intent.putExtra("id_send", (String) getIntent().getExtras().get("id_send"));
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
registerReceiver(uiUpdated, new IntentFilter("SERVER_MESAGE"));
mBound = true;
}
Where the mConnection is defined that way:
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
CService.LocalBinder binder =(CService.LocalBinder) service;
mService = binder.getService();
Log.d("Service", "onServiceConnected");
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.d("Service", "onServiceDisconnected");
mBound = false;
}
};
And in the onStop I unbindService:
#Override
protected void onStop() {
if (mBound) {
Log.d("ActivityStop", "Stoping activity");
unregisterReceiver(uiUpdated);
unbindService(mConnection);
mBound = false;
}
super.onStop();
}
The onBind in the service is that one:
#Override
public IBinder onBind(Intent intent) {
final String id_local = intent.getStringExtra("id_local");
final String id_send = intent.getStringExtra("id_send");
if (!misatgesList.isEmpty()) {
misatgesList.clear();
}
mBackGroundTimer.schedule(new TimerTask() {
#Override
public void run() {
String serverResult = restRecive(id_local, id_send,
misatgesList.size());
if (serverResult != null) {
misatgesList.addAll(procesMisatges(serverResult,
id_local));
Intent i = new Intent("SERVER_MESAGE");
i.putExtra("recive", serverResult);
sendBroadcast(i);
}
}
}, 0, 1000);
return mBinder;
}
And the onUnBind is that one:
#Override
public boolean onUnbind(Intent intent) {
mBackGroundTimer.cancel();
misatgesList.clear();
Log.d("ServiceOnUnBind", "ServiceOnUnBind");
//stopSelf();
return super.onUnbind(intent);
}
So my question would be, how I can bind again the service when the activity goes in again? Or what should I do to keep the binding alive until the user goes in the activity?
I found the solution!
What I meant was how to call again the onBind. That is done using the onRebind, that alows you to call again the onBind.
So, I created the onRebind:
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
Also, for the onRebind to work, you have to turn the return in the onUnbind to true.
#Override
public boolean onUnbind(Intent intent) {
mBackGroundTimer.cancel();
misatgesList.clear();
Log.d("ServiceOnUnBind", "ServiceOnUnBind");
//return super.onUnbind(intent);
return true;
}
For more explanation, check there: Bound Services
Use getApplicationContext() API when binding to your service from Activity as below:
getApplicationContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
getApplicationContext returns the global application context - the difference from other contexts is that for example, an activity context may be destroyed (or otherwise made unavailable) by Android when your activity ends. The Application context remains available all the while your Application object exists (which is not tied to a specific Activity)
Code:
#Override
public void onResume() {
super.onResume();
Intent intent = new Intent(getActivity(), UserAPIService.class);
getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
mService.fetchUserInfo();
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
UserAPIService.LocalBinder binder = (UserAPIService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
The user info is attempted to be fetched, but the service is null because it hasn't been bound yet. What is the best way to go about this? I could make the API call in the onServiceConnected method, but there has to be a better way.
You can call the
mService.fetchUserInfo();
inside the method
onServiceConnected(ComponentName className,IBinder service)
You cannot get the service instance unless your service is bound and it may require some time . onStart() is better place to bind a service.
I am struggling with the ServiceConnection for inapt purchases. Neither methods on ServiceConnected or onServiceDisconnected get called.
Logcat is empty!
What am I doing wrong?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.inapp);
mServiceConn = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
showtouser("Disconnection from server");
}
#Override
public void onServiceConnected(ComponentName name,
IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
bindService(new
Intent("com.android.vending.billing.InAppBillingService.BIND"),
mServiceConn, Context.BIND_AUTO_CREATE);
showtouser("");
}
};
Ofc it does nothing, because callback method onServiceConnected() is called after successful bind. Now you are calling bindService() after it has been bounded. This code has no action. Call it e.g. after setContentView(). Check docs http://developer.android.com/guide/components/bound-services.html
can you give me a simple example of an application with background service which uses bind/unbind methods to start and stop it? I was googling for it for a half-hour, but those examples use startService/stopService methods or are very difficult for me. thank you.
You can try using this code:
protected ServiceConnection mServerConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.d(LOG_TAG, "onServiceConnected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d(LOG_TAG, "onServiceDisconnected");
}
}
public void start() {
// mContext is defined upper in code, I think it is not necessary to explain what is it
mContext.bindService(intent, mServerConn, Context.BIND_AUTO_CREATE);
mContext.startService(intent);
}
public void stop() {
mContext.stopService(new Intent(mContext, ServiceRemote.class));
mContext.unbindService(mServerConn);
}
Add these methods to your Activity:
private MyService myServiceBinder;
public ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
myServiceBinder = ((MyService.MyBinder) binder).getService();
Log.d("ServiceConnection","connected");
showServiceData();
}
public void onServiceDisconnected(ComponentName className) {
Log.d("ServiceConnection","disconnected");
myService = null;
}
};
public Handler myHandler = new Handler() {
public void handleMessage(Message message) {
Bundle data = message.getData();
}
};
public void doBindService() {
Intent intent = null;
intent = new Intent(this, BTService.class);
// Create a new Messenger for the communication back
// From the Service to the Activity
Messenger messenger = new Messenger(myHandler);
intent.putExtra("MESSENGER", messenger);
bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
}
And you can bind to service by ovverriding onResume(), and onPause() at your Activity class.
#Override
protected void onResume() {
Log.d("activity", "onResume");
if (myService == null) {
doBindService();
}
super.onResume();
}
#Override
protected void onPause() {
//FIXME put back
Log.d("activity", "onPause");
if (myService != null) {
unbindService(myConnection);
myService = null;
}
super.onPause();
}
Note, that when binding to a service only the onCreate() method is called in the service class.
In your Service class you need to define the myBinder method:
private final IBinder mBinder = new MyBinder();
private Messenger outMessenger;
#Override
public IBinder onBind(Intent arg0) {
Bundle extras = arg0.getExtras();
Log.d("service","onBind");
// Get messager from the Activity
if (extras != null) {
Log.d("service","onBind with extra");
outMessenger = (Messenger) extras.get("MESSENGER");
}
return mBinder;
}
public class MyBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
After you defined these methods you can reach the methods of your service at your Activity:
private void showServiceData() {
myServiceBinder.myMethod();
}
and finally you can start your service when some event occurs like _BOOT_COMPLETED_
public class MyReciever extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.intent.action.BOOT_COMPLETED")) {
Intent service = new Intent(context, myService.class);
context.startService(service);
}
}
}
note that when starting a service the onCreate() and onStartCommand() is called in service class
and you can stop your service when another event occurs by stopService()
note that your event listener should be registerd in your Android manifest file:
<receiver android:name="MyReciever" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
First of all, two things that we need to understand,
Client
It makes request to a specific server
bindService(new Intent("com.android.vending.billing.InAppBillingService.BIND"),
mServiceConn, Context.BIND_AUTO_CREATE);
here mServiceConn is instance of ServiceConnection class(inbuilt) it is actually interface
that we need to implement with two (1st for network connected and 2nd network not connected) method to monitor network connection state.
Server
It handles the request of the client and makes replica of its own which is private to client only who send request and this raplica of server runs on different thread.
Now at client side, how to access all the methods of server?
Server sends response with IBinder Object. So, IBinder object is our handler which accesses all the methods of Service by using (.) operator.
.
MyService myService;
public ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
Log.d("ServiceConnection","connected");
myService = binder;
}
//binder comes from server to communicate with method's of
public void onServiceDisconnected(ComponentName className) {
Log.d("ServiceConnection","disconnected");
myService = null;
}
}
Now how to call method which lies in service
myservice.serviceMethod();
Here myService is object and serviceMethod is method in service.
and by this way communication is established between client and server.
I have a service running in my Android application which contains a HashMap that I would like to use in an Activity. So I bound the service to my activity and created a link between to two in order to use the data structure.
This is how I did it so far:
Activity (relevant code):
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
imService = ((IMService.IMBinder) service).getService();
}
public void onServiceDisconnected(ComponentName className) {
imService = null;
Toast.makeText(ViewFlipperTest.this,
R.string.local_service_stopped, Toast.LENGTH_SHORT).show();
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindService(new Intent(ViewFlipperTest.this, IMService.class),
mConnection, Context.BIND_AUTO_CREATE);
.
.
.
}
protected void onResume() {
super.onResume();
bindService(new Intent(ViewFlipperTest.this, IMService.class),
mConnection, Context.BIND_AUTO_CREATE);
}
private void getMap(ViewFlipper flipper2) {
Map<Integer, internalChatObj> tempMap = imService.getMapwData();
}
Service (relevant code):
public class IMService extends Service implements IAppManager{
.
.
.
public Map getMapwData(){
if(getNumberOpenChats()>0){
return openChatMapwData;
}
else
return null;
}
}
Each time I try and run the method getMap(), I get a null pointer. I even put a check to see if the imService was null and it was null each time. It seems that it is trying to obtain the data from the Service but the binding to the service is null, is that right? I have a check in the Service to send null if the map is empty, so that shouldn't be a problem.
Any help?
Edit based on Will's tips
New code
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
imService = ((IMService.IMBinder) service).getService();
dialog.dismiss();
}
public void onServiceDisconnected(ComponentName className) {
imService = null;
Toast.makeText(ViewFlipperTest.this,
R.string.local_service_stopped, Toast.LENGTH_SHORT).show();
}
};
public void onCreate(Bundle savedInstanceState) {
dialog = ProgressDialog.show(getApplicationContext(), null,"Loading..", true, false);
}
Edit II
IMBinder Class (Seems standard, no?)
public class IMBinder extends Binder {
public IAppManager getService() {
return IMService.this;
}
}
Is it necessary to have IMService.this instead of this?
It really seems like a timing issue; you shouldn't call the getMap function unless you are certain the imService variable exists, which is after a call to onServiceConnected.