I was playing around with the CountDownTimer on Android and I came into sort of a dilemma. In my code, I have the following:
public class mCountDownTimer extends CountDownTimer{
protected boolean hasFinished = false;
public mCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
// TODO Auto-generated constructor stub
}
public void onFinish(){
hasFinished = true;
}
#Override
public void onTick(long millisUntilFinished) {
// TODO Auto-generated method stub
}
}
Basically I want to find out if my CountDownTimer has finished. But in the function I want to call it in, I have some code that goes:
public void function(){
public boolean finished = false;
if(interrupted)
countDownTimer.cancel();
if(temporaryCountHolder == false){
countDownTimer.start();
interrupted = true;
}
}
How can i tell whether or not my timer has finished? I want to implement something that says:
if(countDownTimer.hasFinished == true){
Time now = new Time(); //finds the current time
now.setToNow();
String lsNow = now.format("%m-%d-%Y %I:%M:%S");
lsNow += " just Started\n";
try {
dumpToFile("StepsChanged", lsNow);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
But if I put the statement right after
if(temporaryCountHolder == false)
statement, then the if statement with hasFinished will always evaluate to be false. How can I get it so that I can record the time if and only if the timer has finished?
As per your comments, the reason why you are getting the false value is because you are executing the statements before the timer has stopped.
You can go like below,
#Override
public void onFinish(){
hasFinished = true;
Time now = new Time(); //finds the current time
now.setToNow();
String lsNow = now.format("%m-%d-%Y %I:%M:%S");
lsNow += " just Started\n";
try {
dumpToFile("StepsChanged", lsNow);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
To simply record the time you can just move those methods to the onFinish method of countdowntimer class. I don't know about dumpToFile if it is a method of another class you can make it a static method and use it or even some suitable alternative methods. Hope this helps.
you need to cancel CountDownTimer in OnFinsh
#Override
public void onFinish() {
Log.v(TAG, "On Finish");
Intent intent = new Intent(TIME_OUT);
intent.putExtra("dialog", "timeout");
sendBroadcast(intent);
countDownTimer.cancel();
}
Related
I have been trying to create time out while AsyncTask execution more than 1 minute. If the time up, then should exit with Notification.
This is my code:
private class GetLongLat extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
longlatDialog = new ProgressDialog(MainActivity.this);
longlatDialog.setMessage("Fetching Data. Please wait..");
longlatDialog.setCancelable(false);
longlatDialog.show();
}
#Override
protected Void doInBackground(Void... arg0) {
GPSTracker gpsTracker;
//This is the timer to set time out
Timer timer = new Timer();
timer.schedule(new TaskKiller(this), 3000);
timer.cancel();
do{
gpsTracker = new GPSTracker(MainActivity.this);
gpsTracker.getLocation();
}while(!String.valueOf(gpsTracker.latitude).equals("0.0"));
return null;
}
protected void onCancelled() {
// do something, inform user etc.
Toast.makeText(getApplicationContext(), "Failed getting long lat. Please check your internet connection", Toast.LENGTH_LONG).show();
System.exit(1);
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (longlatDialog.isShowing())
longlatDialog.dismiss();
}
}
And this is a class called in doInBackground to set the time up.
class TaskKiller extends TimerTask {
private AsyncTask<?, ?, ?> mTask;
public TaskKiller(AsyncTask<?, ?, ?> task) {
this.mTask = task;
}
public void run() {
mTask.cancel(true);
}
}
But when i run the code, nothing happen. I mean the progress dialog always run very long time.
EDIT
I have edit my code to call GetLongLat something like this:
GetLongLat n = new GetLongLat();
n.execute();
try {
n.get(3000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
Toast.makeText(getApplicationContext(), "Failed getting long lat. Please check your internet connection", Toast.LENGTH_LONG).show();
System.exit(1);
}
But also, doesn't work.
I think you can use AsyncTask.get()
GetLongLat n = new GetLongLat();
n.get(30000, TimeUnit.MILLISECONDS);
you will have to use the n.get in a separate Thread..
Edited: one more different method but not efficient.,
GetLongLat n = new GetLongLat();
n.execute();
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run() {
if ( n.getStatus() == AsyncTask.Status.RUNNING )
n.cancel(true);
}
}, 30000 );
why are you canceling the timer? just after calling schedule()?
Cancels the Timer and all scheduled tasks
timer.cancel(); should be removed. check docs for cancel()
You can achieve this behaviour in many ways.
Here's an example using CountDownTimer
// Start your AsyncTask
private YourAsyncTask mTask = new YourAsyncTask().execute();
// Run a timer after you started the AsyncTask
new CountDownTimer(60000, 1000) {
public void onTick(long millisUntilFinished) {
// Do nothing
}
public void onFinish() {
mTask.cancel(true);
}
}.start();
You are cancelling the timer just after initiating it. You can do it like this too. But this type of busy waiting is not recommended at all.
#Override
protected Void doInBackground(Void... arg0) {
GPSTracker gpsTracker;
//This is the timer to set time out
new CountDownTimer(60000, 1000) {
public void onTick(long millisUntilFinished) {
// Do nothing
}
public void onFinish() {
// Set latitude to zero to finish the while loop outside.
// gpsTracker.latitude = "0.0"; // Something like this
}
}.start();
do{
gpsTracker = new GPSTracker(MainActivity.this);
gpsTracker.getLocation();
}while(!String.valueOf(gpsTracker.latitude).equals("0.0"));
return null;
}
Here's another approach. In your doInBackground method, you can use System.currentTimeMillis to check whether 1 minute has elapsed or not.
protected Void doInBackground(Void... arg0) {
GPSTracker gpsTracker;
long startTime = System.currentTimeMillis();
do{
gpsTracker = new GPSTracker(MainActivity.this);
gpsTracker.getLocation();
}while(!String.valueOf(gpsTracker.latitude).equals("0.0")
&& ((System.currentTimeMillis() - startTime) <= 60000);//60000 millisecond = 1 minute
return null;
}
`
Just alter your code like this and check whether your async task is getting cancelled or not.
GetLongLat getLongLatAsync = new GetLongLat();
getLongLatAsync.execute();
try {
Handler handler = new Handler();
/** 1st method **/
handler.postDelayed(new Runnable()
{
#Override
public void run() {
if (getLongLatAsync.getStatus() == AsyncTask.Status.RUNNING )
getLongLatAsync.cancel(true);
}
}, 3000 ); //3 Seconds
/** 1st method ends **/
/** second method */
handler.post(new Runnable()
{
#Override
public void run() {
getLongLatAsync.get(3000, TimeUnit.MILLISECONDS);//You should run it in seperated thread or else it will block ui thread.
}
});
/** Second method ends**/
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
Toast.makeText(getApplicationContext(), "Failed getting long lat. Please check your internet connection", Toast.LENGTH_LONG).show();
}
and in the onCancelld method write your logic
#Override
protected void onCancelled() {
Log.d(TAG,"Asynctask has been cancelled.");
}
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.
I'm using viewpager to show music and on swip left/right changing music according to that.When i swip viewpager it takes few sec in swip(it doesnot swip smoothly).
Code:
#Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub
if (mCurrentPage > arg0) {
try {
Constant.position--;
musicService = new Intent(getApplicationContext(),
MusicService.class);
musicService.putExtra(Constant.NEXT, Constant.PREVIOUS);
startService(musicService);
musicService = null;
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
Constant.position++;
musicService = new Intent(getApplicationContext(),
MusicService.class);
musicService.putExtra(Constant.NEXT, Constant.NEXT);
startService(musicService);
musicService = null;
} catch (Exception e) {
e.printStackTrace();
}
}
mCurrentPage = arg0;
}
whenever I remove this code from onPageSelected, it swip smoothly. I had also putted this code inside handler but no befinits same issue.
Suggest me where I'm doing wrong and how to resolver this.
Update:
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
mThread = new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
sPosition = Constant.position;
if (intent != null) {
try {
mPrevious = (String) intent.getExtras().get(
Constant.NEXT);
System.out.println("value of previous=" + mPrevious);
if (mPrevious.equalsIgnoreCase(Constant.PLAY)) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
cancelNotification();
} else {
mediaPlayer.start();
buildNotification(title, album);
}
} else if (mPrevious
.equalsIgnoreCase(Constant.PREVIOUS)) {
playPrevious();
} else if (mPrevious.equalsIgnoreCase(Constant.NEXT)) {
playNext();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
mThread.start();
return START_NOT_STICKY;
}
From the guide topic Services:
Caution: A services runs in the same process as the application in which it is declared and in the main thread of that application, by default. So, if your service performs intensive or blocking operations while the user interacts with an activity from the same application, the service will slow down activity performance. To avoid impacting application performance, you should start a new thread inside the service
Make sure your music service starts a thread to delegate work to.
I have a issue with using a timer on a listview.
In the list item I showed using sqlite values. There is a textview which showing time difference of last updated time of the data and current time. i have to show it in every one second. so the user can know how long he updated the record.
I tried this in several ways.
First way
I tried to add timer in adapter class. so for every item new timer is created. so application crashed because of many timers run simultaneously.
Second way
I tried using adapter.notifyDataSetChanged() way. Like as this.
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
if (adapterChatThread != null) {
adapter.notifyDataSetChanged();
}
timerHandler.postDelayed(this, 1000); // run every second
}
};
timerRunnable.run();
I move to another activity when click on list item and user can come back to this Activity.
so in Onresume I used
timerHandler.postDelayed(timerRunnable, 500);
and OnPause
timerHandler.removeCallbacks(timerRunnable);
Issue is data is not showing well. I mean in every second data difference is not one second. some time differnce is 2sec, 5 sec, .. etc.
means timer is not working as I expected.
Third way
I used a asynctask and call it in every second using a timer.
class ThreadTimer extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
return null;
}
#Override
protected void onPostExecute(Void result) {
if (adapter != null)
adapter.notifyDataSetChanged();
super.onPostExecute(result);
}
}
I called this as in here
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
new ThreadTimer().execute();
timerHandler.postDelayed(this, 1000); // run every second
}
};
timerRunnable.run();
previous issue triggered. (data not showing well)
Fourth way
Using AsyncTask as this
class ThreadTimer extends AsyncTask<Void, Void, Void> {
void Sleep(int ms) {
try {
Thread.sleep(ms);
} catch (Exception e) {
}
}
#Override
protected Void doInBackground(Void... params) {
while (threadRun) {
Sleep(1000);
return null;
}
return null;
}
#Override
protected void onPostExecute(Void result) {
adapter.notifyDataSetChanged();
super.onPostExecute(result);
}
}
I called this class in OnResume.
In on pause I set threadRun= false;
issue is same.
please help me.
My requirement is update list item in every second.
Thank you.
edit
here is my adapter class textview update code.
Date lastUpdatedTime;
final ChatThreadDAO ctd = new ChatThreadDAO();
long timeForNextResponse = ctd.getLastRespondedTime(vct.get(position).getThread_id());
try {
if (vct.get(position).getThread_read_status() == 1 && timeForNextResponse > 0) {
final long respTime = timeForNextResponse;
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
lastUpdatedTime = formatter.parse(vct.get(position).getLast_updated_time());
final long timeDiff = (new Date()).getTime() - lastUpdatedTime.getTime();
if (timeDiff <= respTime) {
timeForNextResponse = respTime - timeDiff;
ctd.updateTimeRespondToLastMsg(vct.get(position).getThread_id(), timeForNextResponse);
holder.tvChatTimer.setVisibility(View.VISIBLE);
holder.tvChatTimer.setText(timeForNextResponse / 1000 + "");
} else {
ctd.updateTimeRespondToLastMsg(vct.get(position).getThread_id(), 0);
}
} else {
holder.tvChatTimer.setVisibility(View.INVISIBLE);
}
} catch (ParseException e) {
e.printStackTrace();
}
here vct is
Vector vct;
I assign the values to vector in adapter class constructer.
Here is an example similar to your case.
private class connectionControl extends Thread {
boolean stop_ = false;
public void stop_() {
this.stop_ = true;
}
public void run() {
System.out.println("Thread started:" + getClass().getSimpleName());
while(!this.stop_) {
try {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Calendar c = Calendar.getInstance();
int rightNow = c.get(Calendar.SECOND) + c.get(Calendar.MINUTE)*60;
if(rightNow - lastUpdatedTime > 10) {
wirelessIcon.setImageResource(R.drawable.wirelessred);
}
else if(rightNow - lastUpdatedTime > 5) {
wirelessIcon.setImageResource(R.drawable.wirelessyellow);
}
else {
wirelessIcon.setImageResource(R.drawable.wirelessgreen);
}
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Thread stoped:" + getClass().getSimpleName());
}
}
You set your lastUpdatedTime the same way you created rightNow whenever you call notifyDataSetChanged() method of your adapter.
I was wondering how to use a handler in android to send two messages from a separate thread to update UI. The thread is declared in another file. I understand that using java Thread is not desirable in Android, but I have given up using android methods, they are terrible. The handler messages are sent every 200 miliseconds from my declared thread. I cannot find a decent example of how to implement it.
Here is my extended thread. This is called from the activity.
import java.io.IOException;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Message;
public class MPlayer extends Thread {
private volatile boolean playing = false;
private volatile boolean finished = false;
MediaPlayer player;
Message msg;
Bundle bundle;
String filepath;
/* other fields, constructor etc. */
public MPlayer(String path) {
filepath = path;
player = new MediaPlayer();
bundle = new Bundle();
msg = new Message();
start();
}
public void seekMPlayer(int i) {
// TODO Auto-generated method stub
player.seekTo(i);
}
public boolean getPlaying() {
// TODO Auto-generated method stub
return playing;
}
#Override
public void run() {
try {
player.setDataSource(filepath);
player.prepare();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (!finished) {
while (playing && !finished) {
try {
Thread.sleep(200);
if (playing && !finished) {
bundle.putString("progval", songTime());
// msg.setData(bundle);
// threadHandler.sendMessage(msg);
} else
break;
} catch (InterruptedException e) {
}
}
}
}
public synchronized void pauseMPlayer() {
playing = false;
player.pause();
}
public synchronized void PlayMPlayer() {
playing = true;
player.start();
// call notify() here when you switch to wait/notify.
}
public void stopMPlayer() {
playing = false;
finished = true;
player.release();
// call notify() here too.
}
private String songTime() {
// TODO Auto-generated method stub
if (filepath != null) {
int progressseconds = (int) ((player.getCurrentPosition() / 1000) % 60);
int progressminutes = (int) ((player.getCurrentPosition() / 1000) / 60);
int durationseconds = (int) ((player.getDuration() / 1000) % 60);
int durationminutes = (int) ((player.getDuration() / 1000) / 60);
String progmin, progsec, durmin, dursec;
if (progressminutes >= 10)
progmin = Integer.toString(progressminutes);
else
progmin = "0" + Integer.toString(progressminutes);
if (progressseconds >= 10)
progsec = Integer.toString(progressseconds);
else
progsec = "0" + Integer.toString(progressseconds);
if (durationminutes >= 10)
durmin = Integer.toString(durationminutes);
else
durmin = "0" + Integer.toString(durationminutes);
if (durationseconds >= 10)
dursec = Integer.toString(durationseconds);
else
dursec = "0" + Integer.toString(durationseconds);
return (progmin + ":" + progsec + "/" + durmin + ":" + dursec);
} else {
return ("No File!");
}
}
}
Handler should bind a Looper of the thread. Use this constructor to specify a thread looper
Handler handler = new Handler(Looper.getMainLooper());
And now the you can send message to the main thread
There is nothing wrong in using Java threads in Android but it is a bit overkill to use it just for sending periodic messages. The recommended way to do it is to use Handler.postDelayed. This article suggests following method: put all your updating code into a Runnable and add postDelayed call to the end of this Runnable's run() to schedule it again. This approach eliminates overhead of having a background thread.
However it is easy to use Handler to send messages from the other thread. As I understand you are trying to send messages to some UI component so it can update itself.
In my application I faced a similar problem. I declared a handler inside the UI component and passed this handler to a background thread in a constructor parameter.
The UI part looks like:
class MyActivity extends Activity {
Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
// update UI according to a content of msg from background thread
// ...
}
};
private Thread mBackgroundWorker = new BackgroundThread(mHandler);
protected void onCreate(Bundle savedInstanceState) {
// ...
mBackgroundWorker.start();
// ...
}
protected void onDestroy() {
// we created the thread in this activity
// so we should manage its lifecycle here
mBackgroundWorker.interrupt();
}
}
And the background thread is implemented like
class BackgroundThread extends Thread {
private final mHandler;
public BackgroundThread(Handler h) {
mHandler = h;
}
public void run() {
// do some processing...
mHandler.sendMessage(/*some message to update an UI*/);
// ...
}
}