i've a strange issue. i want to update the text of a notification every second so i wrote this code
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
batteryTemperature = getBatteryTemperature();
new Handler().postDelayed(this, 1000);
}
}, 1000);
if(batteryTemperature != 0) {
builder.setContentText("BatteryLevel"+batteryTemperature);
} else {
builder.setContentText("The batteryTemperature value is 0");
}
With a Log i saw that in the Handler the batteryTemperature value is different from 0 but out of the Handler it return 0. Why? How can i set the correct value in the notification?
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
batteryTemperature = getBatteryTemperature();
handler.postDelayed(this, 1000);
}
}, 1000);
Do not create a Handler every time the Runnable is called. You need to executed this snippet, every time the runnable is executed
if(batteryTemperature != 0) {
builder.setContentText("BatteryLevel"+batteryTemperature);
} else {
builder.setContentText("The batteryTemperature value is 0");
}
Try this (UI thread safe):
TimerTask task = new TimerTask()
{
private final Handler mHandler = new Handler(Looper.getMainLooper());
#Override
public void run()
{
mHandler.post(new Runnable()
{
#Override
public void run()
{
batteryTemperature = getBatteryTemperature();
if (batteryTemperature != 0)
{
builder.setContentText("BatteryLevel" + batteryTemperature);
}
else
{
builder.setContentText("The batteryTemperature value is 0");
}
}
});
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 1000);
There are two things you're asking: 1) how do I update my notification and 2) why is the value always 0?
Let me answer the second one first, try this code instead:
private MyHandler myHandler = new MyHandler();
...
// get the ball rolling...
myHandler.sendEmptyMessageDelayed(MyHandler.UPDATE, 1000);
...
private class MyHandler extends Handler {
private int UPDATE = 0;
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE:
updateBatteryTemperatureNotification(getBatteryTemperature());
sendEmptyMessageDelayed(MyHandler.UPDATE, 1000);
break;
case STOP:
removeMessages(UPDATE);
break;
}
super.handleMessage(msg);
}
}
Is it safe to assume you know how to update the Notification when you have the data correct?
Related
I have a ArrayList that I fetch from internet. Now I am performing the list retrieval using Handler postdelayed. Like below in the onCreate of the activity.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
lis_dat.remove(lis_dat.size() - 1);
if (gri_not_lis) {
rv_3r_ada.notifyItemRemoved(lis_dat.size());
} else {
rv_3r_2c_ada.notifyItemRemoved(lis_dat.size());
}
List<String> lis_of_dat;
int cou = 0, pos = lis_dat.size();
String gen_sta, gen_end, gen_mon;
if (yea) {
String[] mon_sym = new DateFormatSymbols().getMonths();
lis_of_dat = Arrays.asList(mon_sym);
} else {
int how_man;
if (lis_is_new) {
how_man = 500;
} else {
how_man = 15;
}
if (day_in_bet(sta, end) <= how_man) {
gen_sta = sta;
gen_end = end;
} else {
gen_sta = sta;
Calendar cal = Calendar.getInstance();
cal.setTime(db_han.con_dat(sta));
cal.add(Calendar.DATE, how_man);
gen_end = USE_DAT.format(cal.getTime());
}
lis_of_dat = gen_dat_in_bet(gen_sta, gen_end);
}
for (String dat : lis_of_dat) {
if (yea) {
Date date = get_mon_dat(dat, YEA.format(db_han.con_dat(sta)));
gen_sta = get_mon_fir_or_las_dat(date, true);
gen_end = get_mon_fir_or_las_dat(date, false);
gen_mon = dat;
} else {
gen_sta = dat;
gen_end = null;
gen_mon = mon;
}
add_to_lis(gen_sta, gen_end, gen_mon, pos, gri_not_lis);
pos++;
}
pos_f[0] = pos;
cou_f[0] = cou;
is_loa = false;
}
}, 1000);
Now my question is this 1000 milliseconds here may vary in different devices. On whom the UI will stay frozen. So what's the alternative of this. Instead of waiting for 1 sec how can I wait till the UI loading is complete and then I do the retrieval?
I could use AsyncTask but then the task will stay running till the task is complete even if I go to another activity. but i don't need the task running after onPause is called. So how do I do it?
You can use AsyncTask which running in separate thread, your keeps UI responsive . You can cancel it in onPause of Activity by calling **asyncTaskRunner.cancel(true) **
private class AsyncTaskRunner extends AsyncTask<String, String, String> {
private String resp;
ProgressDialog progressDialog;
#Override
protected String doInBackground(String... params) {
return resp;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(String... text) {
}
}
You can save instance of handler and then remove all call backs in
onPause of the activity.
private Handler handler = new Handler();
handler.postDelayed(() -> {
// do you task here
},1000);
#Override
public void onPause() {
super.onPause();
handler.removeCallbacksAndMessages(null); // this is important
}
And if you want something which do not freeze UI without any delay,
there you go
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Executors.newSingleThreadExecutor().submit(() -> {
// Do you task here without any delay it will not freeze the UI
});
}
You can also try this,
class MyThread implements Runnable{
#Override
public void run() {
// Your Task Here, put your all calculations Here
}
}
and then in onCrate()
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new MyThread());
and then in onPause() or onDestory()
executor.shutdownNow();// this will stop the thread instantly
I am trying to display values inside ArrayList on single line textView one by one after some interval. How to achieve this without blocking the main thread?
I have written code which is able to do this with Thread.sleep but, after a few seconds of running, activity is getting crashed. I have used For Loop & Thread.sleep to iterate every ArrayList value after some interval.
When activity crashes, I am getting IndexOutOfBondException after a few seconds of running.
public void errorRepeater() {
Thread t = new Thread() {
#Override
public void run() {
// !isInterrupted()
while (!isInterrupted()) {
for (xz = 0; xz < errorList.size(); xz++) {
try {
Thread.sleep(2000); //1000ms = 1 sec
runOnUiThread(new Runnable() {
#Override
public void run() {
String sErrorList = errorList.get(xz);
String sErrorListOkBox = errorListOkBox.get(xz);
Log.i("MQTT sErrorList", sErrorList);
TextView tvC1HPLP = findViewById(R.id.errormsg);
tvC1HPLP.setText(sErrorList);
TextView tvok = findViewById(R.id.ok);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
t.start();
}
textView should display values inside ArrayList one by one without crashing activity.
Just for reference, you can try something like this.
// You can define those both textview globally.
TextView tvC1HPLP = findViewById(R.id.errormsg);
TextView tvok = findViewById(R.id.ok);
Handler mHandler = new Handler();
final Runnable runnable = new Runnable() {
int count = 0;
#Override
public void run() {
String sErrorList = errorList.get(count%errorList.size);
String sErrorListOkBox = errorListOkBox.get(count%errorListOkBox.size);
tvC1HPLP.setText(sErrorList);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
count++;
mHandler.postDelayed(this, 4000); // four second in ms
}
};
mHandler.postDelayed(runnable, 1000);
I have a scheduled timer running to show the delay in coming to school. Whenever a student arrives to the school, a custom dialog opens up with display showing the delay in arrival : 20.0 min. It gets incremented by 0.5min every half a minute. My code is -
public void startTimer(long delay_minutes) {
final long delay = delay_minutes;
delay_countup = (double) delay;
//Start the scheduled time
departuretimer = new Timer();
departuretimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
countup = 0.0 + delay_countup;
Log.d("hi","Values 0" + delay_countup + countup);
mHandler.obtainMessage(1).sendToTarget();
delay_countup = delay_countup + 0.5;
Log.d("hi","Values 1" + delay_countup);
}
}, 0, 30000);
}
public Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
delay_time.setText(String.valueOf(countup) + "min");
rootView.invalidate();
}
};
The problems are -
a) the timer runs in background for the old arrived student even when the dialog is opened for new arrived student. I mean the timer is never killed when the dialog is closed.(The dialog is closed only to confirm the arrival of the student)
b) Sometimes the textview delay_timedisplays wrong value. It shows 22.0min and immediately 0.5min and then again 23.0min.
Why is this?
EDIT 1:
Handling timer cancel after click of button in the dialog
private void handleClickAction() {
dismiss();
timer.cancel();
timer = null;
}
EDIT 2 :
The logs always display correct values but in the UI sometimes there is a problem. The problem is that for example -
delay_countup = 50.0
countup = 50.0
Textview updates as 50.0 //This is correct
Now,
delay_countup = 50.5
countup = 50.5
Textview updates as 0.5 //This is incorrect. I need 50.5
This happens sometimes...
It seems that you are never removing the first timer. So when you initialize the second timer you have two timers simultaneously trying to update the UI.
Store the timer as a member variable and check if it's initialized before starting a second one. When the dialog is closed you should cancel() the Timer. So you should also see how to implement methods when the dialog is dismissed - this should call a cleanup method which cancel() and sets the timer to null.
public class DialogTest extends Dialog {
Timer timer;
double countup = 0;
double initial_time = 0;
public DialogTest(Context context){
super(context);
}
#Override
protected void onStart() {
super.onStart();
startUpCounting();
}
#Override
protected void onStop() {
Log.e("b", "timer stopped");
if(timer != null){
timer.cancel();
timer = null;
}
super.onStop();
}
public void startUpCounting() {
delay_for_student.setText("Delay in Arrival");
rootView.invalidate();
Log.e("b", "timer started");
if(timer != null){
timer.cancel();
timer = null;
}
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
countup = 0.0 + initial_time;
if (countup == 0.0) {
onTimeHandler.obtainMessage(1).sendToTarget();
} else {
mHandler.obtainMessage(1).sendToTarget();
}
initial_time = initial_time + 0.5;
}
}, 0, 1000);
}
public Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
Log.e("b", "timer: " + countup);
delay_time.setText(String.valueOf(countup) + "min");
rootView.invalidate();
}
};
public Handler onTimeHandler = new Handler() {
public void handleMessage(Message msg) {
Log.e("b", "timer ---");
delay_time.setText("-");
rootView.invalidate();
}
};
}
I am trying to simulate an sending msg progress .
The main idea is to colour the members who message sent to them, promote the status bar etc.. (gui changes ) all this with delay for each loop iteration.
The main problem is that everything is going inside the onClick listener and runing thread inside it wont help ): cause gui is changing only after delay is completed.
Any one may advice me how to do this simulation ?
send.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
for(int i=0; i<phoneNumbers.size(); i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
members.get(i).setBackgroundColor(Color.GREEN);
members.get(i).invalidate();
mProgressDialog.setProgress(i+1);
sentCount.setText(getString(R.string.msgSentCount) + (i+1));
if(i==12){
scroolView.animate().translationYBy(-50);}
}
}
});
Thanks you very much !
If I unserstood you right - fake progress + waiting time. First of all handlers a perferct to delay an output:
//Fake Progress
progress = new ProgressDialog(this);
open(this);
// Delay output
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
setData();
}
}, 6000);
in the function setData(), do the task you wanna run after
and progress bar for fake:
public void open(Activity activity) {
progress.setMessage("Fakeprogress, Data Mining...");
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setIndeterminate(false);
progress.setCancelable(false);
progress.setMax(100);
progress.setProgress(10);
progress.show();
final int totalProgressTime = 100;
final Thread t = new Thread() {
#Override
public void run() {
int jumpTime = 0;
while (jumpTime < totalProgressTime) {
try {
sleep(60);
//System.out.println("********" + jumpTime);
jumpTime += 1;
progress.setProgress(0);
progress.setProgress(jumpTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
progress.dismiss();
}
};
t.start();
}
Finaly got it works with recursion !!!!
public static int counter=0;
public void runMother(final Handler handler)
{
if(counter==3)return;
handler.postDelayed(new Runnable() {
#Override
public void run() {
members.get(counter).setBackgroundColor(Color.GREEN);
counter++;
runMother(handler);
}
}, 1000*counter);
I have a class with 6 async methods, each one should call a blocking method. (meaning, a blocking method is posted on a background thread, and the result is posted on the ui thread)
I find my self writing the following code 6 times (1 per each async method), having only the blocking method and 'result' object type different.
mBackgroundThreadHandler.post(new Runnable() {
#Override
public void run() {
final String result = myBlockingMethod();
mUIHandler.post(new Runnable() {
#Override
public void run() {
//use result on UI thread
}
});
}
});
mBackgroundThreadHandler - a handler for a background thread
mUIHandler - a handler for the ui thread
Is there a "pretty" way to reuse this code?
While still a bit lengthy, maybe this could help?
abstract class BgTask implements Runnable {
#Override
public void run() {
final String result = getResult();
mUIHandler.post(new Runnable() {
#Override
public void run() {
processResult(result);
}
});
}
abstract String getResult();
abstract void processResult(String result);
}
With the above class, the mBackgroundThreadHandler invocation becomes
mBackgroundThreadHandler.post(new BgTask() {
#Override
String getResult() {
return myBlockingMethod();
}
#Override
void processResult(String result) {
// UI magic.
}
});
you probably should look into doing custom handlers, instead of just posting Runnables to them
the UI custom handler
Handler mUIHandler = new Handler(Looper.getMainLooper()){
public void handleMessage (Message msg){
switch(msg.what){
case 0: // action 0,
doResultZero(msg.obj);
break;
case 1: // action 1
break;
case 2: // action 2
break;
}
}
};
the background handler
Handler mBackgroundThreadHandler = new Handler( /* insert here the background looper */){
public void handleMessage (Message msg){
switch(msg.what){
case 0: // action 0
msg.obj = executeActionZero();
mUIHandler.sendMessage(msg);
break;
case 1: // action 1
break;
case 2: // action 2
break;
}
}
};
so, to start the process you do:
Message m = new Message();
m.what = 0;
mBackgroundThreadHandler.sendMessage(m);
Use can use the following class
public class RunnableOnBackgroudAndResultOnUI {
private Handler mBackgroundThreadHandler;
private Handler mUIHandler;
public RunnableOnBackgroudAndResultOnUI(Handler backgroundThreadHandler, Handler uIHandler) {
mBackgroundThreadHandler = backgroundThreadHandler;
mUIHandler = uIHandler;
}
public void run(final Runnable background, final Runnable ui) {
mBackgroundThreadHandler.post(new Runnable() {
#Override
public void run() {
background.run();
mUIHandler.post(ui);
}
});
}
}
and execute it like this
RunnableOnBackgroudAndResultOnUI runnableOnBackgroudAndResultOnUI = new RunnableOnBackgroudAndResultOnUI(mBackgroundThreadHandler, mUIHandler);
runnableOnBackgroudAndResultOnUI.run(new Runnable() {
#Override
public void run() {
// run on background
}
}, new Runnable() {
#Override
public void run() {
// run on ui
}
});
}
});