I am making an app where you run a thread in a service and it checks the current foreground package using this library
Service Code:
public class CheckService extends Service {
long startTime;
long stopTime;
boolean shouldRun = true;
private static final String TAG = "CheckService";
final AppChecker appChecker = new AppChecker();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
Runnable runnable = new Runnable() {
#Override
public void run() {
Log.v(TAG,"Thread is still running");
while(shouldRun){
Log.v(TAG,"Process running is "+ appChecker.getForegroundApp(getApplicationContext()));
if (System.currentTimeMillis() - startTime >= stopTime){
shouldRun = false;
stopSelf();
return;
}
try{
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
#Override
public int onStartCommand(Intent intent, int flags, final int startId) {
startTime = System.currentTimeMillis();
stopTime = intent.getLongExtra("stop-time",0);
if (stopTime == 0){
stopSelf();
}else{
Log.v(TAG," Thread is started at "+ String.valueOf(startTime));
new Thread(runnable).run();
}
return Service.START_NOT_STICKY;
}
#Override
public void onDestroy() {
Log.v(TAG,"Service is destroyed");
super.onDestroy();
}
}
Basically, I want the thread to run for a given duration given by the user.
When the thread stops after the given duration is over, my app crashes while showing this error
01-10 17:26:08.541 23317-23317/com.sriram.donotdisturb I/Choreographer:
Skipped 1207 frames! The application may be doing too much work on its
main thread.
01-10 17:26:08.567 23317-23324/com.sriram.donotdisturb I/art: Wrote
stack traces to '/data/anr/traces.txt'
Most of the code is in the thread. Where am I going wrong??
you should use start instead of run. run executes the run method. You need to use start() for the thread to begin is execution. Alternatively you can use an IntentService, that is already able to handle asynchronous requests
Related
I am using Job Scheduler API in my app to schedule a job for me after specific time interval. It runs fine when the app is running. But whenever the user closes the app or clears it from the recent task list the app stops and the scheduled job never executes afterwards until you open the app and it is rescheduled again from the time it is opened.
Now i want someone to help me to keep the jobs on executing even if the app is closed or cleared from the recent task list.
If there is any alternative solution please tell me.
i am looking for the solution from the past 3 days. Tried everything said by developers on StackOverFlow and other sites and none of them worked for me.
This is where is schedule the job!
ComponentName componentName = new
ComponentName(getActivity().getBaseContext(),WallpaperJobService.class);
JobInfo jobInfo = new JobInfo.Builder(777,componentName)
.setRequiresCharging(sharedPreferences.getBoolean("Charging",false))
.setRequiredNetworkType(sharedPreferences.getBoolean("Wifi",false) ?
JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY)
.setPeriodic(sharedPreferences.getInt("Duration",15) * 60 *
1000)
.setPersisted(true)
.build();
JobScheduler scheduler = (JobScheduler)
getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);
My Job Service Class:
public class WallpaperJobService extends JobService {
private boolean jobCancelled;
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;
#Override
public boolean onStartJob(JobParameters params) {
Log.i("WallpaperJobService", "Job started!");
changeWallpaper(params);
return true;
}
private void changeWallpaper(final JobParameters params) {
final ArrayList<Image> images = (ArrayList<Image>)
MainActivity.favoritesRoomDatabase.roomDao().getAllFavoriteWallpapers();
sharedPreferences = getSharedPreferences("GridSize", MODE_PRIVATE);
editor = sharedPreferences.edit();
if (images != null && images.size() != 0) {
if (sharedPreferences.getInt("Index", 0) == images.size()) {
editor.putInt("Index", 0);
editor.commit();
}
Picasso.get().load(Constants.domain +
images.get(sharedPreferences.getInt("Index", 0)).getImage_url()).into(new
Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap,
Picasso.LoadedFrom from) {
new Thread(new Runnable() {
#Override
public void run() {
if (jobCancelled) {
Log.i("WallpaperJobService","Returned");
return;
}
try {
//Doing some work here
} catch (IOException e) {
e.printStackTrace();
}
Log.i("WallpaperJobService", "Job finished!");
jobFinished(params, false);
}
}).start();
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable)
{
Log.i("WallpaperJobService", "Bitmap load failed " +
e.getMessage());
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
} else {
Log.i("WallpaperJobService", "Favorite database is null!");
}
}
#Override
public boolean onStopJob(JobParameters params) {
Log.i("WallpaperJobService", "Job cancelled before completion!");
jobCancelled = true;
return true;
}
}
When doing stuff periodically in the background — JobScheduler, WorkManager, AlarmManager, FCM push messages, 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.
Yesterday and today I tried to solve the problem from my service. I read lots of topics about this problem (when i want unstopable timer every 15s) but i don't find any solution.
First i try asynch task and service which are nevertheless implement WakeLock still pause when I disconnect the charger. In this topic i read that is no chance to do this in Service. (Here)
Now i try the AlertManager but i read that from some version of android don work repeting in small intervals.
My questions here is, How can i do this (15s interval which can be run always (sleep mode, no on charge etc..)) and android don't be stop this task. I need regular renewal every 15 seconds in all circumstances.
Someone help me how to do this?
Thank
My service on create
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakelock= pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getCanonicalName());
wakelock.acquire();
runnable = new Runnable() {
public void run() {
while(true) {
if (!running) return;
if (updateVillages()) {
result = true;
if (isNewVillage()) {
if (isNotificationEnable) doNotificate();
}
System.out.println("Prebehlo overovanie");
} else {
result=false;
System.out.println("Není internetové pripojenie");
}
updateUI();
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread= new Thread(runnable);
thread.start();
I am Referring this Application https://github.com/hzitoun/android-camera2-secret-picture-taker.
In this Application there are two classes(APictureCapturingService.java & PictureCapturingServiceImpl.java) that takes pictures without preview can these two classes be converted to Background Service that runs always never dies.
Is this possible to have camera capturing process as a background service if yes how to proceed?
I don't know how you are taking picture in your activity but i can guide you to run your app in background even your close your app and you can able to run your camera code in every second..
public class SampleService extends Service {
public SampleService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return null;
}
#Override
public int onStartCommand(final Intent inten, int flags, int startId) {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
// Make use your method here..
}
});
}
}, 5000, 2000);
return super.onStartCommand(inten, flags, startId);
}
#Override
public void onCreate() {
super.onCreate();
}}
And you need to start the service form activity..
startService(new Intent(this, SampleService.class));
I have used this for monitoring the foreground app it will work..
I write a method on service to run every x seconds. But there are some problems.
What I did is
public class noti extends Service {
Context mcont;
private Handler myhandler ;
private long RETRY_TIME = 15000;
private long START_TIME = 2000;
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onStart(Intent intent, int startId) {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mcont=this;
myhandler= new Handler();
myhandler.postDelayed(myRunnable, START_TIME);
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
try {
myhandler.removeCallbacks(myRunnable);
} catch (Exception e) {
// TODO: handle exception
}
}
private Runnable myRunnable = new Runnable() {
public void run() {
try {
new get_notifyalert_service(mcont).execute("") ;
} catch (Exception e) {
// TODO: handle exception
}
myhandler.postDelayed(myRunnable, RETRY_TIME);
}
};
}
this is the right way?
on the phone when I check the settings->apps->running-apps it says sometimes restarting and it took long time
thanks in advance
I see two problems in your solution:
First: Your commands will indeed be activated periodically, but they will do so on the main thread. In many cases, maybe most, you want your periodical processing to run on a separate thread.
if that is what you want, a timer will be a better option:
t = new Timer();
task = new TimerTask() {
#Override
public void run() {
// do periodical action <-------------
}
};
t.scheduleAtFixedRate(task, 0, 1000);
Second: your service will, sooner or later, be reclaimed by Android, stopping the periodical
processing.
For many apps this is not a real problem. You do not really want your background logic running all the time.
If that is not the case for you, declare your service as a foreground service (i.e. guaranteed not to be killed by Android):
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
..Or, at minimum, set it to be sticky:
public class StickyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_NOT_STICKY;
}
}
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!