I have created a Android service where I am finding out the process which are in Error state and the usage stats of app from UsageStatManager. When I run this service then it executes the methods in it once and I want to do a periodic check of the process in error state and the usage stats of apps.
One way I thought of was to implement a while loop with a Thread.sleep() for the time I would like to check my statistics but wondering if there is any other way of doing this in a much better way as placing a while loop may use CPU consumption. Any ideas would be helpfull.
My code:
public class Senddata_1 extends Service {
private String ip = "85.228.204.209";
private int port = 5000;
String message;
String file;
String TAG = "Senddata_1";
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("M-d-yyyy HH:mm:ss");
public void find_out_process_in_error_state(){
/*Some code to find out process in error state*/
return;
}
private UsageStatsManager getUsageStatsManager(Context context){
UsageStatsManager usm = (UsageStatsManager) context.getSystemService("usagestats");
return usm;
}
public List<UsageStats> getUsageStatsList(Context context){
List<UsageStats> usageStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,startTime,endTime);
return usageStatsList;
}
public void printUsageStats(List<UsageStats> usageStatsList){
}
#Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "Inside service Senddata_1");
find_out_process_in_error_state();
printUsageStats(getUsageStatsList(Senddata_1.this));
new Thread(new Senddata_1.ClientSend()).start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
// return;
}
public class ClientSend implements Runnable {
}
}
you can use Timer and in there set time to start service and run function
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//start service here
}
}, 0, mTimeRate);
mTimeRate will be in milliseconds
Related
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.
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.
I'm trying to call a service class from another service class but I get this error:
android.content.Context.getPackageName() on a null object reference
Do you know how I call service from another service?
When I setup my app to phone first, a broadcastreceiver is starting Alarm class and in Alarm class, I want to start another service in ReadGmail() method. But I get that null object reference error.
Here is my code:
public class Alarm extends Service {
private String userName;
private String password;
private String receivingHost;
Context context;
public int onStartCommand(Intent intent, int flags, int startId) {
final Handler handler = new Handler();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String senderPassword=new String("password");
String senderUserName=new String("username#gmail.com");
Alarm newGmailClient=new Alarm();
newGmailClient.setAccountDetails(senderUserName, senderPassword);
newGmailClient.readGmail();
}
});
}
};
Timer timer = new Timer();
timer.schedule(doAsynchronousTask, 10, 120000);
return super.onStartCommand(intent, flags, startId);
};
public void setAccountDetails(String userName,String password){
this.userName=userName;//sender's email can also use as User Name
this.password=password;
}
public void readGmail(){
this.receivingHost="imap.gmail.com";//for imap protocol
Properties props2=System.getProperties();
props2.setProperty("mail.store.protocol", "imaps");
Session session2=Session.getInstance(props2, null);
try {
Store store=session2.getStore("imaps");
store.connect(this.receivingHost,this.userName, this.password);
Folder folder=store.getFolder("INBOX");//get inbox
folder.open(Folder.READ_ONLY);//open folder only to read
Message message[]=folder.getMessages();
String key= "Hey";
String subject;
for(int i=0;i<message.length;i++){
System.out.println(message[i].getSubject());
subject=message[i].getSubject();
if(subject.equals(key)){
System.out.println("inside");
Intent mTutorial = new Intent(Alarm.this, LaunchActivity.class);
this.startService(mTutorial);
//I want to call service class in here. LaunchActivity is my service class.
}
//Log.d(message[i].getSubject(),message[i].getSubject());
}
folder.close(true);
store.close();
} catch (Exception e) {
System.out.println(e.toString());
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.d("", "FirstService destroyed");
}
}
This is your problem:
Alarm newGmailClient=new Alarm();
Your Alarm class extends Service. It is an Android Service. You cannot create an instance of an Android component with new. Only Android can create Android components. If you want to start a Service, you call startService.
Why do you want to start another Service? Please explain.
Use an interface your Service will use to communicate events:
public interface ServiceCallbacks {
void doSomething();
}
I want to check some web API and do something per x minutes. I think I should write a service on Android (is there any other solution?).
But how can do that?
I am thinking about writing a service class and in the manifest file I should add this line:
<service
android:name="com.xx.yy.noti_check"
android:enabled="true"
>
</service>
And in my noti_check class I check my web API like this on onStartCommand:
public class noti_check 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 Service.START_STICKY;
}
#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(mcont).execute("") ;
}
catch (Exception e) {
// TODO: handle exception
}
myhandler.postDelayed(myRunnable, RETRY_TIME);
}
};
}
Is this is the right way?
Is this the right way?
No. Only have a service running when it is actively delivering value to the user. Watching the clock tick is not actively delivering value to the user. Use AlarmManager for periodic work like this.
Below given code is written to track battery level of device and store it in db. In order to get battery level, function "batterylevel" is called every 3 minutes, and battery level is inserted to db table. And also code saves the time, when device gets full charged, in another db table. Everything works fine for some time. But problem occurs after about 30 minutes, the running service automatically enters to its oncreate method, after that service won't show any logs, eventually service stops causing force close while trying to stop the service manually.
public class BatteryLevelService extends Service {
BroadcastReceiver batteryLevelReceiver;
Timer t ;
Calendar cal;
Date lastBatteryFullTime;
Context context;
int sec;
int lastFullChargeYear,lastFullChargeMonth,lastFullChargeDay;
int lastFullChargeHour,lastFullChargeMinute,lastFullChargeSecond;
private File dir;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate(){
Log.d("Service", "oncreate Service Started");
}
private void batteryLevel() {
cal=Calendar.getInstance();
long currentHour=cal.get(Calendar.HOUR_OF_DAY);
long currentMinute=cal.get(Calendar.MINUTE);
long currentSecond=cal.get(Calendar.SECOND);
final String currentTime=currentHour+" : "+currentMinute+" : "+currentSecond;
Intent batteryIntent = registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int rawlevel = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
int level = -1;
if (rawlevel >= 0 && scale > 0) {
level = (rawlevel * 100) / scale;
}
MainActivity.sqladp.insertBatteryLevel(level, currentTime);
if(level==100){
cal=cal.getInstance();
lastFullChargeYear=cal.get(Calendar.YEAR);
lastFullChargeMonth=cal.get(Calendar.MONTH);
lastFullChargeDay=cal.get(Calendar.DAY_OF_MONTH);
lastFullChargeHour=cal.get(Calendar.HOUR_OF_DAY);
lastFullChargeMinute=cal.get(Calendar.MINUTE);
lastFullChargeSecond=cal.get(Calendar.SECOND);
lastBatteryFullTime=new Date(lastFullChargeYear, lastFullChargeMonth, lastFullChargeDay, lastFullChargeHour, lastFullChargeMinute);
String[] lastFullChargeTime=lastBatteryFullTime.toString().split("GMT");
MainActivity.sqladp.deleteLastFullBattery();
MainActivity.sqladp.insertLastUsage("Battery", "", lastFullChargeTime[0], "");
}
Log.d("Battery level", ""+level + "%");
}
#Override
public void onStart(Intent intent, int startId) {
Log.d("Service", "Service Started");
t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//Called each time when 1000 milliseconds (1 second) (the period parameter)
batteryLevel();
Log.d("", "batlevel ");
}
},
//Set how long before to start calling the TimerTask (in milliseconds)
0,
//Set the amount of time between each execution (in milliseconds)
3*60*1000);
}
#Override
public void onDestroy() {
Log.d("service", "onDestroy");
t.cancel();
}
The method onStart() is only used for old Android versions (<2.0). For later versions you should use onStartCommand() as bellow:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
this will solve your problem