I intended to work like this:
user switches on a feature: let say weather.
now weather data will come from server every 6 hours and will be shown to widget(remoteview), Now user switches off the feature. then widget should not show the weather or even refresh the data every 6 hours.
there are also 3-4 more features like that.
Now i had created a service to get all required data and than i have passed them to remoteview. For starting service i had used this in TimeOut Activity:
i = new Intent(TimeOut.this, TimeService.class);
i.setAction("com.example.Weather.Idle");
startService(i);
same for stopping service in switch off code:
stopService(i)
This code was working fine in API <=19. But in Lollipop it crashes at starting or stoping service.
I searched a lot in SO and also tried code for Binding or unbinding service but didn't help any.
Please help me with some code rather than just links...
Thanks in advance :)
Starting a service from any activity class
Intent intent = new Intent(MainActivity.this, BackgroundService.class);
startService(intent);
Here is service class code
public class BackgroundService extends Service{
public static Context appContext = null;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
if (appContext == null) {
appContext = getBaseContext();
}
Toast.makeText(appContext, "Services Started", Toast.LENGTH_SHORT).show();
return START_STICKY;
}
Add your logic here. You can do some work here using a thread. You can stop service whenever you want and i hope you will not find any crash.
I have faced similar issue with Service in 5.0. This is probably not the correct answer, but it works. You could try. I use EventBus to communicate with my services. So when I want to stop the service I'd send,
EventBus.getDefault().post(new ServiceEvent(ServiceEvent.STOP_SERVICE));
In the service,
public void onEvent(ServiceEvent event) {
if (event.getEvent() == ServiceEvent.STOP_SERVICE) {
methodToStopService();
}
}
private void methodToStopService() {
// do some stuff
stopSelf();
}
Make sure you register your service for events.
private void registerEventBus() {
EventBus eventBus = EventBus.getDefault();
if (!eventBus.isRegistered(this)) {
eventBus.register(this);
}
}
ServiceEvent class - It's my own class which I use with EventBus.
public class ServiceEvent {
private int event;
public static final int STOP_SERVICE = -1;
public ServiceEvent(int event) {
this.event = event;
}
public int getEvent() {
return event;
}
}
Related
Simply, I want to upload files over the net using a service.
I have created a service with both: binding and startService. I create a foreground service that displays the progress.
The issue is, after the upload is complete, I call stopForeground(true) and then stopSelf but the notification is not removed and (probably) the service is not killed.
Code of the service class:
public class UploaderService extends Service {
// ...
public void finishUpload(File audioFile, File eventsData) {
LogWrapper.d(TAG, "finishUpload");
mUploadHelper.upload(audioFile, eventsData)
// consider this just a callback:
.subscribe(uuid -> {
// Log is printed but service is not stopped
LogWrapper.d(TAG, "finishUpload.subscribe");
stopForeground(true);
stopSelf();
}, LogWrapper::fatalError);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationCompat.Builder builder = NotificationsManager.getDefaultBuilder(this)
.setProgress(0, 0, true)
.setContentText(intent.getStringExtra(EXTRA_TOPIC_NAME))
.setContentTitle("Uploading data to server");
// first creating a notification with uuid,
// after POST /post call, post.uid will be used.
startForeground(DEAFULT_NOTIFICATION_ID, builder.build());
return START_REDELIVER_INTENT;
}
#Override
public IBinder onBind(Intent intent) {
LogWrapper.d(TAG, "onBind " + intent);
return mUploaderBinder;
}
#Override
public boolean onUnbind(Intent intent) {
LogWrapper.d(TAG, "onUnbind " + intent);
intent.putExtra(EXTRA_TOPIC_NAME, mUploadHelper.getTopic().name);
startService(intent);
return false;
}
#Override
public void onCreate() {
super.onCreate();
mUploaderBinder = new UploaderBinder();
}
public class UploaderBinder extends Binder {
public UploaderService getService() {
return UploaderService.this;
}
}
}
Though I could not find it in docs, the startService command should be called from outside the service i.e. from an Activity. I called it from my activity just before binding to it and it worked as expected.
I was probably experiencing an undefined behavior- the service was starting but not stopping. I wish someone could give me a better explanation of why that was happening, and that this indeed is the correct way to do stuff.
Great thanks to #pskink for pointing me in the right direction.
My Discovery class extends Service class. When I try to get its singletone from other class this way:
Discovery discovery = Discovery.getInstance();
I get a NullPointerException. This is the Discovery code:
public static Discovery getInstance(){
if (discovery == null){
discovery = new Discovery();
discovery.initDiscovery ();
}
Log.i(TAG, "get discovery instance");
return discovery;
}
public Discovery() {
}
private void initDiscovery(){
mDiscoveredDevices = new ArrayList<String>();
BluetoothManager bluetoothManager = (BluetoothManager) discovery.getSystemService(Context.BLUETOOTH_SERVICE);<--NullPointerException
....
}
This is not Android my friend.
To create a service you need to declare it in manifest:
<service
android:name=".DiscoveryService" />
After which you can instantiate it but never using operator new. Instead you need to call:
startService(context, new Intent(context, DiscoveryService.class);
There are other ways of firing a service intent but this will suffice for now.
The service's construction code should be placed at onCreate:
class DiscoveryService extends Service {
#Override
public void onCreate() {
service construction code here
}
}
And its request handling code in onStartCommand:
public int onStartCommand(Intent intent, int flags, int startId) {
handle incoming intent
}
Now, if you do need to access a service instance probably the simplest way
of achieving it would be to declare and maintain a static instance reference within
the service. Do it like this:
class DiscoveryService extends Service {
private static DiscoveryService inst; // <-----------------
public DiscoveryService getInstance() {
return inst;
}
#Override
public void onCreate() {
service construction code here
inst = this;
}
#Override
public void onDestroy() {
cleanup code here
inst = null;
}
}
This approach has its shortcomings, but unlike yours, it will work. Still use with care.
Finally - years of writing & reviewing Android code have led me to the conclusion
that what most novice developers want when they ask for Service, is in fact an IntentService..
Please read the docs and make sure you got your class right.
Good luck.
I've got a Service in my Android application. During onStartCommand, I pass the Service object to another class. Then, from there, there's a thread that after 30 seconds starts another Service. It is something like this:
public class FooService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
MyClass mc = new MyClass(this);
mc.testMethod();
stopSelf();
return START_NOT_STICKY;
}
}
And this is MyClass:
public class MyClass {
private Service service;
public MyClass(Service service) {
this.service = service;
}
public void testMethod() {
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(20*1000);
Intent intent = new Intent(service, BarService.class);
service.startService(intent);
}
catch (Exception e) {
// CATCH!
}
}
}).start();
}
}
Now, as you can see, in FooService I call stopSelf() wich destroys that Service object. By the way MyClass has got a copy of that Service that was passed by value. After 20 seconds, we can start BarService from MyClass. I've tested it and it works but I can't understand why! The way I wrote the code is dirty (for me). Is it correct to start another service from one that was destroyed? Thank you for your help.
I've tested it and it works but I can't understand why
It works today on the environments you tested in. It may not work in all environments (e.g., ROM mods) and may not work tomorrow (e.g., Android OS updates). A destroyed Context, such as your stopped service, should not be used for anything. It happens that presently you can still use it to call startService() later, but that behavior is not guaranteed.
Is it correct to start another service from one that was destroyed?
No. In this case, I fail to see why you need two services in the first place.
I've got a copy of that service
No, you do not.
I'm trying to call a service class to update the value of a variable from my widget but it doesn't ever seem to get to the service class. I've had a look at some examples and I can't figure out what I'm doing wrong, and I don't really know very much about services yet. All help appreciated.
Service class
public class toggleMonitoringService extends Service{
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate()
{
Log.d("Me","creating service");
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int startId, int something) {
// TODO Auto-generated method stub
String toggle = intent.getExtras().getString("Toggle");
Log.d("Me","Toggle : " + toggle);
if (toggle.equals("app1"))
{
UpdateWidgetService.monitorApp1 = !UpdateWidgetService.monitorApp1;
}
else if (toggle.equals("app2"))
{
UpdateWidgetService.monitorApp2 = !UpdateWidgetService.monitorApp2;
}
super.onStartCommand(intent, startId, something);
return 0;
}
}
Where I set up the intent and pending intent to handle the button click from the widget
Intent monitor1toggle = new Intent(this.getApplicationContext(),toggleMonitoringService.class);
monitor1toggle.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
monitor1toggle.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,allWidgetIds);
monitor1toggle.putExtra("Toggle","app1");
PendingIntent monitor1 = PendingIntent.getService(getApplicationContext(), 0 , monitor1toggle,0);
remoteViews.setOnClickPendingIntent(R.id.firstappstatus, monitor1);
Try start service manually, wihtout using PendingIntent.
Better way is not to start service each time you need to do something, but to start it once, bind to it and use common method calls when you need something from the service.
For your example even a simple Thread would be more appropriate.
I am trying to run a service, whem i stop my app that service still run means it's continuing its task. What is the way to stop service when we stop our app? Plese help me how can i stop this service. One more thing is also there if i use intent in this class to move back to that class from where service is calling i moved back but when i press back button on emulator to go back then it display that service screen also.
I am showing the code of service class
public class SetMovableBG_Inbuilt_SetImage extends Service
{
Timer mytimer;
int interval = 2000;
int interval1 = 4000;
Drawable drawable;
WallpaperManager wpm;
int prev = 0;
int numImage;
private ArrayList<Integer> imgId;
#Override
public void onCreate()
{
super.onCreate();
mytimer = new Timer();
wpm = WallpaperManager.getInstance(this);
}
// here i am geting intent from the class from where i am calling this class.
//everything works fine but service not stops even after stop the app
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
imgId = intent.getIntegerArrayListExtra("ImgId");
numImage = imgId.size();
mytimer.schedule(new TimerTask()
{
#Override
public void run()
{
// TODO Auto-generated method stub
if ( prev >= numImage )
{
prev = 0;
}
try
{
wpm.setResource(imgId.get(prev));
}
catch ( IOException e )
{
e.printStackTrace();
}
prev++;
}
}, interval, interval1);
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
}
you can use Service.stopService method to stop the service from other component like activities. You can use Service.stopSelf method to stop the service from the service itself. according to doc
A started service must manage its own lifecycle. That is, the system
does not stop or destroy the service unless it must recover system
memory and the service continues to run after onStartCommand()
returns. So, the service must stop itself by calling stopSelf() or
another component can stop it by calling stopService().
To know more about Services see here