getApplicationContext() ... forcing close? - android

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

Related

How to test the process that a client of an Android bound service bind to the service?

I have an service App that defined a bound service, and another client App that one of its activity binds to the bound service. How can I write test case to test the bind service process?
The code of the client App binding to the service is similar to what the Android official doc has:
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();
intent.setComponent(new ComponentName(SERVICE_APP_PACKAGE_NAME,
SERVICE_NAME));
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
unbindService(connection);
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 connection = 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;
}
};
}
What kind of test case can test the setIntent() & bindService() or unbindService() method in the activity's onStart() and onStop() method?
You don't want to test onBind. You know that works, that's tested as part of the Google framework. What you want to test is two things:
1)That your ServiceConnection functions properly set mBound and mService.
2)That your onStart calls onBind to bind it.
The best way to do this is actually a refactor. This code isn't as testable as it could be. Bring mService and mBound into the ServiceConnection class, and make it a full class (rather than an anonymous class). Then you can easily test (1) using mocks for the input. To test (2) I would actually subclass the Activity, override bindService to just set a variable to true, and ensure after calling onStart the variable was set to true.

Memory leak - Service + thread

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.

Doubts about bindService

I have some boubts about Android bound service. The guide: http://developer.android.com/guide/components/bound-services.html
,about bindService(), says:
The `bindService()` method returns immediately without a value
But this does not seems to be correct, since here the signature of the method is
public abstract boolean bindService (Intent service, ServiceConnection conn, int flags)
where the returned boolean value is described as below:
If you have successfully bound to the service, true is returned; false is returned if the connection is not made so you will not receive the service object.
So the question is: why the documentation says that the method returns immediately without a value? Moreover, here, the bind is done in this way:
void doBindService() {
bindService(new Intent(Binding.this,
LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
and I don't understand the sense of mIsBound = true, since the javadoc says that bindService() can also return false, if the bounding to service fail. So it should be:
void doBindService() {
mIsBound = bindService(new Intent(Binding.this,
LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
}
Am I wrong?
The documentation is incorrect. When returned boolean is false this means that no further attempts to establish connection are made. When true is returned this means that system tries to establish a connection and this can succeed or fail.
Look at answer for this question: "in what case does bindservice return false".
Basically bindservice returns false when it does not find a service to even attempt to bind to.
Ok, i finally completed learning all the nuances of binding services in android, and that is the ServiceBindHelper class, that can be treated as "ultimate truth" (excuse my immodesty).
https://gist.github.com/attacco/987c55556a2275f62a16
Usage example:
class MyActivity extends Activity {
private ServiceBindHelper<MyService> myServiceHelper;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myServiceHelper = new ServiceBindHelper<MyService>(this) {
#Override
protected Intent createBindIntent() {
return new Intent(MyActivity.this, MyService.class);
}
#Override
protected MyService onServiceConnected(ComponentName name, IBinder service) {
// assume, that MyService is just a simple local service
return (MyService) service;
}
};
myServiceHelper.bind();
}
protected void onDestroy() {
super.onDestroy();
myServiceHelper.unbind();
}
protected void onStart() {
super.onStart();
if (myServiceHelper.getService() != null) {
myServiceHelper.getService().doSmth();
}
}
}

bindService() gives NullPointerException and onServiceConnected() never called

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)

Binding a service before calling a method on it

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().

Categories

Resources