I have a MyServiceClass defined as follows:
public class MyService extends Service {
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
}
If I call startService(new Intent(getBaseContext(), MyService.class)); from an activity class in the same package/app/APK, then I can see the Toast message.
But if I put this class in an application with no activity whatsoever (that is, service-only application) by simply tying it to boot receiver:
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, com.example.tutorialspoint7.noactivity.MyService.class));
}
}
Then, when the service starts, I no longer see the message.
I can restart the service on demand via Package Browser:
I understand that if there is no activity to provide a UI, then those messages don't really have where to be displayed. My questions, though, are:
Is there a default place where I can find these messages? (e.g. log file, buffer, LogCat, etc.)
Can I redirect these messages to the home screen current screen?
Why isn't the Android Studio framework display a warning when it sees/builds an APK that contains Toast.makeText().show() messages that have nowhere to be displayed?
The Toast messages are not related to your activity, but it a service on the Android UI which can be accessed by any application/activtiy. A simple glance at the source code would tell you that.
So if you pass the application context by getApplicationContext(), it will display from an activity-less application too.
FYI:
The toast is not bound to the UI of your activity. If you display a toast from your activity and then minimize it(press home), the toast remains on the home screen.
No, you cannot see toast messages that didnt get displayed because they were not enqued in the service itself.
Regarding android studio warning, I'm not sure why it doesn't report it, you could raise an issue regarding the same. But I had read that android developers suggest using the application context in all instances, even when an activity context is available. Sorry i cannot find the source from where I read this.
Use getApplicationContext() to access an activity-free context
Related
OK, here is my code, I'm trying to create a running service even when the app is closed.
In main activity, I have created a new button and call startMyService() to start the service as following:
public void startMyService(View view) {
Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent);
}
the Service class is simple :
public class MyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("MyService", "service is running");
final Uri uri = Settings.System.DEFAULT_RINGTONE_URI;
final Context x =(Context) MyService.this;
new Thread(new Runnable() {
#Override
public void run() {
MediaPlayer player = MediaPlayer.create(x,uri);
player.setLooping(true);
player.start();
}
}).start();
Toast.makeText(getApplicationContext(), "Service is running", Toast.LENGTH_LONG).show();
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
Log.e("MyService", "service done");
}
}
Of course, I have added the service to manifest
<service android:name=".MyService" android:exported="false" android:description="#string/service_description" />
Now after running, I pressed the button to start the service, and close the activity, I supposed the music will be playing in the background but it stopped just after closing the activity.
How to solve this issue? How to make the service still running, and how to make it running again after an android OS destroying it?
I know there are too many topics about android services and START_STICKY
However, as you see this is not working in code above, why?
Note: This is not about playing music in the background, I used playing music because it is the simplest way to know when service is stopped, this is about how to make service keeps running in the background as supposed to be, for example, to do some task like tracking data changes from the server.
It's normal behavior when your application target from android O, if you want to remain your Service you should use startForgroundService with Notification. Read here
While an app is in the foreground, it can create and run both foreground and background services freely. When an app goes into the background, it has a window of several minutes in which it is still allowed to create and use services. At the end of that window, the app is considered to be idle. At this time, the system stops the app's background services, just as if the app had called the services' Service.stopSelf() methods.
I have an application with only a service. Following is my code of the service, it is unable to call the device's build-in sms app.
public class smsservice extends Service {
private static final String TAG = "MyService";
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "Service created.");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("TAG", "Service started.");
try {
String sb = (String) intent.getSerializableExtra("dest1");
Intent sendIntent = new Intent(Intent.ACTION_VIEW);
sendIntent.putExtra("sms_body", sb);
sendIntent.setType("vnd.android-dir/mms-sms");
startActivity(sendIntent);
} catch (Exception e) {
Toast.makeText(getApplicationContext(),
"SMS faild, please try again later!",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
Log.d("slog", "onDestroy()");
super.onDestroy();
}
}
I have include the permission in the manifest file
<uses-permission android:name="android.permission.SEND_SMS" />
Is there something I am missing or is it even possible
I have an application with only a service
First, I hope you have a plan for something to run your service. By default, nothing in your app will ever run.
Second, I hope that you can afford security guards. Since you have no activity, the only way anything will ever cause your service to run is if your service is exported. Unless you have some special tricks in mind, this means that any app can ask your service to send an SMS. If this gets exploited, your users may come after you, with guns and knives and so forth.
Third, there is no requirement for an Android device to support sending an SMS via ACTION_VIEW, let alone using some undocumented Intent extras. Use ACTION_SEND or ACTION_SENDTO.
it is unable to call the device's build-in sms app.
If you look at LogCat, I am guessing that you will see an error message mentioning that you need to add FLAG_ACTIVITY_NEW_TASK to the Intent to be able to start it from a service. You need to call addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) on the Intent, before calling startService().
That is because popping up an activity in the middle of whatever the user is doing usually is inappropriate. You do not know if the user is doing something with their device, when all of a sudden, your activity takes over the foreground. Users may also come after you with guns and knives for interrupting their game, their movie, their navigation instructions, etc. Hence, you should hire some security guards.
I have include the permission in the manifest file
That is for sending an SMS via SmsManager. You should not need it for ACTION_SEND or ACTION_SENDTO.
I know this is a basic question, I am new to android service. I have done research on Google and StackOverflow. There are many question in stackoverflow related to or similar to my topic, But I couldn't able to get the proper answer and I am being diverted to different topics.
This is the simple test code I am running.
public class Service extends android.app.Service {
private Handler mHandler;
private void ping() {
try {
Log.e("Tag", "Success");
Toast.makeText(getApplicationContext(), "Service Ping", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e("Error", "In onStartCommand");
e.printStackTrace();
}
scheduleNext();
}
private void scheduleNext() {
mHandler.postDelayed(new Runnable() {
public void run() { ping(); }
}, 3000);
}
public int onStartCommand(Intent intent, int x, int y) {
mHandler = new android.os.Handler();
ping();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
In this a Toast message pops up and Log message printed for every 3 seconds, It works even when the app is minimized. But when i completely quit the app, There is no Toast or Log printed. In this SO ANSWER in clearly says why Toast message cannot called without the UI. And I cannot print the LOG as the process is being killed.
Basically, I want the service to run in background for every 5 min and need to get the data from online. How should I implement the service? and any example code or tutorials are appreciated?
When you start a Service, by default it runs in the same process as whatever component started it. When the process that component is running in quits, so too does the Service. In order to start a Service in its own process, you need to do the following in the manifest:
<service
android:name=".Service"
android:enabled="true"
android:exported="false"
android:process=":separate_service_process"
android:stopWithTask="false" >
</service>
Putting a colon in front of the label for the android:process attribute tells the system to start the service in a separate process, and the android:stopWithTask attribute will tell the system to keep the service alive even when the component that started it stops. See http://developer.android.com/guide/topics/manifest/service-element.html for more information on the manifest settings (the stopWithTask attribute is part of the ServiceInfo class).
Now start your service using startService(Intent) and you should be all set. Good luck!
PS--I'd recommend renaming your Service class to something unique to avoid confusion with the base Service class.
In my Android project I have an Activity:
public MyActivity extends Activity{
...
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, MyService.class)
startService(intent);
}
}
In onStart() of MyActivity, I just starts MyService.
My simple service is just used to listen to phone state change:
public MyService extends Service{
#Override
public int onStartCommand(Intent intent, int arg, int id) {
super.onStartCommand(intent, arg, id);
/*register a PhoneStateListener to TelephonyManager*/
startToListenToPhoneState();// show Toast message for phone state change
return START_STICKY;
}
}
Everything works fine, after launch my app, when I make a phone call, my service is listening to phone state change & show toast messages.
NEXT, I decide to unit test my project, so I created a AndroidTestCase in my test project:
public class MySimpleTest extends AndroidTestCase{
...
#Override
protected void runTest() {
//make a phone call
String url = "tel:3333";
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
mContext.startActivity(mIntent);
}
}
The above test case simply starts a phone call, and it works fine too.
I press the HOME button to bring my app to background, after which, I run the test case to start a phone call, I was expecting that the PhoneStateListener in my service would still be running to show me the Toast message, but it didn't.
Then I figured out that I have to either start or bind MyService in my test case too, after which I am able to see the toast message from PhoneStateListener when run my test case, Why is that? I mean Why my service is running in background with my app but I still have to start or bind the service in test case in order to trigger the PhoneStateLister defined in MyService when running a AndroidTestCase?
In Android ServiceTestCase documentation, it says,
The test case waits to call onCreate() until one of your test methods calls startService(Intent) or bindService(Intent). This gives you an opportunity to set up or adjust any additional framework or test logic before you test the running service.
I think AndroidTestCase provides a framework which you can test your activities, services and so on in a controlled environment so that you should at least start your service before you test interacting with your service.
Reference: http://developer.android.com/reference/android/test/ServiceTestCase.html
I have an intentservice that gets qued by the user and by my app automatically. I need to be able to kill all pending intents that are qued when the user logs out of my application, but I cannot seem to get that to work. I have tried stopService() and stopself(), but the intents continue to fire off the intentservice after the user has logged out. I would try to get the id of the intent but that is difficult as everytime the intentservice starts, the variable holding the intent id's is empty. Here is my intentservice code:
public class MainUploadIntentService extends IntentService {
private final String TAG = "MAINUPLOADINTSER";
private GMLHandsetApplication app = null;
private SimpleDateFormat sdf = null;
public boolean recStops = true;
public MainUploadIntentService() {
super("Main Upload Intent Service");
GMLHandsetApplication.writeToLogs(TAG,
"GMLMainUploadIntentService Constructor");
}
#Override
protected void onHandleIntent(Intent intent) {
GMLHandsetApplication.writeToLogs(TAG, "onHandleIntent Started");
if (app == null) {
app = (GMLHandsetApplication) getApplication();
}
uploadData(app);
GMLHandsetApplication.writeToLogs(TAG, "onHandleIntent Finished");
}
#Override
public void onDestroy() {
GMLHandsetApplication.writeToLogs(TAG, "onDestroy Started");
app = null;
stopSelf();
GMLHandsetApplication.writeToLogs(TAG, "onDestroy completed");
}
public void uploadData(GMLHandsetApplication appl) {
//All of my code that needs to be ran
}
Unfortunately, I don't think it's possible to accomplish that with the standard IntentService methods since it doesn't offer a way to interrupt it while it's already going.
There are a few options I can think of that you can try to see if they fit your need.
Copy the IntentService code to make your own modifications to it that would allow you to remove pending messages. Looks like someone had some success with that here: Android: intentservice, how abort or skip a task in the handleintent queue
Instead of copying all the IntentService code, you might also be able to Bind to it like a normal Service (since IntentService extends Service) so you can write your own function to remove pending messages. This one is also mentioned in that link.
Rewrite the IntentService as a regular Service instead. With this option, you'd have more control over adding and removing messages.
I had what sounds like a similar situation where I was using an IntentService, and I eventually just converted it to a Service instead. That let me run the tasks concurrently and also cancel them when I needed to clear them.
Here
When should I free the native (Android NDK) handles? is the HangAroundIntentService class that has the method cancelQueue().
The class also has the method
public static Intent markedAsCancelIntent(Intent intent)
that converts an intent into a cancel intent, and
public static boolean isCancelIntent(Intent intent).
The class is based on the open-sourced Google's code.
Just a thought but inside of your onhandleintent can you have an argument that checks to see if app is running if not then don't run the code? example. In the start of your app you could have a static var
boolean appRunning;
Next in your onhandle of the intent, when you set the appRunning to false, after an onPause or onDestroy of activity, you could wrap the onhandleintent code in a boolean:
protected void onHandleIntent(final Intent intent) {
if(MainActivity.appRunning){
...
}
}
Just a thought