Let me start by saying I've been searching for a long time, found a lot of similar questions (on SO) but I can't find anything to solve this yet:
I have a Service (jobcrawler) that is started by calling startservice().
Within this service, I am starting a long-running thread, which at some point is calling a class (webservice) whose init looks like this:
public webservice(Context context) {
this.context = context;
this.db = new DatabaseHandler(this.context);
this.access_token = db.getAuthKey();
}
After some network calls, the class(webservice) receives data in a method called recieveData().
Inside recieveData I am attempting to bind to the service as follows:
if (!isBound) {
// not bound yet, then bind to the service.
Intent intent = new Intent(this, jobcrawler.class);
bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
}
Now, I'm getting nullpointerexemption on the line where I call bindservice. Note, that I'm not actually attempting to do anything with the service yet. I'm just trying to bind to it.
any help would be appreciated... if I had hair I'd be pulling it out! lol
Here's some additional code that I think is relevant.
myConnection:
private ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,IBinder service) {
Log.e("webservice", "service is connected");
MyLocalBinder binder = (MyLocalBinder) service;
myService = binder.getService();
isBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
Log.e("webservice", "service is disconnected");
isBound = false;
}
};
binder from service called MyLocalBinder:
public class MyLocalBinder extends Binder {
public jobcrawler getService() {
Log.e("Job Crawler", "returning self");
return jobcrawler.this;
}
}
service's onbind method:
private final IBinder myBinder = new MyLocalBinder();
#Override
public IBinder onBind(Intent arg0) {
Log.d("JobCrawler Service", "Service is bound");
return myBinder;
}
oh and this is where I load the class from the thread inside the service, just in case I should be using a different context or something:
private webservice ws= new webservice(getBaseContext());
I know it's a bit late, but I ran upon the same problem and maybe some googlers will be happy :)
So for me the following worked:
Call the bindService method in reference to your context:
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
Related
I have a Service which is already bound by an external App via AIDL.
However, there are some service requests which require to start an Activity.
Since I cannot call startActivityForResult from within a Service I decided to Bind my local Activities to the service as well.
(PseudoCode) looks like this:
class MyService extends Service{
public IBinder onBind(Intent intent){
if (intent.hasExtra("LocalBindingRequest")){
return getLocalBinder();
else {
return getAidlBinder();
}
}
}
class ExternalApp extends Activity{
void someFunc(){
Intent i = new Intent(new ComponentName("com.my.pkg", "com.my.pkg.MyService");
bindService(i, myServiceConnection, Context.BIND_AUTO_CREATE);
}
}
class InternalApp extends Activity{
MyService mService;
void someFunc(){
Intent i = new Intent(new ComponentName("com.my.pkg", "com.my.pkg.MyService")
.putExtra("LocalBindingRequest", true);
bindService(i, myServiceConnection, Context.BIND_AUTO_CREATE);
}
public void onServiceConnected(ComponentName cn, IBinder service){
InternalBinder ib = (LocalBinder)service;
mService = ib.getService();
}
}
Flow is like this:
ExternalApp binds to AidlBinder
ExternalApp calls Function which requires Service to start an Activity
Service starts Activity
Internal Activity tries to Bind
I get an Exception (appearantly without hitting a breakpoint in onBind or onServiceConnected)
java.lan.ClassCastException: AidlService cannot be cast to InternalBinder
Isn't it possible for a Service to return a different Binder?
If not, what can I do, to propagate a Result back to MyService which is already bound?
Ok I should have read the docs stating in onBind(Intent)
Intent: The Intent that was used to bind to this service, as given to
Context.bindService. Note that any extras that were included with the
Intent at that point will not be seen here.
Thats why I was given the Aidl Service. The fix would be:
class InternalApp extends Activity{
MyService mService;
void someFunc(){
Intent i = new Intent(new ComponentName("com.my.pkg", "com.my.pkg.MyService");
i.setAction("LocalBindingRequest");
bindService(i, myServiceConnection, Context.BIND_AUTO_CREATE);
}
public void onServiceConnected(ComponentName cn, IBinder service){
InternalBinder ib = (LocalBinder)service;
mService = ib.getService();
}
}
class MyService extends Service{
public IBinder onBind(Intent intent){
if ("LocalBindingRequest".equals(intent.getAction()){
return getLocalBinder();
else {
return getAidlBinder();
}
}
}
And we can have separate Binders for each binding request
In the Service class:
class AeroBluetoothService extends Service { ...
private final IBinder asBleBinder = new LocalBinder();
public class LocalBinder extends Binder {
AeroBluetoothService getService() {
return AeroBluetoothService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return asBleBinder;
}
In the client Activity:
Intent bindAsBleIntent;
#Override
public void onServiceConnected( ComponentName className, IBinder service ) {
AeroBluetoothService.LocalBinder asBleBinder = (AeroBluetoothService.LocalBinder) service;
asBleServiceRef = asBleBinder.getService();
}
In Client's onCreate():
bindAsBleIntent = new Intent( getApplicationContext(), AeroBluetoothService.class );
bindService( bindAsBleIntent, /*ServiceConnection*/ this, Context.BIND_AUTO_CREATE );
The problem is that when I try to call a Service method from the Client:
asBleServiceRef.scanForAero();
the reference to the Service instance, asBleServiceRef, is null. It is as though the onServiceConnected() callback is not being called (or is passing a null argument).
I copied this code quite carefully from an Android example. I just noticed that the example calls bindService() from its onStart() method, whereas I'm calling from onCreate(). Could that make any difference? What's the problem?
As #avinash correctly saw, the problem was simply neglecting to declare the Service in the Manifest.
I would like to know if I am doing the right thing. I am clearly getting memory leaks, but I can not pin down where - I have submitted a simplified version of where I think the problem lies . . . is there a potential for leak in the following code?
public class MainActivity extends Activity {
filterService mServer;
private void startService() {
Intent mIntent = new Intent(getApplicationContext(), filterService.class);
startService(mIntent);
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
}
private void stopService() {
stopService(new Intent(getApplicationContext(), filterService.class));
unbindService(mConnection);
mConnection = null;
}
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
mServer = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
LocalBinder mLocalBinder = (LocalBinder)service;
mServer = mLocalBinder.getServerInstance();
}
};
public void onDestroy() {
super.onDestroy();
stopService();
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService();
}
}
Any comments would be most valuable - thank you.
Better unbind from your service in 'onStop()', because 'onDestroy()' may not be called.
If you use 'startService()' to make your service do whatever it is supposed to do and return with 'START_STICKY' from the 'onStartCommand()' method of the service, then it will not be destroyed.
See the documentation about bound services (The Basics):
When the last client unbinds from the service, the system destroys the service (unless the service was also started by startService()).
This way, you can keep your service alive even though the activity is stopped/ destroyed. As soon as it is finished, it can call 'stopSelf()'.
Another source for memory leaks could be a Handler used for communication with the bound service, but I can't judge that from your code.
i have a problem with binding a service to an activity in Android. The problem occurs in the activity:
public class ServiceTestActivity extends Activity {
private static final String TAG = "ServiceTestAct";
boolean isBound = false;
TestService mService;
public void onStopButtonClick(View v) {
if (isBound) {
mService.stopPlaying();
}
}
public void onPlayButtonClick(View v) throws IllegalArgumentException, IllegalStateException, IOException, InterruptedException {
if (isBound) {
Log.d(TAG, "onButtonClick");
mService.playPause();
} else {
Log.d(TAG, "unbound else");
Intent intent = new Intent(this, TestService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
isBound = true;
}
};
}
isBound tells if the service (called TestService) is already bound to the activity.
mService is the reference to the service.
Now if i call "onPlayButton(..)" the first time, with the service not beeing bound, bindService(..) is called and isBound switches from false to true. Then if i call "onPlayButton(..)" again, it calls "playPause()" on the service object. To here everything works fine.
But i want "playPause()" to be called right after the service has been bound, so i changed my code to this:
public void onPlayButtonClick(View v) throws IllegalArgumentException, IllegalStateException, IOException, InterruptedException {
if (isBound) {
Log.d(TAG, "onButtonClick");
mService.playPause();
} else {
Log.d(TAG, "unbound else");
Intent intent = new Intent(this, TestService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
mService.playPause();
}
}
From this point on I get a NullPointerException, because mService doesn't have a reference to the bound service, it's still null. I checked that by logging the value of mService at different positions in the code.
Any tips on what I am doing wrong here? I am pretty new to programming (especially binding) services in android, but I still don't see where the major differences between my to versions are.
One solution is to call playPause() in onServiceConnected(). Another solution is to call startService() with a custom intent that will tell the service to play. I think you might want to think about a redesign. I would try to design the service so that you can start and bind to the service when the activity starts and stop the service when the activity stops. If you need a service that will stay active past the lifetime of the activity, extend the Application class and you can start the service in the onCreate() method.
The binding of the service occurs asynchronously, i.e. the service may not be bound if bindService() returns but when onServiceConnected() has completed. Because of that mService is still null and the exception is thrown.
One solution would be to disable the button by default (in XML or onCreate()) and enable the button in onServiceConnected().
I'm implementing service binding into my application. However when i start my activity which binds to the service, the application force closes. Ive pin pointed that its due to the getApplicationContext() ... Heres my code and where it is called and used...
All help is appreciated.
Thanks
private LocalService mBoundService;
private boolean mIsBound;
Context context = getApplicationContext();
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
mBoundService = ((LocalService.LocalBinder)service).getService();
// Tell the user about this for our demo.
Context context = getApplicationContext();
Toast.makeText(context, "serviceconnected",
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
mBoundService = null;
Toast.makeText(context, "serviceDisconnected",
Toast.LENGTH_SHORT).show();
}
};
void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
bindService(new Intent(context,
LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
in order to bind service with activity,instead of using getApplicationContext(), you should use getBaseContext() or this keyword