Access outer class instance in bound service - java

In android bound service, the following snippets access to service instance using Foo.this but in reality if we try to do it in java it can't be possible. So how it works?
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; }
// Other public methods below
public void foo() {} // etc...
}
// The activity class
public class MyActivity extends Activity {
LocalService mService;
boolean mBound = false;
....
.....
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
LocalBinder binder = (LocalService.LocalBinder) service;
/* See, using this we can get the instance of LocalService in android, but using the same approach in java we get the error. */
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
As you can see in MyActivity class, we can get the instance of LocalService class using getService() method (and after than we can access its methods). But if we try to do that in java we get the error.
In short, how binder.getService() call works in android.

Related

Why can't I directly call method in the binder class?

I was reading the documentation for bound services on android and I stumble upon the following code on the documentation:
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);
}
}
and
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();
// Unbind from the service
if (mBound) {
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;
}
};
}
What strikes me as odd was that why is the method getRandomNumber() not be included in the LocalBinder class. This way you can just use the binder to call method to be perform(getRandomNumber()) rather than having to call the LocalBinder to return the service with getService() and then using the service to call the getRandomNumber(). This extra step of returning the service to call getRandomNumber() doesn't make sense to me so can anyone explain to me why this is the case?

Can't cast to service

I have a strange problem , and I do not know how to solve it.
I want get connection from my running service.
I make this inner class with method :
public class PlayMusicServiceBinder extends Binder{
public PlayMusicService getService(){
return PlayMusicService.this;
}
}
Then i start service and create connection with it:
private PlayMusicService pms
startService(playServiceIntent.putExtra("songs", songs).putExtra("currentPosition", currentPosition).putExtra("path", path));
serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
pms = ((PlayMusicService.PlayMusicServiceBinder)service).getService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
pms = null;
}
};
onBind();
onBind() :
public void onBind(){
this.bindService(new Intent(this, PlayMusicService.class),serviceConnection, Context.BIND_AUTO_CREATE);
}
And compiler say on this line pms = ((PlayMusicService.PlayMusicServiceBinder)service).getService();, that :"Unable to cast"
I have seen many examples where such actions were carried out , and no one complained about the bugs
Help me please.
Thanks.
Did you add this code in PlayMusicService class?
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
private final IBinder mBinder = new PlayMusicServiceBinder();

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