I'm trying to execute a service without an activity, yet ADV emulator seems to not response to my application. As written at the title I would like to have Service applications that will run constantly without UI/activity.
Here is my code:
AndroidManifest.xml:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"></uses-permission>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:label="#string/app_name"
android:icon="#mipmap/ic_launcher"
android:allowBackup="false" >
<service android:name=".service.PublicStartService" android:exported="true" />
</application>
</manifest>
Java File
public class PublicStartService extends Service {
private static final String TAG = "ServiceLog";
// The onCreate gets called only one time when the service starts.
#Override
public void onCreate() {
Log.i(TAG, "onCreate ");
}
// The onStartCommand gets called each time after the startService gets called.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String param = intent.getStringExtra("PARAM");
ExecutorService executorService = Executors.newFixedThreadPool(4);
Runnable worker = new MyRunnable();
executorService.execute(worker);
return Service.START_STICKY;
}
// The onDestroy gets called only one time when the service stops.
#Override
public void onDestroy() {
Log.i(TAG, "onDestroy ");
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
class MyRunnable implements Runnable {
#Override
public void run() {
while (true){
Log.i(TAG, "THREAD THREAD THREAD ");
try {
sleep(500);
} catch (InterruptedException ignored) {
}
}
}
}
}
Any Idea what do it miss to make it execute?
Thanks!
Related
My Job executes perfectly if the app is open but if i close the app the jobservice is never executed. I have followed the tutorial here; Job Scheduler - Code In Flow and it just does not run (or maybe it runs and we do not know it runs?). I have put in notifications and Log.d methods with in my methods so i can see if the job runs and while the app is open the log msgs and notifications push through as expected.
Any help would be appreciated . Thank you
UPDATE 2
===============
I have discovered, since the job runs while the app is open, if i close the app the job gets cancelled without the onStopJob being called. theoretically if i am not wrong job scheduler should continue the job irrespective of the app running or not.
the Log.d msgs looks like this
D/global_PEA: Job Scheduled //Schedule Job Button Pressed
D/global_PEA: Job Started //ExJobService runs
D/global_PEA: run: 0
D/global_PEA: run: 1
D/global_PEA: run: 2
D/global_PEA: run: 3
D/global_PEA: run: 4
// App closed and the output and notifications stop
// in theory it should continue till 9
=======
UPDATE
===============
Here is the adb shell dump of my app. it looks like its scheduled?
I cant get any notification or Log.d msgs when i force run the job from adb like so
adb shell cmd jobscheduler run -f com.raaif.pea 902
which leads me to think that maybe the job does infact run but nothing is shown to the user about it like the notification. Is there any way it could notify the application, even if its openning the app when the job is done?
==============
here are my code files
public class HomeFragment extends Fragment {
private Context mContext;
private Button btn1;
private Button btn2;
#Override
public void onAttach(Context context) {
mContext = context;
super.onAttach(context);
}
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_home, container, false);
btn1 = root.findViewById(R.id.button1);
btn2= root.findViewById(R.id.button2);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
scheduleJob();
}
});
btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cancelJob();
}
});
return root;
}
public void scheduleJob(){
ComponentName componentName = new ComponentName(mContext, ExJobService.class);
JobInfo info = new JobInfo.Builder(JOB_ID_1, componentName)
.setRequiresCharging(false)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setPersisted(true)
.setPeriodic(15 * 60 * 1000)
.build();
JobScheduler scheduler = (JobScheduler) mContext.getSystemService(JOB_SCHEDULER_SERVICE);
int resultcode = scheduler.schedule(info);
if(resultcode==JobScheduler.RESULT_SUCCESS){
Log.d(globals.appTag,"Job Scheduled");
}else{
Log.d(globals.appTag,"Job Scheduling failed");
}
}
public void cancelJob(){
JobScheduler scheduler = (JobScheduler)getContext().getSystemService(JOB_SCHEDULER_SERVICE);
scheduler.cancel(JOB_ID_1);
Log.d(globals.appTag,"Job cancelled");
}
}
And here is my JobService class
import android.app.Notification;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Intent;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import static com.raaif.pea.Constants.CHANNEL_ID_NOTIFICATION_HIGH;
import static com.raaif.pea.Constants.HIGH_NOTIF_ID;
public class ExJobService extends JobService {
private Globals globals = Globals.getInstance();
private boolean jobcancelled = false;
private boolean reschedulestatus = false;
#Override
public boolean onStartJob(JobParameters params) {
Log.d(globals.appTag, "Job Started");
//output low notification
notify("Scheduled JobService", "Starting Background Work");
doBackgroundWork(params);
return true;
}
private void doBackgroundWork(final JobParameters params) {
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 10; i++) {
if (jobcancelled) return;
Log.d(globals.appTag, "run: " + i);
ExJobService.this.notify("Thread Iterator",
String.format("Iteration Count: %d", i));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.d(globals.appTag, "Job Finished");
ExJobService.this.notify("Scheduled JobService", "Background Work Finished");
jobFinished(params, reschedulestatus);
Log.d(globals.appTag, "Job Service Params returned with " + reschedulestatus);
ExJobService.this.notify("Scheduled JobService", "Job Params returned");
}
}).start();
}
#Override
public boolean onStopJob(JobParameters params) {
Log.d(globals.appTag, "Job Cancelled before completion");
jobcancelled = true;
notify("OnStopJob", "Job Cancelled");
return false;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//return Service.START_STICKY;
return super.onStartCommand(intent, flags, startId);
}
public void notify(String title, String content) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
Notification notification =
new NotificationCompat.Builder(ExJobService.this, CHANNEL_ID_NOTIFICATION_HIGH)
.setSmallIcon(R.drawable.ic_memory_black_24dp)
.setContentTitle(title)
.setContentText(content)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setOnlyAlertOnce(false)
.build();
notificationManager.notify(HIGH_NOTIF_ID, notification);
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.raaif.pea">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<!-- SERVICES -->
<service android:name=".ExJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I see here is a problem but i don't know how do you handle it?! look at this:
public class ExJobService extends JobService {
...
private boolean reschedulestatus = false;
#Override
public boolean onStartJob(JobParameters params) {
....
doBackgroundWork(params);
return true;
}
private void doBackgroundWork(final JobParameters params) {
new Thread(new Runnable() {
....
jobFinished(params, reschedulestatus);
....
}).start();
}
}
You are passing false to jobFinished method that unintentionally you do not reschedule the job.
When doing stuff periodically in the background — JobScheduler, WorkManager, AlarmManager etc. — you have to take into account that your process might not be around when it is time for you to do your work. Android will fork a process for you, but it is "starting from scratch". Anything that your UI might have set up in memory, such as a database, would have been for some prior process and might not be set up in the new process.
Currently i am working with an application and my app has a feature that the user will be able to click on a Navigate button and my app will start the Google Map. Till now it's fine and i have done it. But the fact where i am stuck is that i want my app to perform some tasks. To achieve that i have used JobService and scheduled it to run after every 5 seconds even when the app is in background.
When the user presses the back button then inside onDestroy method i have cancelled the scheduler. But when the app is removed from the background by sliding or pressing the cross icon the JobService keeps running as the onDestroy method can be called or not by the os when it is removed from the background. How can i stop the scheduled job when the app is removed from the background?
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="javarank.com.serviceinbackground">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyJobService" android:exported="true" android:permission="android.permission.BIND_JOB_SERVICE" />
</application>
</manifest>
MyJobService class
public class MyJobService extends JobService {
#Override
public boolean onStartJob(final JobParameters jobParameters) {
Toast.makeText(getApplicationContext(), "Doing job", Toast.LENGTH_SHORT).show();
jobFinished(jobParameters, true);
return false;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
return false;
}
}
Here is my MainActivity
public class MainActivity extends AppCompatActivity {
private static final int JOB_ID = 1;
private JobInfo jobInfo;
private JobScheduler scheduler;
private Button navigateButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ComponentName componentName = new ComponentName(this, MyJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, componentName);
builder.setPeriodic(5000);
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
// if true this job exists even after a system reboot...
builder.setPersisted(false);
jobInfo = builder.build();
scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);
navigateButton = (Button) findViewById(R.id.navigate_button);
navigateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
StringBuffer url = new StringBuffer("https://www.google.com/maps/dir/?api=1");
url.append("&origin=23.755736,90.374627");
url.append("&destination=23.754047,90.371682");
url.append("&travelmode=driving");
Uri gmmIntentUri = Uri.parse(url.toString());
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
mapIntent.setPackage("com.google.android.apps.maps");
startActivity(mapIntent);
}
});
}
#Override
protected void onDestroy() {
Toast.makeText(getApplicationContext(), "Destroy called.", Toast.LENGTH_SHORT).show();
scheduler.cancel(JOB_ID);
super.onDestroy();
}
}
I think you need to override following onStop() method and put stopService() command to stop the JobService.
#Override
protected void onStop() {
// A service can be "started" and/or "bound". In this case, it's "started" by this Activity
// and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call
// to stopService() won't prevent scheduled jobs to be processed. However, failing
// to call stopService() would keep it alive indefinitely.
stopService(new Intent(this, MyJobService.class));
super.onStop();
}
You can create a new service like
MyService.java
public class MyService extends Service {
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
//stop you jobservice from here
stopSelf();
}
}
and start it from MainActivity.java
startService(new Intent(MainActivity.this,MyService.class));
Android> 7 automatically saves battery power. You must turn on the application's battery saving stop feature.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Intent intent = new Intent();
String packageName = getPackageName();
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
}
}
add this to AndroidManifest.xml
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
I faced this issue, but I found that after schedule job service, it can't be canceled (From view).
So I turned to stop it inside the job service by calling onStopJob(params)
and it worked.
I am not sure if I have this right or not, but I have some code that I need to run in the background of my android application, and once that is complete, I would like to wait 10 seconds, and then run the code again.
I currently have this working, but I am sure it ain't the right way to go about it and wondered if someone can give me a simple example, or tell me what I need to change to make this "the right way" to do it.
First I have my ScheduleService.java file. This is where my code that I want to run it, and as you can see, once it is finished, it puts the thread to sleep for 10 seconds and then calls itself again, but this means that the code never actually completes (you should see the length of the stack trace if I get an error!)
ScheduleService.java
public class ScheduleService extends Service {
private static final String TAG = "ScheduleService";
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
startJob();
}
});
t.start();
return Service.START_STICKY;
}
private void startJob(){
// all my code is here, and i do what i need
// job completed. Rest for 10 seconds before doing another one
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//do job again
startJob();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy(){
super.onDestroy();
}
}
Now to start the service code, I have the following when my application starts (in my MainActivity.java file)
// stop just encase its already started
context.stopService(new Intent(context, ScheduleService.class));
// start service
context.startService(new Intent(context, ScheduleService.class));
In order to make sure that the service is started when the device restarts, I also have my StartOnBootReciever.java code
public class StartOnBootReciever extends BroadcastReceiver {
private static final String TAG = "Autostart";
/**
* Listens for Android's BOOT_COMPLETED broadcast and then executes
* the onReceive() method.
*/
#Override
public void onReceive(Context context, Intent arg1) {
Log.d(TAG, "BOOT_COMPLETED broadcast received. Executing starter service.");
// upload in background
Intent intent = new Intent(context, ScheduleService.class);
context.startService(intent);
// This code will start the application once the device has been restarted
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
Then in my AndroidManifest.xml file, I have the following
<receiver android:enabled="true" android:exported="true" android:name="StartOnBootReciever" android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<service android:enabled="true" android:exported="false" android:name="com.idamigo.ticketmachine.ScheduleService" />
This all works, but I feel that have code that is self-calling, and "never ending"
In your Service, you have used Thread.Sleep which is unnecessary. Because Service will run continuously in the background until you stop it or System stops it.
Example:
public class ScheduleService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Timer timer = new Timer();
timer.schedule(task,1,10000);
return Service.START_STICKY;
}
TimerTask task= new TimerTask() {
#Override
public void run() {
//do your task here.
}
};
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Go for Service only if you need to run a task continuously in the background. Otherwise, use IntentService. IntentService will be stopped when there is no work for it so you don't need to manage its state by yourself.
I have tried as below to resolve my problem but I have still find problem if remove app from app history service not run.
in my activity:
// start background service by splash screen
startService(new Intent(this, UpdateService.class));
in my manifest:
<application
android:allowBackup="true"
android:icon="#drawable/demo"
android:label="#string/app_name"
android:theme="#style/Theme.AppCompat.Light" >
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity
android:name=".SplashScreen"
android:label="#string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".UpdateService"/>
</application>
in my service :
public class UpdateService extends IntentService {
public UpdateService() {
super("UpdateService");
}
Handler mHandler = new Handler();
int Updatevalue = 0;
Context gContext= this;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Let it continue running until it is stopped.
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
// 10 sec
Thread.sleep(5000);// 1000*60= 1 min ;;; 1000 = 1 sec ;;; 1000*60*2= 2 min
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(gContext, "Service running", Toast.LENGTH_LONG).show();
// web service implement for 2 min updating...
}
});
} catch (Exception e) {
}
}
}
}).start();
return START_STICKY;
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
#Override
protected void onHandleIntent(Intent intent) {
// Let it continue running until it is stopped.
Toast.makeText(this, "Service Started in handle Intent",
Toast.LENGTH_LONG).show();
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
// 10 sec
Thread.sleep(5000);// 1000*60= 1 min ;;; 1000 = 1 sec ;;; 1000*60*2= 2 min
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(gContext, "Service running in handle Intent ",
Toast.LENGTH_LONG).show();
// web service implement for 2 min updating...
}
});
} catch (Exception e) {
}
}
}
}).start();
}
}
I want as a what'up feature if we don't open app then we receives notification of what'up. so I need this functionality with webservice . this will be run in background for receive any data from webservice in JSON format.
I got it's solution by changes in manifest:
<service android:name=".UpdateService" >
</service>
and add super keyword in "onStartCommand" method like :
super.onStartCommand(intent, startId, startId);
and changes retuirn of "onStartCommand" method like :
return START_REDELIVER_INTENT;
thanks
UPDATE:
After adding the suggested methodes (doBindService() and doUnbindService()) along with calls to no avail) From here suggested by #Nick Campion
I've been trying for a while to get this service running but nothing seems to be working - I know I'm probably missing a semicolon or something :)
The program calls startNotificationService(), then the Log shows the log message... and the app continues to run without the Service showing up. I can't find the Service in Advance Task Killer. HELP!!!
XML (In Manifest) :
<service
android:icon="#drawable/icon"
android:label="Smart Spdate Service"
android:name="notifyService">
<intent-filter
android:label="FULL_PATH_NAME_HERE.updateService">
</intent-filter>
</service>
Service Call
Log.v("NOTICE", "Notification Service was not found running - starting");
//startService(new Intent(this, notifyService.class));
startService(new Intent(notifyService.class.getName()));
//startService(new Intent(TweetCollectorService.class.getName()));
/* FROM GOOGLE */
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).
this.bindService(new Intent(this, updateService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
/* END OF GOOGLE CODE */
#Override
public void onDestroy() {
web.close();
doUnbindService(); // Added to `onDestroy` - suggested by Google page
super.onDestroy();
Log.v("NOTICE", "PROGRAM TERMINATED");
}
updateService.java
public class updateService extends Service {
private String TAG = "SERVICE";
public static final int INTERVAL = 60000;
private Timer timer = new Timer();
private static updateService Pointer;
public updateService() {
Pointer = updateService.this;
}
public static class LocalBinder extends Binder {
static updateService getService() {
return Pointer;
}
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
if (timer != null) {
timer.cancel();
}
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId) {
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
doStuff();
}
}, 0, INTERVAL);
super.onStart(intent, startId);
}
public void doStuff() {
Log.v(TAG, "doStuff");
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IBinder mBinder = new LocalBinder();
}
I don't see anywhere where your client binds to your service. Take a look at the local service example.. The reason for using the bind pattern even though you call startService is because the startService call is asynchronous. You need to make an additional call to bind the service to make sure you get a call back once the startup is complete.
I've found that a really great example of a service client and service are available in the NPR Open Source App for you to learn from!