Android, prevent to kill service/thread - android

how can i prevent this service with thread to dont be killed from android, i need this notifications always runnig, but when is mobile locked, nothing will happen. I think android kill service or thread or something like that
MainActivity in onCreate
startService(new Intent(this, NotifyService.class));
My service
public class NotifyService extends Service {
private DatabaseOp mDbHelper;
public Vibrator vibrator;
String username;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate ()
{
mDbHelper = new DatabaseOp(this);
final boolean cyklus = true;
Thread vlakno = new Thread (new Runnable()
{
#Override
public void run()
{
while (cyklus)
{
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String sysDate = getSysDate();
String sysDate2 = getSysDate2();
String time = getSysTime();
mDbHelper.open();
Log.v( "sysDate", sysDate );
Cursor cursorU = mDbHelper.fetchUlohaS(0, sysDate);
if (cursorU.getCount() > 0)
{
String idU = cursorU.getString(cursorU.getColumnIndexOrThrow(DatabaseOp.KEY_ID));
String dbDateU = cursorU.getString(cursorU.getColumnIndexOrThrow(DatabaseOp.KEY_DATE));
String menoU = cursorU.getString(cursorU.getColumnIndexOrThrow(DatabaseOp.KEY_NAZOV));
String mHodina = getResources().getString(R.string.cas)+" "+cursorU.getString(cursorU.getColumnIndexOrThrow(DatabaseOp.KEY_HODINA));
Log.v( "task", dbDateU+"/"+sysDate );
if (dbDateU.equals(sysDate))
{
Notify(menoU, mHodina, idU, 0);
}
}
Cursor cursorS = mDbHelper.fetchSviatokS(3, sysDate2);
if (cursorS.getCount() > 0)
{
String idS = cursorS.getString(cursorS.getColumnIndexOrThrow(DatabaseOp.KEY_ID));
String dbDateS = cursorS.getString(cursorS.getColumnIndexOrThrow(DatabaseOp.KEY_DATUM));
String menoS = cursorS.getString(cursorS.getColumnIndexOrThrow(DatabaseOp.KEY_NAZOV));
if (dbDateS.equals(sysDate2) && time.equals("09:00"))
{
Notify(menoS,getResources().getString(R.string.title_section4), idS, 3);
}
}
mDbHelper.close();
}
}
});
vlakno.start();
}
}

Have you tried to use ForgroundService?
Checkout this repo for an example - https://github.com/supercurio/foreground-service-sample-app

I think you should consider AlarmManager. See http://developer.android.com/reference/android/app/AlarmManager.html.

To tip the system to keep your Service alive as long as possible (i.e. before RAM is very short or user kills the service by hand through application info screen), you need to run it as a foreground service -- by using startForeground() method.
If you're looking for a way to run when the device is turned off, read the Keeping The Device Awake training page and consider using AlarmManager instead as suggested by #khris if your task is not very critical in terms of timing precision.

Related

How to queue multiple tasks in a foreground service, so that they execute one by one?

public class CopyService extends Service {
private List<CustomFile> taskList;
private AsyncTask fileTask;
#Override
public void onCreate() {
super.onCreate();
taskList = new ArrayList<>();
fileTask = new fileTaskAsync();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String filePath = intent.getStringExtra("filePath");
String fileType = intent.getStringExtra("fileType");
String taskType = intent.getStringExtra("taskType");
String fileName = intent.getStringExtra("fileName");
CustomFile customFile = new CustomFile();
customFile.filePath = filePath;
customFile.fileType = fileType;
customFile.taskType = taskType;
customFile.fileName = fileName;
taskList.add(customFile);
Notification notification = getNotification();
startForeground(787, notification);
if (fileTask.getStatus() != AsyncTask.Status.RUNNING) {
CustomFile current = taskList.get(0);
taskList.remove(current);
fileTask = new fileTaskAsync().execute(current);
}
stopSelf();
return START_NOT_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private class fileTaskAsync extends AsyncTask<CustomFile, Void, String> {
#Override
protected String doInBackground(CustomFile... customFiles) {
CustomFile customFile = customFiles[0];
FileUtils.doFileTask(customFile.filePath, customFile.fileType,
customFile.taskType);
return customFile.fileName;
}
#Override
protected void onPostExecute(String name) {
sendResult(name);
if (!taskList.isEmpty()) {
CustomFile newCurrent = taskList.get(0);
taskList.remove(newCurrent);
fileTask = new fileTaskAsync().execute(newCurrent);
}
}
}
private void sendResult(String name) {
Intent intent = new Intent("taskStatus");
intent.putExtra("taskName", name);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
I need to execute multiple tasks in a service one by one. Task is either copying or moving local files. Suppose, user is copying a big file and he wants to copy or move other files. I need the subsequent tasks to be queued and exected one by one.
Currently, I'm creating a list inside the service and running an async task. In onPostExecute, I check for remaining tasks in the list and start the async task again from there. As shown in the code.
But, I'm concerned about memory leaks. And I'm very new to programming so, I don't know what's the best practice in such situations.
I can't use IntentService, because I want the task to continue even if the user hits home button to open some other app.
AS I said in the comments, I think your solution is reasonable. A Foreground Service is a good candidate for long running work that needs to be executed immediately, and from your description your file copying task matches that criteria.
That said, I don't believe AsyncTask is a good candidate for your problem. AsyncTasks are best deployed when you need to do some quick work off the main thread, in the order of a few hundred milliseconds at most, whereas your copy task could presumably take several seconds.
As you have multiple tasks to complete which aren't directly dependent on one another, I would recommend you make use of a thread pool to conduct this work. For that you can use an ExecutorService:
public class CopyService extends Service {
private final Deque<CustomFile> tasks = new ArrayDeque<>();
private final Deque<Future<?>> futures = new LinkedBlockingDequeue<>();
private final ExecutorService executor = Executors.newCachedThreadPool();
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//May as well add a factory method to your CustomFile that creates one from an Intent
CustomFile customFile = CustomFile.fromIntent(intent);
tasks.offer(customFile);
//...Add any other tasks to this queue...
Notification notification = getNotification();
startForeground(787, notification);
for(CustomFile file : tasks) {
final Future<?> future = executor.submit(new Runnable() {
#Override
public void run() {
final CustomFile file = tasks.poll();
//Ddo work with the file...
LocalBroadcastManager.getInstance(CopyService.this).sendBroadcast(...);
//Check to see whether we've now executed all tasks. If we have, kill the Service.
if(tasks.isEmpty()) stopSelf();
}
});
futures.offer(future);
}
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
//Clear pending and active work if the Service is being shutdown
//You may want to think about whether you want to reschedule any work here too
for(Future<?> future : futures) {
if(!future.isDone() && !future.isCancelled()) {
future.cancel(true); //May pass "false" here. Terminating work immediately may produce side effects.
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
This shouldn't cause any memory leaks, as any pending work is destroyed along with the Service.

how to stop a service running multiple instance?

I am developing a android app, which will update device location after 4 seconds interval and depending on the response received from the server it will open specific activity.
Problem 1) In some case it will open up a activity like incoming phone call with sound. I am facing problem when I am removing the app from recent app. I noticed the poll function is running twice at the same time, and multiple media is playing at the same time.
Problem 2) I am using Service intead of IntentService(I am a beginner and not sure which will be better). The background service should run even the phone goes to sleep mode, just like WhatsApp or other messenger run.
As the file is big enough, I am attaching only important part
public class TaxiNorrService extends Service implements LocationListener {
...
...
final Handler poll_handler = new Handler();
private NotificationManager mNM;
private final Actions actions = new Actions();
public Ringtone r;
private String newtext;
private Runnable BreakRunnable;
private Runnable poll_runnable;
private Handler BreakHandler;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
poll_runnable = new Runnable() {
#Override
public void run() {
if(!App.isAutoBreak()){
if(BreakHandler !=null){
BreakHandler.removeCallbacks(BreakRunnable);
}
if(r != null) {
if (r.isPlaying()) {
r.stop();
}
}
}
if (actions.checkPermission(getApplicationContext())) {
checkGPS();
if(isNetworkAvailable()){
if(App.isPollOn()){
poll(latitude, longitude);
}
}else{
if(BreakHandler !=null){
BreakHandler.removeCallbacks(BreakRunnable);
}
boolean foregroud = false;
try {
foregroud = new ForegroundCheckTask().execute(getApplication()).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
boolean background = isMyServiceRunning(TaxiNorrService.class);
if(foregroud == true && background == true && App.isAppForground()){
if(!App.isLoadingVisible()){
Intent intent = new Intent(TaxiNorrService.this, Loading_activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}
}
poll_handler.postDelayed(this, 4000);
}
};
return Service.START_STICKY;
}
private void poll(double lat, double lon){
//Connected to API endpoint
}
...
...
#Override
public void onDestroy() {
if(r != null) {
if (r.isPlaying()) {
r.stop();
}
}
poll_handler.removeCallbacks(poll_runnable);
super.onDestroy();
}
}
I found the answer for my questions. The code written in the onStartCommand should be within onCreate function. This is because onCreate will execute when service starts first time, and onStartCommand will execute every time when you start the app. Please follow this topic,
Android - running a method periodically using postDelayed() call

How can I periodically run a service/thread in background even when the screen is locked?

I'm working on an app that can check web data every half an hour and I need to ensure it keeps running as long as the power is on.
For now, the structure of my app is like this:
main_activity:
AlarmManager in onCreate()
alarm_receiver:
start_service
acquire partial_wl for the service
service:
get network data using StrictMode
pop activity_2 if the data is expected
activity_2:
vibration
button to exit(activity_2.this.finish())
But in testing I find the service will stop(be killed) after the first 30 mins. In addition, if I start a thread for networking in service instead of using StrictMode, it will be killed in 5mins after the screen is locked.
Hope someone could give a suggestion for this. It's truly disturbing.
Many thanks.
common service lives no metter what is happen with activity. if you want it start periodically check out mine service:
https://bitbucket.org/kvrus/ocs-android/raw/036de7f0d3579b2a193bcb82309f7f82819508e6/app/src/main/java/koss/ru/oneclickrate/network/EcbEuropeService.java
/**
* Loads exchange rates form network periodically
* Returns results in broadcast message.
* Created by koss on 19.02.16.
* */
public class EcbEuropeService extends Service {
public static final String ECB_URL = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
public static final int UPDATE_PERIOD = 30000;
public static final int UPDATE_TICK = 1000;
public static final String NOTIFICATION = "koss.ru.oneclickrate.receiver";
public static final String EXTRA_CURRENCIES_MAP = "extra_currencies_map";
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
getUrlData();
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
public Cubes getUrlData() {
(new AsyncTask<Object, Object, Cubes>() {
Map<CurrencyType, BigDecimal> result = new EnumMap<CurrencyType, BigDecimal>(CurrencyType.class);
#Override
protected Cubes doInBackground(Object... params) {
Cubes cubes = new Cubes();
InputStream is = null;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(ECB_URL);
urlConnection = (HttpURLConnection) url.openConnection();
is = urlConnection.getInputStream();
cubes = EcbEuropeResponseParser.parse(is);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(urlConnection!=null) IOUtils.close(urlConnection);
if(is!=null) IOUtils.closeQuietly(is);
return cubes;
}
}
#Override
protected void onPostExecute(Cubes map) {
super.onPostExecute(map);
sendBroadcastMessage(map);
startTimer();
}
}).execute();
return null;
}
/**
* Restarts timer
* */
public void startTimer() {
cdt.cancel();
cdt.start();
}
CountDownTimer cdt = new CountDownTimer(UPDATE_PERIOD, UPDATE_TICK) {
#Override
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
getUrlData();
}
};
private void sendBroadcastMessage(Cubes currenciesMap) {
Intent intent = new Intent(NOTIFICATION);
intent.putExtra(EXTRA_CURRENCIES_MAP, currenciesMap);
sendBroadcast(intent);
}
I have changed a few things and it works well now.
1.As my phone is 4.4.2(api=19), alarmmanager.setrepeating is inexact. So I turn to use .setExact (new method of .set()) and reschedule the alarm at the end of AsyncTask(network) in Service.
2.Make wakelock instance global, acquiring it in AlarmReceiver and releasing at the end of the AsyncTask. I used to put .release() in onDestroy() which releases the lock before the task is done.
3.There is a setting about protected-background applications in my phone and I didn't turn it on. That can allow system kill the application and disable the alarm manager.

Application skipping 600 frames

so im building this service for a application locker. it runs fine for the most part.but when i try to run the service to lock my own application(ie the app locker itself) there's a lag for like 4-5 seconds and then the lock activity launches. The logcat displays that it has skipped 600 frames and is doing too much work on the main thread. can anyone tell him how do i fix this or optimize this code
the AppActivities contains the name of activities that are to be ignored from launching the locker again when they are on top of the stack.eg the lockscreen activity to be shown to the user. The allowedapp is the last app verified by the user
public class LockerService extends Service {
String LockedApps[];
String allowedapp = null;
DataBaseHandler handler;
Intent pwdIntent = null;
ActivityManager am;
String[] AppActivities = { "com.packagename.Locker",
"com.packagename.Compare_Pattern",
"com.packagename.Captcha_Verfication",
"com.haibison.android.lockpattern.LockPatternActivity" };
private final static Handler servicehandler = new Handler() {
#Override
public void handleMessage(Message msg) {
}
};
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
handler = new DataBaseHandler(this);
am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
pwdIntent = new Intent(LockerService.this, Locker.class);
pwdIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
private Runnable checkforeground = new Runnable() {
public void run() {
handler.open();
LockedApps = handler.getPackages();
handler.close();
String packname = am.getRunningTasks(1).get(0).topActivity
.getPackageName();
String activityname = am.getRunningTasks(1).get(0).topActivity
.getClassName();
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(LockerService.this);
allowedapp = sp.getString("allowedapp", "anon");
// check if top application is mylocker application
if ((packname.equals("com.packagename"))
&& (allowedapp.equals("com.packagename"))) {
// do nothing
}
// check if top application is mylocker application and prevent relaunching the lockeractivity every 1.5 seconds
else if ((packname.equals("com.packagename"))
&& !(Arrays.asList(AppActivities).contains(activityname))) {
try {
Editor edit = sp.edit();
edit.putString("current_app", packname);
edit.commit();
startActivity(pwdIntent);
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if ((Arrays.asList(LockedApps).contains(packname))
&& (allowedapp.equals(packname))) {
// do nothing
} else if ((Arrays.asList(LockedApps).contains(packname))) {
Editor edit = sp.edit();
edit.putString("current_app", packname);
edit.commit();
startActivity(pwdIntent);
}
servicehandler.postDelayed(this, 1500); // 1.5 seconds
}
};
#Override
public void onStart(Intent intent, int startId) {
servicehandler.removeCallbacks(checkforeground);
servicehandler.postDelayed(checkforeground, 1500);// 1.5 second
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
servicehandler.removeCallbacks(checkforeground);
stopSelf();
}
}
first of all as Gabe mentioned, a runnable runs on the main Thread.To solve the frames issue You'll need to create another new thread to run your code in the background.
Try this initialize executorService and LcThread and a boolean running_statusin your service.
The running_status variable is used to break the while loop of your thread so that stops looping in the back
#Override
public void onStart(Intent intent, int startId) {
running_status = true;
executorService = Executors.newSingleThreadExecutor();
servicehandler.removeCallbacks(LcThread);
LcThread = new LockerThread();
executorService.submit(LcThread);
}
create the following class
class LockerThread implements Runnable {
#Override
public void run() {
while(running_status){
//copy code from your old Runnable run method here
}
}
}
next modify the onDestroy method
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (executorService != null) {
executorService.shutdown();
}
running_status = false;
servicehandler.removeCallbacks(LcThread);
stopSelf();
}
hope this solves your problem
A runnable still happens on the main thread. Services do not have their own thread by default, they run on the UI thread. If you want to do heavy processing in a service, you need to use a Thread or AsyncTask, so the processing does not occur on the UI thread.

Android: How to restrict specific apps

In my app, I need to block sms, email and phone. I am not detecting for incoming or outgoing calls or sms. Simply, I have a service which will run in background and check if any of three processes is running. If they are running then my activity will open up when user clicks on dialer or sms app. So far, what I have tried, I am posting below:
Service Class
public class DialerService extends Service {
ActivityManager am;
List<RunningAppProcessInfo> mAppProcessInfosList;
private Runnable myRunnable;
boolean threadDone = true;
Handler mHandler;
boolean isLockedAppRunning = false;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
public void onCreate() {
am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
mAppProcessInfosList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
mHandler = new Handler();
Log.v("Dialer Service", "onCreate called");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
myRunnable = new Runnable() {
#Override
public void run() {
isRestrictedAppRunning();
}
};
new Thread(new Runnable() {
public void run() {
while (threadDone) {
try {
mHandler.post(myRunnable);
} catch (Exception e) {
}
}
}
}).start();
return START_STICKY;
}
private void isRestrictedAppRunning() {
mAppProcessInfosList = am.getRunningAppProcesses();
for (int i = 0; i < mAppProcessInfosList.size(); i++) {
if (mAppProcessInfosList.get(i).processName
.equals("com.android.phone")
|| mAppProcessInfosList.get(i).processName
.equals("com.android.email")
|| mAppProcessInfosList.get(i).processName
.equals("com.android.mms")) {
isLockedAppRunning = true;
Intent dialogIntent = new Intent(getBaseContext(),
TestActivity.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(dialogIntent);
}
}
}
#Override
public void onDestroy() {
super.onDestroy();
this.threadDone = false;
}
}
This code is working but it has following issue:
It blocks all the apps, while my requirement is to restrict only those apps which I have listed to block. For e.g., if I am blocking phone and sms, my activity should open only on click of dialer and sms app, and not when I click on maps.
I am not getting how to do this.
When you detect that your blacklisted app is coming up, you need to bring down the running activity. A background service/thread will best handle the activity monitor. There are other internal methods using IActivityWatcher but the internal interface and related hidden APIs are subject to deprecation. I believe it is already deprecated in JB.

Categories

Resources