Using Android studio, I am trying to make an app that gets data from a web-service and display the data and updates the view every 5 sec or when the data on the web-service changes. With this I am trying to change the colours on some button based on an int, the int changes and the color on the button changes when I apply buttons(); to another button and then presses it but I want it to update by itself.
When I used a while loop the app gets stuck
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
buttons();
}
});
The runOnUiThread is placed in the onCreate.
using run on UI thread will cause your UI to freeze , try using a timer task instead .
example :
#Override
public void StopTimerTask() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
public void StartTimer() {
timer = new Timer();
initializeTimerTask();
int UpdateTime = Integer.valueOf(UserSettings.getString("Update", "60000"));
timer.schedule(doAsynchronousTask, 0, YOURTIME);
}
public void initializeTimerTask() {
doAsynchronousTask = new TimerTask() {
#Override
public void run() {
myHandler.post(new Runnable() {
public void run() {
YOUR LOGIC HERE
}
});
}
};
}
doing this where u just put another class into main activity was succesful only problem is that it have to be in my main class
public class updategui extends TimerTask {
Activity context;
Timer timer;
public updategui(Activity context, int seconds) {
this.context = context;
timer = new Timer();
timer.schedule(this,
seconds * 1000, // initial delay
seconds * 1000); // subsequent rate
}
#Override
public void run() {
if(context == null || context.isFinishing()) {
this.cancel();
return;
}
context.runOnUiThread(new Runnable() {
#Override
public void run() {
try {
buttons();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}}
This is my code on Activity to Invalidate the canvas it is not invalidating. Means onDraw() is not getting called even once;
public GraphView view;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
view = GraphView(this,null);
runplotTimer();
}
public void runplotTimer()
{
Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
InvalidateTimer();
}
},1000,40);
}
public void InvalidateTimer()
{
this.runOnUiThread(new Runnable() {
#Override
public void run()
{
//Log.d(ALARM_SERVICE, "Timer of 40 miliseconds");
view.InvalidateGraph();
}
});
}
on View class this is method which is gettting called from Activity. other OnDraw declaration is same as required.
public void InvalidateGraph()
{
m_bCalledPlotRealTimeGraph = true;
invalidate(chanX_count1, 0, chanX_count1+7, graphheight);
}
Any help please ?
You are attempting to make changes to the View on a Timer Thread, which will not work. You need to call invalidate on the main (UI) thread:
((Activity) view.getContext()).runOnUiThread(new Runnable() {
#Override
public void run() {
invalidate(chanX_count1, 0, chanX_count1+7, graphheight);
}
});
you need to Start the Timer
Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
InvalidateTimer();
}
},1000,40);
t.start()
Instead of Timer use Handler.
class UpdateHandler implements Runnable {
#Override
public void run(){
handler.sendEmptyMessageAtTime(0, 1000);
handler.postDelayed(this, 1000);
}
}
private Handler handler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//Call your draw method
}
}
};
Inside onCreate and onResule write
if( mupdateTask == null )
mupdateTask = new UpdateHandler();
handler.removeCallbacks(mupdateTask);
Call your handler using
handler.postDelayed(mupdateTask, 100);
I know you can only change the text in tTxtViews from the UI thread but i cant seem to find a way to work with that.
I'll go in to a bit more details: I'm trying to have a TextView that displays the time passed, but I can't do it in a thread, or a method that keeps getting called.
can you help me with a way of doing this? because I'm pretty much out of ideas.
Thanks.
public class MainActivity extends Activity {
protected static final long TIMER_DELAY = 100;
private TextView tv;
protected Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.helloWorld);
handler = new Handler();
handler.post(timerTask);
}
private Runnable timerTask = new Runnable() {
public void run() {
Calendar now = Calendar.getInstance();
//format date time
tv.setText(String.format("%02d:%02d:%02d", now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.MINUTE), now.get(Calendar.SECOND)));
//run again with delay
handler.postDelayed(timerTask, TIMER_DELAY);
}
};
}
I forgot add this, sorry. Don't forget do this:
#Override
public void onPause() {
if (handler != null)
handler.removeCallbacks(timerTask);
super.onPause();
}
And if you want resume app try this
#Override
public void onResume() {
super.onResume();
if (handler != null)
handler.post(timerTask);
}
Use this
new Thread(new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// Do what you want.
}
});
}
}).start();
or use a Handler:
Runnable r = new Runnable() {
#Override
public void run() {
// Do what you want.
}
};
Handler mHandler = new Handler();
mHandler.post(r);
I'm trying to use the UI-Thread, so I've written a simple test activity. But I think I've misunderstood something, because on clicking the button - the app does not respond anymore
public class TestActivity extends Activity {
Button btn;
int i = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
runThread();
}
});
}
private void runThread(){
runOnUiThread (new Thread(new Runnable() {
public void run() {
while(i++ < 1000){
btn.setText("#"+i);
try {
Thread.sleep(300);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}));
}
}
Below is corrected Snippet of runThread Function.
private void runThread() {
new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
Just wrap it as a function, then call this function from your background thread.
public void debugMsg(String msg) {
final String str = msg;
runOnUiThread(new Runnable() {
#Override
public void run() {
mInfo.setText(str);
}
});
}
You have it back-to-front. Your button click results in a call to runOnUiThread(), but this isn't needed, since the click handler is already running on the UI thread. Then, your code in runOnUiThread() is launching a new background thread, where you try to do UI operations, which then fail.
Instead, just launch the background thread directly from your click handler. Then, wrap the calls to btn.setText() inside a call to runOnUiThread().
runOnUiThread(new Runnable() {
public void run() {
//Do something on UiThread
}
});
There are several techniques using of runOnUiThread(), lets see all
This is my main thread (UI thread) called AndroidBasicThreadActivity and I'm going to update it from a worker thread in various ways -
public class AndroidBasicThreadActivity extends AppCompatActivity
{
public static TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_basic_thread);
textView = (TextView) findViewById(R.id.textview);
MyAndroidThread myTask = new MyAndroidThread(AndroidBasicThreadActivity.this);
Thread t1 = new Thread(myTask, "Bajrang");
t1.start();
}
}
1.) By passing Activity's instance as an argument on worker thread
class MyAndroidThread implements Runnable
{
Activity activity;
public MyAndroidThread(Activity activity)
{
this.activity = activity;
}
#Override
public void run()
{
//perform heavy task here and finally update the UI with result this way -
activity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
});
}
}
2.) By using View's post(Runnable runnable) method in worker thread
class MyAndroidThread implements Runnable
{
Activity activity;
public MyAndroidThread(Activity activity)
{
this.activity = activity;
}
#Override
public void run()
{
//perform heavy task here and finally update the UI with result this way -
AndroidBasicThreadActivity.textView.post(new Runnable()
{
#Override
public void run()
{
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
});
}
}
3.) By using Handler class from android.os package
If we don't have the context (this/ getApplicationContext()) or Activity's instance (AndroidBasicThreadActivity.this) then we have to use Handler class as below -
class MyAndroidThread implements Runnable
{
Activity activity;
public MyAndroidThread(Activity activity)
{
this.activity = activity;
}
#Override
public void run()
{
//perform heavy task here and finally update the UI with result this way -
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
});
}
}
If using in fragment then simply write
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
// Do something on UiThread
}
});
We use Worker Thread to make Apps smoother and avoid ANR's. We may need to update UI after the heavy process in worker Tread.
The UI can only be updated from UI Thread. In such cases, we use Handler or runOnUiThread both have a Runnable run method that executes in UI Thread.
The onClick method runs in UI thread so don't need to use runOnUiThread here.
Using Kotlin
While in Activity,
this.runOnUiThread {
// Do stuff
}
From Fragment,
activity?.runOnUiThread {
// Do stuff
}
Using Java,
this.runOnUiThread(new Runnable() {
void run() {
// Do stuff
}
});
For fragment use that:
requireActivity().runOnUiThread(() -> {
//your code logic
});
For activity use that:
runOnUiThread(() -> {
//your code logic
});
runOnUiThread is used in a way the UI can be updated with our background thread. For more: https://www.tutorialspoint.com/how-do-we-use-runonuithread-in-android
thy this:
#UiThread
public void logMsg(final String msg) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
}
You can use from this sample :
In the following example, we are going to use this facility to publish the result from a
synonym search that was processed by a background thread.
To accomplish the goal during the OnCreate activity callback, we will set up
onClickListener to run searchTask on a created thread.
When the user clicks on the Search button, we will create a Runnable anonymous
class that searches for the word typed in R.id.wordEt EditText and starts the
thread to execute Runnable.
When the search completes, we will create an instance of Runnable SetSynonymResult
to publish the result back on the synonym TextView over the UI thread.
This technique is sometime not the most convenient one, especially when we don't
have access to an Activity instance; therefore, in the following chapters, we are
going to discuss simpler and cleaner techniques to update the UI from a background
computing task.
public class MainActivity extends AppCompatActivity {
class SetSynonymResult implements Runnable {
String synonym;
SetSynonymResult(String synonym) {
this.synonym = synonym;
}
public void run() {
Log.d("AsyncAndroid", String.format("Sending synonym result %s on %d",
synonym, Thread.currentThread().getId()) + " !");
TextView tv = (TextView) findViewById(R.id.synonymTv);
tv.setText(this.synonym);
}
}
;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button search = (Button) findViewById(R.id.searchBut);
final EditText word = (EditText) findViewById(R.id.wordEt);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Runnable searchTask = new Runnable() {
#Override
public void run() {
String result = searchSynomim(word.getText().toString());
Log.d("AsyncAndroid", String.format("Searching for synonym for %s on %s",
word.getText(), Thread.currentThread().getName()));
runOnUiThread(new SetSynonymResult(result));
}
};
Thread thread = new Thread(searchTask);
thread.start();
}
});
}
static int i = 0;
String searchSynomim(String word) {
return ++i % 2 == 0 ? "fake" : "mock";
}
}
Source :
asynchronous android programming Helder Vasconcelos
This is how I use it:
runOnUiThread(new Runnable() {
#Override
public void run() {
//Do something on UiThread
}
});
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gifImageView = (GifImageView) findViewById(R.id.GifImageView);
gifImageView.setGifImageResource(R.drawable.success1);
new Thread(new Runnable() {
#Override
public void run() {
try {
//dummy delay for 2 second
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//update ui on UI thread
runOnUiThread(new Runnable() {
#Override
public void run() {
gifImageView.setGifImageResource(R.drawable.success);
}
});
}
}).start();
}
Try this: getActivity().runOnUiThread(new Runnable...
It's because:
1) the implicit this in your call to runOnUiThread is referring to AsyncTask, not your fragment.
2) Fragment doesn't have runOnUiThread.
However, Activity does.
Note that Activity just executes the Runnable if you're already on the main thread, otherwise it uses a Handler. You can implement a Handler in your fragment if you don't want to worry about the context of this, it's actually very easy:
// A class instance
private Handler mHandler = new Handler(Looper.getMainLooper());
// anywhere else in your code
mHandler.post(<your runnable>);
// ^ this will always be run on the next run loop on the main thread.
I have the following:-
public class resApp extends MapActivity implements Runnable {
public void run() {
searchImage.setVisibility(View.GONE);
}
}
I also have a background thread that runs before this but that seems to run ok.
When i run the app the run() never gets called.
Can you help?
This code did work about 6 months ago but the device was 2.1.
Thanks
Chris
edit
I had already implemented
private Handler handler;
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.toString().equalsIgnoreCase("1")) {
ad.dismiss();
} else {
pd.dismiss();
}
}
};
as an example and I already have an asynchronous task that runs in the back ground and in 2.1 I could have getters and setters in there. I have now had to pull these out and put them into the run() method as 2.2 doesn't like setting onclicklistener in an async task.
All I need to do is call the run() method on post execute but have tried everything:-
protected void onPostExecute(Object result) {
// Pass the result data back to the main activity
if (dialog != null) {
resApp.this.dialog.dismiss();
}
}
Could I just do:-
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
this.resApp.run();
}
};
You can call the run() method by using Handler.
Handler myHandler = new Handler();
resApp myObj;
And call it by using myHandler.post(myObj);