I have a service as MyService. In my service, I have a global variable: value which is controled by a function control_Value(). The function used to control the value of varialbe value as follows rules:
The time when calling the function is called initial time. At intial time, the value is set as One. After 3 seconds from initial time, the value is set to Zero. The value will maintain Zero until the function is called again.
Based on the rule above, I wrote the control_Value() as follows:
public void control_Value()(){
value="One";
try{
Thread.sleep(3000);
value="Zero";
}
catch{}
}
Do you think Thead.sleep(3000) is a good approach? If not, please give me a better solution. Note that, the above function worked well.
This is my service
public class MyService extends Service {
String value=null;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO do something useful
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
//TODO for communication return IBinder implementation
return null;
}
#Subscribe
public void onSMSContentReceived(OnSMSReceiverEvent event) {
control_Value();
}
}
Update: The onSMSContentReceived is called automatically when a SMS come to phone.
This is solution using countdown timer from suggestion of TGMCians
//Global variable
private CountDownTimer mCountDownTimer;
//
#Override
protected void onDestroy() {
if(mCountDownTimer!=null){
mCountDownTimer.cancel();
}
super.onDestroy();
}
public void control_Value()(){
mCountDownTimer = new CountDownTimer(3000,1000) {
#Override
public void onTick(long millisUntilFinished) {
value="One";
}
#Override
public void onFinish() {
// Your stuff
value="Zero";
}
};
mCountDownTimer.start();
}
Do you think Thead.sleep(3000) is a good approach?
Never. Service run on application main thread without UI. Application will prompt ANR message in case you hold application main thread for certain seconds.
What to do
If you want to perform operation after certain seconds, then you can use CountDownTimer in your service which has methods onTick & onFinish where onTick hits on regular interval and onFinish hits when time is up.
Related
I am currently resuming a project I had been working on, and starting from scratch to recreate it.
However, upon creating a Service class, I noticed something - in my old project, a method inside the Service called onStartCommand contains all of the code that needs to be fired, whereas in my new project when I create a Service class, this method is nowhere to be found.
- Do I need to manually ADD this "onStartCommand" method to contain my service code?
- If not, where exactly would my code go? It seems in my "old" project's code, I completely comment-block public TimerService, and pass null into IBinder, and create onStartCommand etc instead.. and I can't quite figure out why.
- While i'm here, can someone please double-check my CountdownTimer code below? and if it's correct, should I be putting it inside of a Thread?
When I create a new Service Class, it looks like this:
public class TimerService extends Service {
public TimerService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
However in my old Project, my Service class looks like this:
public class TimerService extends Service {
/*
public TimerService() {
}
*/
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
intent.getStringExtra("TIMER_VALUE");
String string_timerValue;
string_timerValue = intent.getStringExtra("TIMER_VALUE");
long long_timerValue;
long_timerValue = Long.parseLong(String.valueOf(string_timerValue));
// I DO NOT WANT ANY TICK VALUE, SO GIVE IT FULL TIMER VALUE
long long_tickValue;
long_tickValue = Long.parseLong(String.valueOf(string_timerValue));
new CountDownTimer(long_timerValue, long_tickValue) {
public void onTick(long millisUntilFinished) {
// DO NOTHING
}
public void onFinish() {
Toast.makeText(TimerService.this, "TIMES UP", Toast.LENGTH_LONG).show();
stopService(intent);
}
}.start();
return START_STICKY;
// END OF onStartCommand
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
// END OF ENTIRE SERVICE CLASS
}
THANK YOU!!
Do I need to manually ADD this "onStartCommand" method to contain my service code?
Yes.
can someone please double-check my CountdownTimer code below?
Only create a service when one is absolutely necessary. It is unclear why this service is necessary.
Beyond that:
Use stopSelf(), not stopService(), to stop a service from inside that service.
Examining Intent extras and using START_STICKY is not a good combination. START_STICKY says "if you terminate my process to free up system RAM, please restart my service when possible, but pass null for the Intent". That will cause your service to crash with a NullPointerException.
At the moment I have got a singleton class that extends service like this:
public class ServiceSingleton extends Service {
private static ServiceSingleton instance;
private static boolean serviceSt;
private static PrefValues preferences;
private static Context context;
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
public static ServiceSingleton getInstance(Context cont) {
if (instance == null) {
context = cont;
// Some code
}
return instance;
}
So basically I run some methods in this class about every 30 minutes by using something like this:
private static void oneTasks() {
//task itself
}
private static void oneService() {
if (!serviceSt) {
serviceRunning = false;
return;
}
serviceRunning = true;
oneTasks();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
oneService();
}
}, (INTERVAL));
}
I also heard AlarmManager can do the same thing.
Anyway, my question is, If I am running periodical methods, which way to invoke methods is the best way(especially with the consideration of battery usage)?
At the moment I have got a singleton class that extends service like this
Yuck. Do not make a service be held indefinitely in a static data member.
So basically I run some methods in this class about every 30 minutes
You have not stated how you are doing that.
Anyway, my question is, If I am running periodical methods, which way to invoke methods is the best way(especially with the consideration of battery usage)?
If your objective is to only do this work when your process happens to be running for other reasons, you are welcome to use pretty much anything you want. I'd use ScheduledExecutorService.
If your objective is to do this work, even if your app is not running, AlarmManager covers that scenario. Team it with an IntentService, so that your process only needs to be in system RAM when it is actually doing work.
If your objective is to do this work, even if your app is not running, and even if the device falls asleep, you will need to use AlarmManager with a _WAKEUP alarm, coupled with either WakefulBroadcastReceiver, my WakefulIntentService, or the equivalent.
By using the Alarm Manager you can register a repeated alarm that will fire automatically every specific time, even if your application is closed. so it's a very efficient in term of battery usage.
Then inside the alarm's broadcast receiver you have to implement what you need. and you should consider creating a new thread or using IntentService class if your method will take more than a few seconds.
I know it's surely not the most elegant and best solution, but you could simply have a Thread with an infinite loop that had a SystemClock.sleep(1800000) at the end, so basically something like this:
final Thread buf_liberator = new Thread(
new Runnable() {
public void run() {
while (true) {
/* Your stuff */
SystemClock.sleep(1800000);
}
}
}
);
buf_liberator.setPriority(7);
buf_liberator.start();
Also you would need to have a stop condition inside the Thread as you can't stop it with the stop() method anymore.
You can also do it by CountDownTimer
CountDownTimer countDownTimer;
public void usingCountDownTimer() {
countDownTimer = new CountDownTimer(Long.MAX_VALUE, 10000) {
// This is called after every 10 sec interval.
public void onTick(long millisUntilFinished) {
setUi("Using count down timer");
}
public void onFinish() {
start();
}
}.start();
}
and onPause() method add
#Override
protected void onPause() {
super.onPause();
try {
countDownTimer.cancel();
} catch (Exception e) {
e.printStackTrace();
}
}
My application turned black screen right after I initialize service in my activity. No error or warning message was shown. Awhile later the application is already not responding and even after the time limit the service did not update info to the server. I wanted to use the service to send user's location constantly to the server after every minute. Service is initialize in my activity. I also included the service in AndroidManifest.xml as well.
LocationService
The code below is my structure of Service
public class LocationService extends Service{
#Override
public IBinder onBind(Intent arg0){
return null;
}
private String TAG = "LocationService";
#Override
public void onCreate(){
super.onCreate();
boolean isUpdateResult = true;
try{
while(isUpdateResult){
new CountDownTimer (60000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//Send information to server
}.start();
}
}
finally{
}
}
#Override
public void onDestroy(){
super.onDestroy();
}
}
Below is how I call the service in my main activity.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.display_screen);
startService(new Intent(Web_Slider.this,
LocationService.class));
}
Any idea what causes the black screen? Did I missed out something here?
Any comments will be appreciated! Thank you in advance.
I managed to solve this. Apparently if I run new CountDownTimer (60000, 1000) in the beginning of the loop, the screen will turned into black screen. If not mistaken is due constantly create new CountDownTimer cause it unable to function as it should. The right way to put it is take away the While(isUpdateResult). The function will constantly start a count down timer because there is a .start(); after onFinish();. So there while loop is not needed.
new CountDownTimer (60000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//Send information to server
}.start();
I have to run a bit of code in the background every one second, the code will call a webservice which searches a database and returns a value to the application. My question is which method would be the most effective to do this? I have read up on Timers, Threads, AsyncTask and Services and each seem to have their pros and cons. Please can someone tell me which would be the best to use considering execution time and battery life.
Thanks
Update:
I decided to use Aysnc task to run my code in the background while using a TimeTask to trigger the AsyncTask at regular intervals. This way the operation is destroyed when I leave that particular activity
You should use the service to do the background operation but in your case you want to run code in 1 sec here is the example of service using handler it call in every 1 sec.
public class YourService extends Service {
private static final String TAG = "Your Service";
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onDestroy() {
super.onDestroy();
// Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
handler.removeCallbacks(sendUpdatesToUI);
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
/// Any thing you want to do put the code here like web service procees it will run in ever 1 second
handler.postDelayed(this, 1000); // 1 seconds
}
};
#Override
public void onStart(Intent intent, int startid) {
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000);//1 second
Log.d(TAG, "onStart");
}
}
and service can't run every time android idle the service within 3 or 4 hr i suggested you to use the foreground service to use your process long running.
For operations like this I tend to use a Service component. for the task itself i use an AsyncTask which will wait a set time before it repeats itself (using a while loop).
You will have to create a new Thread so that the call don't lock up the device if the call takes longer than expected. The AsyncTask is an easy way to use multithreading, but it lacks the functionality of repeating tasks. I would say that you are best of either using a Timer or the newer ScheduledExecutorService.
If you chose to use the Timer you create a TimerTask that you can hand it. The ScheduledExecutorService takes a Runnable instead.
You might want to wrap the thread in a Service (The Service does not provide a new Thread), but this is not always necessary depending on your needs.
As suggested in comment, you can also use the Handler.postDelayed(). Although you still need to create a new thread and then call Looper.prepare() on it:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
(Code from Looper docs)
Also; calls to a webservice every second seems way too frequent, especially if the user is on a slow connection or there are data that needs to be transferred, try to reduce the calls as much as possible.
I think it's not only one solution, so it's up to you. You can try start thread with this run method:
private final int spleeptime = 1000;
public boolean running;
#Override
public void run() {
while (running) {
try {
int waited = 0;
while ((waited < spleeptime)) {
sleep(100);
waited += 100;
}
} catch (InterruptedException e) {
} finally {
// your code here
}
}
}
In my activity oncreate method, i have called a service using OnStartCommand(). My requirement is when the user is on the same Activity (when the Activity is visible), a set of code should run repeatedly. (Example .. I should make a web service call and get the response and do some action based on it after regular intervals).
I have put this set of code in this method.
#Override
public int onStartCommand(Intent i, int flags , int startId){
// Code to be repeated
return Service.START_STICKY;
}
But, this is getting executed only once. How to make it run repeatedly from the time the user came to this page till he leaves this page ??
CountDownTimer.cancel() method seems to be not working.
I would recommend you to use Timer instead. It's much more flexible and can be cancelled at any time. It may be something like that:
public class MainActivity extends Activity {
TextView mTextField;
long elapsed;
final static long INTERVAL=1000;
final static long TIMEOUT=5000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTextField=(TextView)findViewById(R.id.textview1);
TimerTask task=new TimerTask(){
#Override
public void run() {
elapsed+=INTERVAL;
if(elapsed>=TIMEOUT){
this.cancel();
displayText("finished");
return;
}
//if(some other conditions)
// this.cancel();
displayText("seconds elapsed: " + elapsed / 1000);
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, INTERVAL, INTERVAL);
}
private void displayText(final String text){
this.runOnUiThread(new Runnable(){
#Override
public void run() {
mTextField.setText(text);
}});
}
}
You can use Timer for the fixed-period execution of a method.
See here is a tutorial on this:
http://steve.odyfamily.com/?p=12