I'm having trouble getting the onServiceConnected() method to run, which means that it's not binding my activity to the service.
It's probably something simple that I've missed out - but I've tried quite a few times - starting from scratch.
Here we go...
My Service Class
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class QuickService extends Service {
private final IBinder mBinder = new QuickBinder(this);
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
My Binder Class
import android.os.Binder;
public class QuickBinder extends Binder {
private final QuickService service;
public QuickBinder(QuickService service){
this.service = service;
}
public QuickService getService(){
return service;
}
}
And... The Activity trying to bind to the service.
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
public class QuickActivity extends Activity {
QuickService mService;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_connecting);
}
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, QuickService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
unbindService(mConnection);
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
Logger.d("Connected!!! :D");
// We've bound to LocalService, cast the IBinder and get LocalService instance
QuickBinder binder = (QuickBinder) service;
mService = binder.getService();
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
}
};
}
Also, the Service defined in the manifest file - in case you thought that was the problem.
<service android:name=".QuickService"></service>
So, What am I doing wrong here? Why isn't the onServiceConnected() method being called?
Update it with following
<service android:name=".QuickService">
<intent-filter>
<action android:name=".QuickService .BIND" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
Instead of writing:
Intent intent = new Intent(this, QuickService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
You can write:
startService(new Intent(QuickActivity.this, QuickService.class));
where you want to start service.
Hope this will help you.
Related
I am studying services, and I have written a code to bind a service by clicking on a button, run a method of the service by clicking on another button and unbinding service by clicking on a third button.
If I try to run the method of the service before binding. I get, obviously, an error message, while if I first bind the service the method is normally called.
The question is, If I click on the third button to unbind the service, despite the service native method on Unbind(Intent intent) gives me a positive feedback, I'm still able to call the service method from the main activity like if it should still be bound.
Here is the Service code
package com.antonello.tavolaccio4;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
/**
* Created by Antonello on 14/05/2017.
*/
public class Servizio extends Service{
public IBinder binder=new MyBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public boolean onUnbind(Intent intent){
System.out.println("unbinded");
return false;
}
public class MyBinder extends Binder{
Servizio getService(){
return Servizio.this;
}
}
public void metodo(){
System.out.println("Metodo del service");
}
}
and here is the Main Activity code:
package com.antonello.tavolaccio4;
import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
ServiceConnection serviceConnection;
Servizio servizio;
Button button;
Button button2;
Button button3;
boolean bound;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=(Button)findViewById(R.id.button);
button2=(Button)findViewById(R.id.button2);
button3=(Button)findViewById(R.id.button3);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),Servizio.class);
bindService(intent,serviceConnection, Service.BIND_AUTO_CREATE);
}
});
button2.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
servizio.metodo();
}
});
button3.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),Servizio.class);
unbindService(serviceConnection);
}
});
serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Servizio.MyBinder binder=(Servizio.MyBinder)service;
servizio=binder.getService();
bound=true;
System.out.println(bound);
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
}
Is there anything wrong in my unbindService method?
Thank you for any help.
Is there anything wrong in my unbindService method?
You do not have an unbindService() method. You are calling the one that you are inheriting from Context.
It is your job, as part of calling unbindService(), to also set to null any fields tied to the bound connection (in your case, servizio). As it stands, you are leaking memory, and any inherited methods that your service tries calling may throw exceptions because the service is destroyed.
I am working on a larger project but have become stuck on a very simple element that is binding to an android service. My issue is that I cannot seem to bind to the service. No errors are being thrown at all when calling bindService() and I have used the internal debugger and manual tracing of print statements and I am still failing to understand what is causing this error. Any help appreciated! (This is especially irritating as it is largely C+P from the android development website yet still won't work!)
Main Activity:
package com.example.servicetest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
public class MainActivity extends Activity {
LocalService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// START Activity
Intent intent = new Intent(this, BindingActivity.class);
startActivity(intent);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Binding Activity:
package com.example.servicetest;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Toast;
import com.example.servicetest.LocalService.LocalBinder;
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
/** 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;
System.out.println("End onServiceConnected");
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bind);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
System.out.println("onStart called");
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
this.startService(intent);
}
#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.
System.out.println("Button click");
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
System.out.println("" + num);
} else {
System.out.println("Not bound");
}
}
}
LocalService:
package com.example.servicetest;
import java.util.Random;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
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) {
System.out.println("onBind called");
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
And finally the manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.servicetest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.servicetest.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.servicetest.BindingActivity"
android:label="#string/app_name" >
</activity>
</application>
</manifest>
I think you need to add your service in Mainfest.xml
<service android:name="LocalService" android:enabled="true"></service>
try it and feed me back
After I have bound a service by calling:
bindService(new Intent(IBumpAPI.class.getName()), connection, Context.BIND_AUTO_CREATE);
I need for debugging purposes to make the onServiceDisconnected() get called.
I am aware that the Android system calls this when the connection to the service is unexpectedly lost, such as when the service has crashed or has been killed and that this is not called when the client unbinds.
So my question is how to force the onServiceDisconnected() get called whenever I want so I can complete a test?
You need to start you service then bind with Context.BIND_NOT_FOREGROUND flag and then stop it. This will cause onServiceDisconnected to be called. Here is code (assuming that you have TestService service defined) of MainActivity with two buttons which are linked to call doBind and doUnbind methods:
package com.example.servicetest;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "Service disconnected: " + name);
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "Service connected: " + name);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public void doBind(View v) {
Intent i = new Intent(this, TestService.class);
startService(i);
bindService(i, connection, Context.BIND_NOT_FOREGROUND);
}
public void doUnbind(View v) {
Intent i = new Intent(this, TestService.class);
stopService(i);
}
}
This code provides following logs when you click on buttons:
11-27 09:21:57.326: D/MainActivity(10724): Service connected: ComponentInfo{com.example.servicetest/com.example.servicetest.TestService}
11-27 09:21:58.099: D/MainActivity(10724): Service disconnected: ComponentInfo{com.example.servicetest/com.example.servicetest.TestService}
You might just unbind your service
public void openService {
mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IService.Stub.asInterface(service);
}
#Override
public void onServiceDisconnected(ComponentName cn) {
mService = null;
}
};
bindService(service, mConnection, Context.BIND_AUTO_CREATE);
}
}
public void closeService() {
unbindService(mConnection);
stopService(new Intent(this, Service.class));
}
I'm trying to create a service which will start by the user request in the application.
After the user will choose an update interval, the service will run in the operation system background, and will send a non-relevant message.
I've tried to write the service according to the example for Service class API.
For some reason, I figured in debug (when running doBindService() method) that mUpdateBoundService is getting null.
My second question is whether I can use "Toast" inform message outside an application ? (As kind of a desktop notification).
Can anyone help ? Here is my short code:
UpdateService.java
package android.update;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;
public class UpdateService extends Service {
private NotificationManager mNM;
private final IBinder mBinder = new UpdateBinder();
private int updateInterval;
public class UpdateBinder extends Binder {
UpdateService getService() {
return UpdateService.this;
}
}
public void onCreate() {
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Timer timer = new Timer();
timer.schedule(new UpdateTimeTask(), 100, updateInterval);
}
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
class UpdateTimeTask extends TimerTask {
public void run() {
showNotification();
}
}
public void showNotification() {
Toast.makeText(this, "Hi", 10);
}
#Override
public IBinder onBind(Intent intent) {
updateInterval = intent.getExtras().getInt(getString(R.string.keyUpdateInterval));
return mBinder;
}
}
UpdateActivity.java
package android.update;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class UpdateActivity extends Activity {
private UpdateService mUpdateBoundService;
private boolean mIsBound = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClickStartUpdateService(View view) {
switch (view.getId()) {
case R.id.btnStartUpdateService:
doBindService();
//Toast.makeText(this,"Service Started",Toast.LENGTH_LONG).show();
mUpdateBoundService.showNotification();
break;
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mUpdateBoundService = ((UpdateService.UpdateBinder)service).getService();
}
public void onServiceDisconnected(ComponentName className) {
mUpdateBoundService = null;
}
};
private void doBindService() {
Intent updateActivityIntent = new Intent(UpdateActivity.this,
UpdateService.class);
EditText txtUpdateInterval = (EditText) findViewById(R.id.txtUpdateInterval);
int interval = Integer.parseInt(txtUpdateInterval.getText().toString());
updateActivityIntent.putExtra(getString(R.string.keyUpdateInterval), interval);
bindService(updateActivityIntent, mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
}
Your toast is not showing because you are not telling it to. Try:
public void showNotification() {
Toast.makeText(this, "Hi", 10).show();
}
For your service issue, I think that you do not properly understand how services & activities work together. A service can run independently of a service, or you can have a service whose lifecycle matches that of a given activity. From your code, it is not clear which of these models you are following. Your implementation will cause the service to wake periodically, but only while your activity is running. If the user switches to another activity, your service will no longer be woken.
If you want a service to wake periodically independently of the activity, then you need to run your timer event in the service itself. Better still use an Alarm to wake your service: Register an Alarm with AlarmManager which will fire an Intent at a future point (or regular intervals, if you prefer), and extend your service from IntentService, override onHandleIntent() and add the necessary Intent Filter to your Service entry in the manifest.
Although I followed the tutorial on the Android Developers website, I can't get my activity to bind to my service.
package com.dieselboris.motioncapture;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.dieselboris.motioncapture.LocalService.LocalBinder;
public class HelloMotionCaptureActivity extends Activity implements OnClickListener {
private TextView textBox;
LocalService mService;
boolean mBound = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textBox = (TextView) findViewById(R.id.textView1);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService NEVER RETURNS TRUE!!!!
Intent intent = new Intent(this, LocalService.class);
boolean isBound = bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
String text = Boolean.toString(isBound);
textBox.setText(text);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
//start the service when clicked
public void onClick(View v) {
if (v == startButton)
{
//NEVER IN HERE
if (mBound) {
int num = mService.getRandomNumber();
Toast.makeText(this, "incoming number: " + num, Toast.LENGTH_LONG).show();
}
Toast.makeText(this, "the service should run now", Toast.LENGTH_LONG).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;
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();
String text = Integer.toString(num);
textBox.setText(text);
}
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
The Service I try to connect to:
package com.dieselboris.motioncapture;
import java.util.Random;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
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);
}
}
I get the following output from the emulator:
ERROR/AndroidRuntime(10878): FATAL EXCEPTION: main
ERROR/AndroidRuntime(10878): java.lang.NullPointerException
ERROR/AndroidRuntime(10878): at com.dieselboris.motioncapture.HelloMotionCaptureActivity.onClick(HelloMotionCaptureActivity.java:66)
ERROR/AndroidRuntime(10878): at android.view.View.performClick(View.java:2408)
ERROR/AndroidRuntime(10878): at android.view.View$PerformClick.run(View.java:8817)
ERROR/AndroidRuntime(10878): at android.os.Handler.handleCallback(Handler.java:587)
ERROR/AndroidRuntime(10878): at android.os.Handler.dispatchMessage(Handler.java:92)
ERROR/AndroidRuntime(10878): at android.os.Looper.loop(Looper.java:144)
ERROR/AndroidRuntime(10878): at android.app.ActivityThread.main(ActivityThread.java:4937)
ERROR/AndroidRuntime(10878): at java.lang.reflect.Method.invokeNative(Native Method)
ERROR/AndroidRuntime(10878): at java.lang.reflect.Method.invoke(Method.java:521)
ERROR/AndroidRuntime(10878): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
ERROR/AndroidRuntime(10878): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
ERROR/AndroidRuntime(10878): at dalvik.system.NativeStart.main(Native Method)
It seems that I call the public method from the service before it's initialized or the connection is not yet setup.
I followed the example on the developers site carefully and can't figure out what I am doing wrong.
My permissions weren't set correctly.
I had to insert a permission for the whole application and a "uses-permission" in application manifest.
Without permissions the intent is never delivered to the service.