I finally got the Local Service Sample to work using the LocalServiceActivities.java and the Basics of Android : Part III – Android Services.
Here's my code Controller.java, LocalService.java, Binding.java, and ILocalService.java all baked together one after another separated by comment headers:
/**************************************************************************************************
* Filename: Controller.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains the primary activity for this application
**************************************************************************************************/
package com.marie.localservicesample;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/*
* Example of explicitly starting and stopping the local service.
* This demonstrates the implementation of a service that runs in the same
* process as the rest of the application, which is explicitly started and stopped
* as desired.
*/
//public static class Controller extends Activity {
public class Controller extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.local_service_controller);
// Watch for button clicks.
Button button = (Button)findViewById(R.id.start);
button.setOnClickListener(mStartListener);
button = (Button)findViewById(R.id.stop);
button.setOnClickListener(mStopListener);
}
private OnClickListener mStartListener = new OnClickListener() {
public void onClick(View v) {
// Make sure the service is started. It will continue running
// until someone calls stopService(). The Intent we use to find
// the service explicitly specifies our service component, because
// we want it running in our own process and don't want other
// applications to replace it.
//startService(new Intent(Controller.this, LocalService.class));
Intent startSvc = new Intent(Controller.this, LocalService.class);
startSvc.putExtra(LocalService.EXTRA_MESSENGER, new Messenger(handler));
startSvc.putExtra(LocalService.EXTRA_SONG, 7);
startService(startSvc);
Intent binding = new Intent(Controller.this, Binding.class);
startActivity(binding);
}
};
private OnClickListener mStopListener = new OnClickListener() {
public void onClick(View v) {
// Cancel a previous call to startService(). Note that the
// service will not actually stop at this point if there are
// still bound clients.
stopService(new Intent(Controller.this,
LocalService.class));
}
};
/*
* This is a handler to be passed to the Service via a Messenger.
*/
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// simple handler test
String obj = (String) msg.obj;
Log.i("handleMessge", "obj: " + obj);
}
};
}
/**************************************************************************************************
* Filename: LocalService.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains a local service
**************************************************************************************************/
package com.marie.localservicesample;
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.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
public class LocalService extends Service {
private NotificationManager mNM;
// Unique Identification Number for the Notification.
// We use it on Notification start, and to cancel it.
//private int NOTIFICATION = R.string.local_service_started;
private int NOTIFICATION = R.string.local_service_started;
private int statusCode = 10;
// This is the object that receives interactions from clients. See
// RemoteService for a more complete example.
private final IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/**
* Class for clients to access. 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 implements ILocalService {
LocalService getService() {
return LocalService.this;
}
#Override
public int getStatusCode() {
return statusCode;
}
}
public static final String EXTRA_MESSENGER = "com.marie.localservicesample.EXTRA_MESSENGER";
private Messenger messenger;
public static final String EXTRA_SONG = "com.marie.localservicesample.EXTRA_SONG";
private int song;
#Override
public void onCreate() {
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Display a notification about us starting. We put an icon in the status bar.
showNotification();
Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
thr.start();
}
/*
* This is the ServiceWorker thread that passes messages to the handler defined in
* the MainActivity class.
* NOTE: Instead of passing messages to a handler in MainActivity I would like
* it to pass messages to a handler defined in the RcvMessages activity.
*/
class ServiceWorker implements Runnable
{
public void run() {
// do background processing here... something simple
while (messenger == null);
// send a message to the handler
try {
Message msg = Message.obtain();
msg.obj = "Hello " + "Song " + song;
msg.arg1 = song;
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
// stop the service when done...
// LocalService.this.stopSelf();
// Or use the unbindBtn in the MainActivity class.
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
Bundle extras = intent.getExtras();
messenger = (Messenger)extras.get(EXTRA_MESSENGER);
try {
song = (Integer) extras.get(EXTRA_SONG);
} catch (NullPointerException e) {
e.printStackTrace();
song = 0;
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
#Override
public void onDestroy() {
// Cancel the persistent notification.
mNM.cancel(NOTIFICATION);
// Tell the user we stopped.
Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show();
}
/**
* Show a notification while this service is running.
*/
private void showNotification() {
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.local_service_started);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.stat_sample, text,
System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
//PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, LocalServiceActivities.Controller.class), 0);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Controller.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.local_service_label),
text, contentIntent);
// Send the notification.
mNM.notify(NOTIFICATION, notification);
}
/* Duplicate added by Eclipse
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
*/
}
/**************************************************************************************************
* Filename: Binding.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains the binding for this application
**************************************************************************************************/
package com.marie.localservicesample;
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.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
/*
* Example of binding and unbinding to the local service.
* This demonstrates the implementation of a service which the client will
* bind to, receiving an object through which it can communicate with the service.
*/
public class Binding extends Activity {
private boolean mIsBound;
private LocalService mBoundService;
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();
ILocalService localService = (ILocalService)service;
int statusCode = localService.getStatusCode();
Log.d("Binding","called onServiceConnected. statusCode: " + statusCode);
Toast.makeText(Binding.this, R.string.local_service_connected,
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;
Log.d("Binding", "called onServiceDisconnected");
Toast.makeText(Binding.this, R.string.local_service_disconnected,
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(Binding.this,
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();
}
private OnClickListener mBindListener = new OnClickListener() {
public void onClick(View v) {
doBindService();
}
};
private OnClickListener mUnbindListener = new OnClickListener() {
public void onClick(View v) {
doUnbindService();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.local_service_binding);
// Watch for button clicks.
Button button = (Button)findViewById(R.id.bind);
button.setOnClickListener(mBindListener);
button = (Button)findViewById(R.id.unbind);
button.setOnClickListener(mUnbindListener);
}
}
/**************************************************************************************************
* Filename: ILocalService.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains an example interface for LocalService
**************************************************************************************************/
package com.marie.localservicesample;
public interface ILocalService {
// An example method for ILocalService
public int getStatusCode();
}
My question is why would anyone want to provide an ILocalService.java if they already have a startService() with a thread and a handler like I do? My ILocalService.java is a trivial demo which asks for a statusCode. As far as I can tell my ILocalService.java will only consist of getters of status and no setters. So will I only be asking for status info of my local service? What would be an example of a setter to my local service?
Your binder looks like this:
public class LocalBinder extends Binder implements ILocalService {
LocalService getService() {
return LocalService.this;
}
#Override
public int getStatusCode() {
return statusCode;
}
}
The key part of interest is getService. What this means is that any of your Activities that bind to your Service (since this is a local service) can actually obtain the service object and can call ANY functions on that service function, not just getters. You aren't limited to just the narrow communication channel that is startService and the Intent, you have the full method interface for the service object. In the past I've passed BluetoothDevice instances, Handler instances and other complex Java objects through to the service object.
Related
I have the following code in which I have one date picker and time picker
When I select that date and time I want to show notification...
It is perfectly working but when I again put notification means if I pu6 multiple notification it will show me only last one...
Means only last notification is showing not all...
NotifyService.java
package com.blundell.tut.service;
import android.R;
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.util.Log;
import android.widget.Toast;
import com.blundell.tut.ui.phone.SecondActivity;
public class NotifyService extends Service {
/**
* Class for clients to access
*/
public class ServiceBinder extends Binder {
NotifyService getService() {
return NotifyService.this;
}
}
// Unique id to identify the notification.
public static int NOTIFICATION = 123;
// Name of an intent extra we can use to identify if this service was started to create a notification
public static final String INTENT_NOTIFY = "com.blundell.tut.service.INTENT_NOTIFY";
// The system notification manager
private NotificationManager mNM;
#Override
public void onCreate() {
Log.i("NotifyService", "onCreate()");
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// If this service was started by out AlarmTask intent then we want to show our notification
if(intent.getBooleanExtra(INTENT_NOTIFY, false))
showNotification();
// We don't care if this service is stopped as we have already delivered our notification
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// This is the object that receives interactions from clients
private final IBinder mBinder = new ServiceBinder();
/**
* Creates a notification and shows it in the OS drag-down status bar
*/
private void showNotification() {
// This is the 'title' of the notification
CharSequence title = "Alarm!!";
// This is the icon to use on the notification
int icon = R.drawable.ic_dialog_alert;
// This is the scrolling text of the notification
CharSequence text = "Your notification time is upon us.";
// What time to show on the notification
long time = System.currentTimeMillis();
Notification notification = new Notification(icon, text, time);
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, SecondActivity.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, title, text, contentIntent);
// Clear the notification when it is pressed
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_VIBRATE;
NOTIFICATION++;
Toast.makeText(NotifyService.this, Integer.toString(NOTIFICATION), Toast.LENGTH_SHORT).show();
mNM.notify(NOTIFICATION, notification);
// Stop the service when we are finished
stopSelf();
}
}
ScheduleClient.java
package com.blundell.tut.service;
import java.util.Calendar;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
/**
* This is our service client, it is the 'middle-man' between the
* service and any activity that wants to connect to the service
*
* #author paul.blundell
*/
public class ScheduleClient {
// The hook into our service
private ScheduleService mBoundService;
// The context to start the service in
private Context mContext;
// A flag if we are connected to the service or not
private boolean mIsBound;
public ScheduleClient(Context context) {
mContext = context;
}
/**
* Call this to connect your activity to your service
*/
public void doBindService() {
// Establish a connection with our service
mContext.bindService(new Intent(mContext, ScheduleService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
/**
* When you attempt to connect to the service, this connection will be called with the result.
* If we have successfully connected we instantiate our service object so that we can call methods on it.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with our service has been established,
// giving us the service object we can use to interact with our service.
mBoundService = ((ScheduleService.ServiceBinder) service).getService();
}
public void onServiceDisconnected(ComponentName className) {
mBoundService = null;
}
};
/**
* Tell our service to set an alarm for the given date
* #param c a date to set the notification for
*/
public void setAlarmForNotification(Calendar c){
mBoundService.setAlarm(c);
}
/**
* When you have finished with the service call this method to stop it
* releasing your connection and resources
*/
public void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
mContext.unbindService(mConnection);
mIsBound = false;
}
}
}
ScheduleService.java
package com.blundell.tut.service;
import java.util.Calendar;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import com.blundell.tut.service.task.AlarmTask;
public class ScheduleService extends Service {
/**
* Class for clients to access
*/
NotifyService ns=new NotifyService();
public class ServiceBinder extends Binder {
ScheduleService getService() {
return ScheduleService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("ScheduleService", "Received start id " + ns.NOTIFICATION + ": " + intent);
// We want this service to continue running until it is explicitly stopped, so return sticky.
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// This is the object that receives interactions from clients. See
private final IBinder mBinder = new ServiceBinder();
/**
* Show an alarm for a certain date when the alarm is called it will pop up a notification
*/
public void setAlarm(Calendar c) {
// This starts a new thread to set the alarm
// You want to push off your tasks onto a new thread to free up the UI to carry on responding
new AlarmTask(this, c).run();
}
}
AlarmTask.java
package com.blundell.tut.service.task;
import java.util.Calendar;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import com.blundell.tut.service.NotifyService;
public class AlarmTask implements Runnable{
// The date selected for the alarm
private final Calendar date;
// The android system alarm manager
private final AlarmManager am;
// Your context to retrieve the alarm manager from
private final Context context;
public AlarmTask(Context context, Calendar date) {
this.context = context;
this.am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
this.date = date;
}
#Override
public void run() {
// Request to start are service when the alarm date is upon us
// We don't start an activity as we just want to pop up a notification into the system bar not a full activity
Intent intent = new Intent(context, NotifyService.class);
intent.putExtra(NotifyService.INTENT_NOTIFY, true);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
// Sets an alarm - note this alarm will be lost if the phone is turned off and on again
am.set(AlarmManager.RTC_WAKEUP, date.getTimeInMillis(), pendingIntent);
long firstTime = date.getTimeInMillis();
am.setRepeating(AlarmManager.RTC_WAKEUP, firstTime, am.INTERVAL_DAY * 7, pendingIntent);
}
}
MainActivity.java
package com.blundell.tut.ui.phone;
import java.util.Calendar;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.DatePicker;
import android.widget.TimePicker;
import android.widget.Toast;
import com.blundell.tut.R;
import com.blundell.tut.service.NotifyService;
import com.blundell.tut.service.ScheduleClient;
public class MainActivity extends Activity
{
// This is a handle so that we can call methods on our service
private ScheduleClient scheduleClient;
private DatePicker picker;
NotifyService ns;
private TimePicker tp;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scheduleClient = new ScheduleClient(this);
scheduleClient.doBindService();
ns=new NotifyService();
picker = (DatePicker) findViewById(R.id.scheduleTimePicker);
tp=(TimePicker)findViewById(R.id.TimePicker);
tp.setIs24HourView(true);
}
public void onDateSelectedButtonClick(View v){
int day = picker.getDayOfMonth();
int month = picker.getMonth();
int year = picker.getYear();
int hour=tp.getCurrentHour();
int min=tp.getCurrentMinute();
// Create a new calendar set to the date chosen
// we set the time to midnight (i.e. the first minute of that day)
Calendar c = Calendar.getInstance();
c.set(year, month, day,hour,min,0);
scheduleClient.setAlarmForNotification(c);
// Notify the user what they just did
//Toast.makeText(this, Integer.toString(ns.NOTIFICATION), Toast.LENGTH_SHORT).show();
//Toast.makeText(this, "Notification set for: "+ day +"/"+ (month+1) +"/"+ year, Toast.LENGTH_SHORT).show();
}
#Override
protected void onStop()
{
// When our activity is stopped ensure we also stop the connection to the service
// this stops us leaking our activity into the system *bad*
if(scheduleClient != null)
scheduleClient.doUnbindService();
super.onStop();
}
}
SecondActivity.java
package com.blundell.tut.ui.phone;
import android.app.Activity;
import android.os.Bundle;
import com.blundell.tut.R;
/**
* This is the activity that is started when the user presses the notification in the status bar
* #author paul.blundell
*/
public class SecondActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
}
Please suggest me at which place i have to change code...????
In this line,
mNM.notify(NOTIFICATION, notification);
Just make sure that each time the different value of NOTIFICATION is being passed.
at AlarmTask.java, you are hard coded always 0 in PendingIntent.
requestCode must be
UNIQUE INTEGER NUMBER
so change your code,
from
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
to
int random = (int)System.currentTimeMillis();
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, random, intent, 0);
Just write code like this.
int random = (int)System.currentTimeMillis();
manager.notify(random , activeNotification);
I know this sounds weird, but I created a simple timer with an activity and a service (started and bound).
In the activity I also implemented onStart and onStop just logging a message (Log.d(TAG,"activity started/stopped").
The fact is that if the phone is connected to the pc everything seems to work. I can start the timer, pause it, modify and restart it. Open other apps and it keeps working on the background. I can recall it and I see the actual countdown going down. If it finish I can recall the activity from a notification and stop the ringing. etc etc
If the phone it's detached from the pc, that it works like there is no service at all. So the activity runs and if I press the home button it goes on the background and keeps working for a couple of minutes than it stops.
I can see the process in the running applications and if I recall the activity it restart from the point where it paused. That is, I set 10 minutes, I click start and then the home button. After 2-3 minutes it stops working and if I recall the activity it continues counting down from 8-7 minutes...
Any idea?
The activity:
package com.sleone.cookingtimer;
import com.sleone.cookingtimer.TimerService.LocalBinder;
import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import kankan.wheel.widget.WheelView;
import kankan.wheel.widget.adapters.NumericWheelAdapter;
import android.util.Log;
public class TimerMainActivity extends Activity {
// private CookingTimer timer;
// suppressWarnings because is initialized binding to the service
private TimerService timerService;
private Intent timerServiceIntent;
private final String TAG = "TimerMainActivity";
private WheelView hoursWheel ;
private WheelView minutesWheel;
private WheelView secondsWheel;
/*
* Initialize the activity
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer_main);
timerServiceIntent = new Intent(this, TimerService.class);
startTimerService();
// init the gui
hoursWheel = (WheelView) findViewById(R.id.hoursWheelView);
minutesWheel = (WheelView) findViewById(R.id.minutesWheelView);
secondsWheel = (WheelView) findViewById(R.id.secondsWheelView);
hoursWheel.setViewAdapter(new NumericWheelAdapter(this, 0, 6));
minutesWheel.setViewAdapter(new NumericWheelAdapter(this, 0, 59));
secondsWheel.setViewAdapter(new NumericWheelAdapter(this, 0, 59));
}
#Override
protected void onStop(){
super.onStop();
Log.d(TAG, "TimerMainActivity stopped");
}
#Override
protected void onStart(){
super.onStart();
Log.d(TAG, "TimerMainActivity started");
}
private void startTimerService() {
// connect to the service
// leave the service in background
Log.d(TAG, "Starting the TimerService");
startService(timerServiceIntent);
// interact with the service
Log.d(TAG, "Binding to the TimerService");
bindService(timerServiceIntent, mConnection, Context.BIND_AUTO_CREATE);
}
private void stopTimerService() {
unbindService(mConnection);
stopService(timerServiceIntent);
}
/*
* Disconnect from the service
*/
#Override
protected void onDestroy() {
Log.d(TAG, "Stopping TimerService");
super.onStop();
stopTimerService();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.timer_main, menu);
return true;
}
public void controlTimer(View view) {
Button controlButton = (Button) findViewById(R.id.controlTimerButton);
if (controlButton.getText().equals(
getResources().getText(R.string.startTimer))) {
if ((hoursWheel.getCurrentItem() == 0)
&& (minutesWheel.getCurrentItem() == 0)
&& (secondsWheel.getCurrentItem() == 0)) {
return;
}
controlButton.setText(R.string.stopTimer);
timerService.startTimer();
} else {
controlButton.setText(R.string.startTimer);
timerService.stopTimer();
}
}
/* 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;
timerService = binder.getService();
binder.createCookingTimer(TimerMainActivity.this);
Log.d(TAG, "onServiceConnected() finished");
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.e(TAG, "TimerService unexpectedly disconnected!!");
}
};
}
The service:
package com.sleone.cookingtimer;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class TimerService extends Service{
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
private CookingTimer timer;
//private int timerServiceId;
public class LocalBinder extends Binder {
public TimerService getService() {
// Return this instance of LocalService so clients can call public methods
return TimerService.this;
}
// when the client connects to the service instantiate the CookingImer
public void createCookingTimer(TimerMainActivity timerMainActivity){
timer = new CookingTimer(timerMainActivity);
}
}
public void startTimer(){
timer.startTimer();
}
public void stopTimer(){
timer.stopTimer();
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return mBinder;
}
}
I don't think you need the timer itself. It;s just a CountDownTimer which onTick it updates the hours/minutes/seconds Wheel and onFinish plays a sound and create a notification.
You might have some sort of race condition, that when connected to the PC, execution is a bit slower, but when not connected the timing is a bit different and the order of execution changes. It's hard to tell without the code.
Ok, I guess I figured it out.
Basically I did not understand exactly that a service could also be paused when the cpu goes to sleep.
So, my guess is that while on the emulator or with the cable connected the cpu never goes to sleep because there is no battery consumption.
To wake up the application even from the cpu sleep I used an AlarmManger with the AlarmManager.RTC_WAKEUP flag.
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.
Hie all,
i am working on Bluetooth connections and to do that i have device address and i want send it to a service which handle Bluetooth connections
i want to send string(device address) from activity to service (Android)
Code In ACTIVITY CLASS:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
// Get the device MAC address
address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BLuetoothDevice object
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
startService(new Intent(CallBluetooth .this,BluetoothService.class));
Intent myIntent = new Intent(CallBluetooth.this, BluetoothService.class);
Bundle bundle = new Bundle();
CharSequence data1 = "abc";
bundle.putCharSequence("extraData",data1);
myIntent.putExtras(bundle);
PendingIntent pendingIntent = PendingIntent.getService(CallBluetooth.this, 0, myIntent, 0);
/*BluetoothService s = new BluetoothService();
s.deviceAddress(address);*/
// Attempt to connect to the device
// mChatService.connect(device);
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled, so set up a chat session
openOptionsMenu();
} else {
// User did not enable Bluetooth or an error occured
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
}
Code In SERVICE CLASS:
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
Bundle bundle = intent.getExtras();
System.out.println("*******************"+"InsideOnStart");
if(bundle != null)
{
CharSequence data = (String) bundle.getCharSequence("extraData");
System.out.println("*******************"+data);
}
}
According to this article i've implemented Activity that sends String to Service. You can look below, maybe it will help.
MainActivity.java
package com.example.androidtranslator;
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.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
private Messenger mService = null;
private boolean mBound;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// some gui code etc...
/**
* Connect to an application service, creating it if needed
*/
bindService(new Intent(this, TranslatorService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/**
* on some GUI action (click button) send message
*
* #param view
*/
public void translate(View view) {
if (!mBound)
return;
Message msg = Message.obtain(null, TranslatorService.MSG_STRING,
"Some message (it can be from textView for example)");
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#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;
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
mBound = false;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);
mBound = true;
}
};
}
TranslatorService.java
package com.example.androidtranslator;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.widget.Toast;
public class TranslatorService extends Service {
public static final int MSG_STRING = 0;
/**
* Handler of incoming messages from clients.
* Show Toast with received string
*/
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_STRING:
Toast.makeText(getApplicationContext(), msg.obj.toString(), Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
#Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
Have you looked at the Service documentation and examples from and Android docs?
In a nutshell, you can use a Messenger to send meaningful messages to the service. Look at the section on: Remote Messenger Service Sample
you cant send data directly from activity to service,
you need to used Android Interface Definition Language (AIDL)
Using aidl you can call any method in service that define in .aidl file from activity, if you want to pass data than you can pass data as arguments of methods
for additional info see Implementing Remote Interface Using AIDL
I was writing a simple AIDL based android remote service & a client to access the API exposed by the remote service. I checked on the internet, in every posts people have called the remote service API inside button's onClickListener() method of client code. However when i tried to call the API exposed by remote service outside the onClickListener() method it throws me NullPointerException, indicating that my service object has not been initialized (Please check the comments inside the onCreate method of client code). I have attached my code with this question. If anyone can explain me why is the behavior so then that would be really great.
Here is client code :
package com.myapp.myclient;
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.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.myapp.myservice.RemoteServiceInterface;
public class MyClient extends Activity {
RemoteServiceInterface remoteInterface;
ServiceConnection connection;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent i = new Intent();
i.setAction("com.myapp.myservice.RemoteService");
startRemoteInterface(i);
bindRemoteInterface(i);
/* This code doesn't execute. Raises a Null Pointer
Exception, indicating that remoteInterface is not
initialized. */
try {
Toast.makeText(getBaseContext(), remoteInterface.getMessage(), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
/* Whereas this code does work. */
Button getMessage = (Button)findViewById(R.id.getMessage);
getMessage.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String msg = null;
try {
msg = remoteInterface.getMessage();
} catch (RemoteException e) {
e.printStackTrace();
}
Toast.makeText(getBaseContext(), msg, Toast.LENGTH_SHORT).show();
}
});
}
class RemoteServiceConnection implements ServiceConnection{
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
remoteInterface = RemoteServiceInterface.Stub.asInterface(service);
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
}
private void startRemoteInterface(Intent i) {
startService(i);
}
private void bindRemoteInterface(Intent i) {
if(connection == null){
connection = new RemoteServiceConnection();
bindService(i, connection, Context.BIND_AUTO_CREATE);
} else {
Toast.makeText(getBaseContext(), "Service cannot bind - already bound.", Toast.LENGTH_SHORT).show();
}
}
}
Here is my remote service code:
package com.myapp.myservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class RemoteService extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
private final RemoteServiceInterface.Stub mBinder = new RemoteServiceInterface.Stub() {
#Override
public String getMessage() throws RemoteException {
return "Hello World!";
}
};
}
Here is my aidl file :
package com.myapp.myservice;
interface RemoteServiceInterface {
String getMessage();
}
Thanks in advance,
Rupesh
bindRemoteInterface(i);
/* This code doesn't execute. Raises a Null Pointer
Exception, indicating that remoteInterface is not
initialized. */
try {
Toast.makeText(getBaseContext(), remoteInterface.getMessage(), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
Please keep in mind that the bind is an asychronus call you have to wait for the callback in the ServiceConnection for onServiceConnected and perform actions after that.
Also you have to use the asInterface method to get the real interface for your connection this is demonstrated by the google aidl example
RemoteServiceInterface mIRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Following the example above for an AIDL interface,
// this gets an instance of the IRemoteInterface, which we can use to call on the service
mIRemoteService = RemoteServiceInterface.Stub.asInterface(service);
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "Service has unexpectedly disconnected");
mIRemoteService = null;
}
};
You can then make the call on the mIRemoteService object. either directly in the onServiceConnected callback or by notifying the service.
remoteInterface is NULL before service is connected (onServiceConnected called) .
startService is an async call, you call startService don't mean the service is started and connected . when service is connected , onServiceConnected is called , then you can use the connection to call remote service .
Actually , you should always check weather remoteInterface is null or not .