I want to start a Service use an Activity. To be specific, it is IntentService. But I have two problems:
When starting my code
private void switchService(boolean isEnable, String serviceName){
Intent intent = new Intent();
intent.setClassName(TestPhoneServiceActivity.this, serviceName);
if(isEnable){
startService(intent);
}
else{
if(isServiceRunning(serviceName)){
stopService(intent);
while(isServiceRunning(serviceName)){
}
Toast.makeText(this, "Service stopped Successfully!", Toast.LENGTH_LONG).show();
}
}
}
DDMS has the error:Unable to start service Intent { cmp=com.xx.android/.AndroidPhoneService }: not found
But the path is right. So what is the problem?And also I want to call a system service. Should I write it into configuration file?
Then I start IntentService use intent.setClass.
ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVICE)
I can not find this service object. Is the IntentService finished and destroyed automatically?And the life cycle of IntentService is different from the other Service?
You should pass in the class of the service instead of the name of the class of the service like so
Intent intent = new Intent();
intent.setClassName(TestPhoneServiceActivity.this, MyIntentService.class);
if(isEnable){
startService(intent);
}
The intent service stops itself after work has completed if you start multiple of the same intent service it will be queued behind and executed sequentially, so the else block is kind of redundant in your case.
And make sure you have declared the service inside your manifest.
Related
now i have a server class that i run on a thread from an activity(i.e servActivity).now when i am not interacting with my app in anyway possible (like i have removed it from recent apps etc) the thread should stop which currently is not stopping. So i researched and i found that i should use a bound service. now a bound service i will have to bind it to servActivity and when servActivity is destroyed i have to unbind and stop service but i dont want to do that. i want to stop service when i am not interacting with the app. i also found that maybe i have to extend application class but cannot find the solution to achieve this?Is it advisable to extend the application class?
i want to be able to create a service running on independent thread from a particular activity(ie servActivity) and then be able to interact with the service from any activity and service should be active (even if the activity in which i started the service i.e-servActivity is destroyed by going to previous activity etc) through button or whatever until i am not interacting with the app(i have a notification controller which also needs to be closed to stop the interaction)
i have a client class on one device whose object i create again and again if i have to make request but i want to make only one object for server class because it has a while(true) loop so it keeps running so i want to be able to interact with the server from all activities and stop it when i am not interacting with the application
i also found a way in which i can make an abstract class which extends activity and extend that derived class to all the other activities in my app.But how to i bind the service to all the other activities in the class so that i can interact with the service from all the other activities?And how would i know that if all activities and notification controller have been stopped and there is no interaction with user?something like this how to know our app has gone to background in android
If there is there any other method please suggest
Please help
thanks in advance
You can create a BroadcastReceiver in your Service Class to interact/start/close your Service from any Activity or even from any App.
Your Activities can broadcast custom Action Strings which can be picked up by any BroadcastReceivers (even ones set up in Services) and thereby invoking their onReceive() methods allow communication.
1) I suggest you don't bind your Service to any Activity and instead use Intent to initiate it in your Activity like this....
//In your Activity
Intent i = new Intent(this, /*MyServiceClassName.class*/);
startService(i);
Or else your Service may still be active until you unbind it.
2) Create a BroadcastReceiver in your Service Class to listen for certain Action Strings broadcasted by your Activities....
//In your Service
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(/*"Action String to stop Service"*/)){
stopSelf();
}else if(action.equals(/*"Action string to interact with Service"*/)){
//Do what you want
};
3) Now set what Action Strings the Broadcast Receiver will listen for and also register it in your Service onCreate() method....
//In your Service onCreate() method
IntentFilter filter = new IntentFilter();
filter.addAction(/*"Action String to stop Service"*/);
filter.addAction(/*"Action String to do something"*/);
registerReceiver(receiver, filter);
4) And also unregister your receiver when Service onDestroy() is invoked as housekeeping....
//Service onDestroy()
#Override
public void onDestroy(){
super.onDestroy();
unregisterReceiver(receiver);
}
5) Finally broadcasting Action Strings from your Activities through Intent....
//From any Activity
Intent intent = new Intent(/*"your custom Action String that should match
up with whats set up with the BroadcastReceiver in Service"*/);
sendBroadcast(intent);
6) So once the broadcast is sent your receiver should pick it up then its onReceive() method will be invoked. Therefore you now have a medium for your Activities and Service to communicate through and also the Service will persist even after you close your app until you stop it explicitly with....
//From any Activity
Intent i = new Intent(this, /*MyServiceClassName.class*/);
stopService(i);
7) Stop service when app is stopped....
//In all your activities
#Override
protected void onDestroy() {
Intent i = new Intent(this, /*MyServiceClassName.class*/);
stopService(i);
super.onDestroy();
}
8) First you'd need to put a killcode intent action String in your Service as demonstrated in points 2 and 3 then put this code in your app's Activity onPause() methods....
#Override
protected void onPause() {
PendingIntent pintent = PendingIntent.getBroadcast( this, 0, new Intent(/*"Action String to stop Service"*/), 0 );
AlarmManager manager = (AlarmManager)(this.getSystemService( Context.ALARM_SERVICE ));
// set alarm to fire 10mins (1000*60*10) from now (SystemClock.elapsedRealtime())
manager.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 1000*60*10, pintent );
super.onPause();
}
And this in your app's Activity onResume() methods....
#Override
protected void onResume() {
PendingIntent pintent = PendingIntent.getBroadcast( this, 0, new Intent(/*"Action String to stop Service"*/), 0 );
AlarmManager manager = (AlarmManager)(this.getSystemService( Context.ALARM_SERVICE ));
manager.cancel(pintent);
super.onResume();
}
on a broadcast I want to call a non static method from Service XYZ. The Service is start by the receiver on boot.
Has someone a idea to run methods from this running service?
One solution in this forum is to make the method static and use a singleton pattern to execute. But is there another method? Maybe with a binder?
//EDIT for example i have the following clases:
public class MyService extends Service{
.....
public void method(){
//TODO
}
}
public class MyBroadcastReceiver extends BroadcastReceiver{
.....
public void onReceive(Context context, Intent intent) {
String intentAction=intent.getAction();
if(intentAction.equals(Intent.ACTION_BOOT_COMPLETED)){
//start service
Intent serviceIntent = new Intent(context, MyService.class);
context.startService(serviceIntent);
}
else{
//TODO call method() in MyService
}
}
how can i call the method method()? I know that i can cast with context.getSystemService() system services. But how can i get my own service object?
greetings
You can add an action string to your intent using setAction in the intent that launches the Service. In your service's onStartcommand you can extract the intent's action, and based off that you can execute the method in your service.
You will always send commands to your service using startService this will not launch your service twice. It will either get started once, or the new intent is sent to the service.
So, in your on boot completed section you should set the intent action to whatever you want, and start the service - you can remove the else block completely.
In your Service implement the onStartCommand, extract the intent's action, and based off that action you can just execute your method.
The parts of this application in question are an IntentService (DatabaseService) and an AppWidgetProvider (LotWidget). In LotWidget, when a button is pressed, a PendingIntent is fired which sends a broadcast to itself, and is received in onReceive(). All of this works fine so far. In onReceive, I read the action from the Intent as well as the various extras, and either start this IntentService, or start the main Activity. Starting the activity works fine, but for some reason I can't understand, the DatabaseService isn't being started. I know code leading up to the DatabaseService intent is being sent by testing with Log.
Here is the onReceive code:
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if(intent.getAction().equals(RETURN_DATA_WIDGET) && initialize(context)){
updateWidget(context);
}
else if(intent.getAction().equals(INTERNAL_INC)){
Log.d("WIDG", "Incrememnt");
Intent incr = new Intent(context, DatabaseService.class);
incr.setAction(INCREMENT);
incr.putExtra("incval", intent.getIntExtra("incval", 999));
context.startService(intent);
}
else if(intent.getAction().equals(INTERNAL_UP)){
Log.d("WIDG", "UPDATE");
Intent upd = new Intent(context, DatabaseService.class);
upd.setAction(UPDATE_COUNT);
context.startService(intent);
}
else if(intent.getAction().equals(OPEN_APP)){
Intent open = new Intent(context, TheLotActivity.class);
open.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(open);
}
}
Using the same intents to start the DatabaseService from the main Activity works fine. My manifest defines the DatabaseService as a Service like so:
<service android:name="com.bsprague.thelot.DatabaseService" >
</service>
I know the Service isn't being started because a Log at the very beginning of onHandleIntent isn't being displayed, though it displays fine when this Intent is sent from the main Activity. Is there something in Android that I'm missing that makes it so you can't start a Service from a BroadcastReceiver?
You are setting an action on the Intent, and your <intent-filter> does not have that action. You might consider replacing the setAction() calls with putExtra() calls instead.
Never mind -- as you pointed out in a comment, since you are specifying the component, all other routing elements (e.g., action) are ignored. Your error from your updated comment suggests that your Intent is picking up the wrong component, LotWidget instead of DatabaseService.
I have a Service and BroadcastReceiver in my application, but how do I launch the service directly from the BroadcastReceiver? Using
startService(new Intent(this, MyService.class));
does not work in a BroadcastReceiver, any ideas?
EDIT:
context.startService(..);
works, I forgot the context part
Don't forget
context.startService(..);
should be like that:
Intent i = new Intent(context, YourServiceName.class);
context.startService(i);
be sure to add the service to manifest.xml
use the context from the onReceive method of your BroadcastReceiver to start your service component.
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, YourService.class);
context.startService(serviceIntent);
}
Best Practice :
While creating an intent especially while starting from BroadcastReceiver, dont take this as context.
Take context.getApplicationContext() like below
Intent intent = new Intent(context.getApplicationContext(), classNAME);
context.getApplicationContext().startService(intent);
try {
Intent intentService = new Intent(context, MyNewIntentService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intentService );
} else {
context.startService(intentService );
}
} catch (Exception e) {
e.printStackTrace();
}
It's better to use ContextCompat:
Intent serviceIntent = new Intent(context, ForegroundService.class);
ContextCompat.startForegroundService(context, serviceIntent);
Because a receiver's onReceive(Context, Intent) method runs on the main thread, it should execute and return quickly. If you need to perform long running work, be careful about spawning threads or starting background services because the system can kill the entire process after onReceive() returns. For more information, see Effect on process state To perform long running work, we recommend:
Calling goAsync() in your receiver's onReceive() method and passing the BroadcastReceiver.PendingResult to a background thread. This keeps the broadcast active after returning from onReceive(). However, even with this approach the system expects you to finish with the broadcast very quickly (under 10 seconds). It does allow you to move work to another thread to avoid glitching the main thread.
Scheduling a job with the JobScheduler
developer.android.com
I am still working on my location-based alarm android application. I have an AlarmService class that starts notifications and proximity alerts. I am starting this service with:
startService(intentAlarmService);
I try to stop the service using:
Intent intentAlarmService = new Intent(this, AlarmService.class);
stopService(intentAlarmService);
This is what happens: The service stops, but then, when I start another instance of the service (i.e. exit the app, launch the app, start the service) - I discover (through Toasts) that the previous instances of the service are still running. For example, in the AlarmService class, there is a LocationListener with the onLocationChanged method. So, in this method, I put:
Toast.makeText(AlarmService.this, "AlarmTitle: " + mAlarmTitle, Toast.LENGTH_SHORT).show();
And when I re-start the service, Toasts keep showing up with the previous AlarmTitles, and the current AlarmTitle.
So, something is not working when I try to stop the AlarmService - what could this be?
Note: when I re-install the application, the service stops for real. Then when I start the service, only the current AlarmTitle shows in the Toast (I want this to happen every time).
Something is wrong with my service. Any ideas what I can do?
thanks.
CODE FROM MY APP:
public void onDestroy() {
super.onDestroy();
Intent alarmIntent = new Intent(getApplicationContext(), AlarmReceiver.class);
PendingIntent pendingIntentAlarm = PendingIntent.getBroadcast(getApplicationContext(), PENDING_INTENT_REQUEST_CODE1, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
pendingIntentAlarm.cancel();
Intent intentAlarmService = new Intent(getApplicationContext(), AlarmService.class);
stopService(intentAlarmService);
mNtf.cancel(NOTIFICATION_ID1);
mNtf.cancelAll();
}
I discover (through Toasts) that the previous instances of the service are still running.
My guess is that you are leaking services, probably by failing to call removeUpdates() to detach your LocationListener. There is only one true running copy of the service (from an Android lifecycle standpoint), but you are preventing the other services from being garbage collected through your leak.
Also, please replace all occurrences of getApplicationContext() with this.
test this :
private Boolean Tb = true;
if(condition)
{
if(Tb)
{
Toast.makeText(getApplicationContext(),"content...", Toast.LENGTH_LONG).show();
}
Tb =false;
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Tb =true;
}
}, Toast.LENGTH_LONG);
}
}