I'm trying to code a timer for Android, but I'm getting problems with the handler. This line:
handler.post(new Runnable(){
...is triggering a NullPointerException. Why?
public class HomeFragment extends Fragment {
private int stunde,minute,sekunde;
private TextView textfield;
private Button buttonStart,buttonStop;
private Handler handler;
private boolean Running = true;
private Runnable runnable;
private Thread thread;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
buttonStart =(Button) rootView.findViewById(R.id.button1);
buttonStop = (Button) rootView.findViewById(R.id.button2);
buttonStop.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
thread.stop();
}
});
textfield = (TextView) rootView.findViewById(R.id.startZeit);
buttonStart.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
Running = true;
runnable = new Runnable(){
#Override
public void run() {
while(Running){
try{
Thread.sleep(1000);
}
catch(InterruptedException e){
e.printStackTrace();
}
handler.post(new Runnable(){
#Override
public void run(){
sekunde+=1;
if(sekunde == 60){
minute +=1;
sekunde = 0;
}if(minute == 60){
stunde +=1;
}
textfield.setText(String.format("%02d",stunde)+" : "+String.format("%02d", minute)+" : "+String.format("%02d",sekunde));
}
});
}
}
};
thread = new Thread(runnable);
thread.start();
handler = new Handler();
}
});
return rootView;
}
}`
Your handler has to be instantiated with
handler = new Handler();
before it is used.
Your formatting is quite hard to read but you get a NPE if runnable or handler have not been initialised. Since you are providing a new runnable object, that means your handler has not been initialised.
I think you are creating your handler inside an onClickListener. Try initialising it in onCreate or towards the top of onCreateView for clarity.
Goodluck
Because you didn't initialized the handler object. So you are getting a NullPointerException on it.
You will need to do some thing like that:
Handler handler = new Handler();
Somewhere in your code before you can use this object.
Related
TextView output;
int i;
Random random=new Random();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
output=findViewById(R.id.textView);
new Thread(new mythread()).start();
}
class mythread implements Runnable{
#Override
public void run() {
try {
while(true) {
i = random.nextInt(100);
output.setText(i + "");
Thread.sleep(500);
}
}catch (Exception e){}
}
}
}
it just showing one number in text view
but requirement is ,it should generate random number and keep updating textview after 500ms
Thank You!
The main problem, in your code, is that you can update UI only in the main thread and you are using a custom thread.
The second problem is that you are using Thread.sleep that is a very bad practise.
I suggest you to use Handler
Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
Log.d("Handler", "Running Handler");
handler.postDelayed(this, 500);
}
}
handler.postDelayed(runnable, 0);
and here the kotlin version
var handler = Handler()
var runnable = object : Runnable {
override fun run() {
Log.d("Handler", "Running Handler");
handler.postDelayed(this, 500)
}
}
handler.postDelayed(runnable, 500)
Try this, I think it will solved your problem.
public class MainActivity extends AppCompatActivity {
private Random random;
private Handler handler;
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_number);
displayRandomNumber();
}
/**
* Display random number in text view
*/
private void displayRandomNumber()
{
random = new Random();
handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
int value = random.nextInt();
textView.setText(String.valueOf(value));
handler.postDelayed(this,2000);
}
}, 2000);
}
}
I have been trying to figure out how to make a countdown timer using 'handler()' and i still don't know how to make it so the app will execute the line "Finished" when the countdown hits 0.
I am after whatever line of code is required for me to enter in the 'UpdateGUI()' to exit the runnable and go back to the main activity to display "Finished".
I have not been coding very long, so maybe it is an obvious answer, but I can't find it on any threads on this page...
Some help would be much appreciated :-)
Thank you
public class MainActivity extends AppCompatActivity {
int i = 10;
TextView tv;
final Handler myHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button but = (Button) findViewById(R.id.button);
but.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
tv = (TextView) findViewById(R.id.textView);
Timer myTimer = new Timer();
myTimer.schedule(new TimerTask() {
#Override
public void run() {
UpdateGUI();
}
}, 0, 1000);
tv = (TextView) findViewById(R.id.textView);
tv.setText("Finished");
}
});
}
private void UpdateGUI() {
if (i == 0) {
//this is where i need to enter the code!!
}
else
i--;
myHandler.post(myRunnable);
}
final Runnable myRunnable = new Runnable() {
public void run() {
tv.setText(String.valueOf(i));
}
};
}
If I understand you correctly in case you need to run your runnable after some period of time use Handler method postDelayed(runnable, timeOutInMillis)
UPDATE: example of handler timer
int timesRun;
Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
runTimer();
i++;
}
};
// call it in button callback
public void runTimer(){
// update your timer here
if (i != 10) // if 10 seconds not passed run it one more time
handler.postDelayed(runnable, 1000); // run every second
}
Note that this is not the most elegant way to do this, but still, it should work
I have a Fragment which sets up a ListView and creates a Handler to update the Listview periodically. However, it looks like the Handler still runs after the Fragment has been destroyed.
The following is the code.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//boilerplate code
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
assignAdapter();
handler.postDelayed(this, 15000);
}
});
return v;
}
Updating the ListView after the destruction of the Fragment causes the app to crash. How can I cause the Handler to stop as the Fragment gets destroyed? I would also like to know what effects if any pausing the app has on the Handler as well.
You need to implement handler like this
private Handler myHandler;
private Runnable myRunnable = new Runnable() {
#Override
public void run() {
//Do Something
}
};
#Override
public void onDestroy () {
mHandler.removeCallbacks(myRunnable);
super.onDestroy ();
}
You need to store a reference to your handler and runnable in the fragment, and then when the fragment is destroyed you need to remove callbacks from the handler passing in the runnable.
private Handler mHandler;
private Runnable mRunnable;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//boilerplate code
mRunnable = new Runnable() {
#Override
public void run() {
assignAdapter();
handler.postDelayed(this, 15000);
}
};
mHandler = new Handler(mRunnable);
mHandler.post();
return v;
}
#Override
public void onDestroy() {
mHandler.removeCallbacks(mRunnable);
super.onDestroy();
}
Another way of stopping the handler with the use of WeakReference to the fragment:
static final class UpdateUIRunnable implements Runnable {
final WeakReference<RouteGuideFragment> weakRefToParent;
final Handler handler;
public UpdateUIRunnable(RouteGuideFragment fragment, Handler handler) {
weakRefToParent = new WeakReference<RouteGuideFragment>(fragment);
this.handler = handler;
}
public void scheduleNextRun() {
handler.postDelayed(this, INTERVAL_TO_REDRAW_UI);
}
#Override
public void run() {
RouteGuideFragment fragment = weakRefToParent.get();
if (fragment == null || fragment.hasBeenDestroyed()) {
Log.d("UIUpdateRunnable", "Killing updater -> fragment has been destroyed.");
return;
}
if (fragment.adapter != null) {
try {
fragment.adapter.forceUpdate();
} finally {
// schedule again
this.scheduleNextRun();
}
}
}
}
where fragment.hasBeenDestroyed() is simply a getter for mDestroyed property of a fragment:
#Override
public void onDestroy() {
super.onDestroy();
mDestroyed = true;
}
Someone posted another question similar and the problem is due to a bug in the ChildFragmentManager. Basically, the ChildFragmentManager ends up with a broken internal state when it is detached from the Activity. Have a look at the original answer here
Hello guys I'm trying to update the UI after a short delay and for this I'm using handler's postdelayed method. The following code initially sets my textview text to "Processing" and the code that's included in the the handler's runnable gets executed but doesn't update the UI? Please note that this is done in a Fragment
TextView progressText=(TextView)parent.findViewById(R.id.inProgressText);
progressText.setText("Processing");
getActivity().getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
TextView progressText=(TextView)parent.findViewById(R.id.inProgressText);
progressText.setText("Request completed");
}
}, 3000);
Thanks for your help
Change
getActivity().getMainLooper()).postDelayed(new Runnable()
to:
final Handler handler = new Handler();
Then
handler.postDelayed(new Runnable() {
#Override
public void run() {
final TextView progressText=(TextView)findViewById(R.id.inProgressText);
progressText.setText("Request completed");
}
}, 3000);
Use this code
public class MainActivity extends Activity {
TextView progressText = null;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_main, container, false);
progressText = (TextView) rootView.findViewById(R.id.inProgressText);
progressText.setText("Processing");
progressText.postDelayed(new Runnable() {
#Override
public void run() {
progressText.setText("Request completed");
}
}, 3000);
return rootView;
}
}
Please try this way : I checked in Fragement and it is working perfectly.
View parent= inflater.inflate(R.layout.your_fragement, container, false);
TextView progressText=(TextView)parent.findViewById(R.id.inProgressText);
progressText.setText("Processing");
progressText.postDelayed(new Runnable() {
#Override
public void run() {
progressText.setText("Request completed");
}
}, 3000);
Hi Iam trying to update 3 textviews every second. I have written this piece of code. the thread starts normally but the textviews they do not get updated. I am passing a function inside the text parameters of the texts views that gets the current system time (using Calendar) in digits but then converts it to letters. example: for 3.45 THREE FORTYFIVE. any help would be appreciated. thanks
public class MainActivity extends Activity {
TextView currentv;
GetDate gd;
TextView currentmin;
TextView currentmins;
private Handler mHandler;
private boolean Running = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
currentv = (TextView) this.findViewById(R.id.tvtimehour);
currentmin = (TextView) findViewById(R.id.tvtimemin);
currentmins = (TextView) findViewById(R.id.tvtimesecond);
gd = new GetDate();
currentv.setText(gd.calculateTimeHour());
currentmin.setText(gd.calculateTimeMinute());
currentmins.setText(gd.calculateTimeMinuteDigit());
mHandler = new Handler();
Runnable runb = new Runnable(){
#Override
public void run(){
while(Running == true){
try{
Thread.sleep(1000);
}
catch(Exception e){
e.printStackTrace();
}
mHandler.post(new Runnable(){
#Override
public void run(){
currentv.setText(gd.calculateTimeHour());
currentmin.setText(gd.calculateTimeMinute());
currentmins.setText(gd.calculateTimeMinuteDigit());
}
});
}
}
};
new Thread(runb).start();
}
Try this,
private MyTimerTask mytask;
private Timer timer;
mytask = new MyTimerTask();
timer = new Timer();
timer.schedule(mytask, 0,60000);
Timer class:
class MyTimerTask extends TimerTask {
#Override
public void run() {
// TODO Auto-generated method stub
runOnUiThread(new Runnable() {
public void run() {
// Do your stuff here it will work
currentv.setText(gd.calculateTimeHour());
currentmin.setText(gd.calculateTimeMinute());
currentmins.setText(gd.calculateTimeMinuteDigit());
}
});
}
}
Use Timer for this, I think because Thread can not update your UI.