Where timer is a textview and throws error during runtime and UI comes out saying unfortunately has stopped.Have attached error mess link below.Plz help not understanding where I am going wrong
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.level_twolayout);
Thread t1 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
Timer.setText("Hello");
}
}
});
t1.start();
}
You must update UI from main thread.
Use this code. in place of Timer.setText("Hello");
// verify we are indeed updating UI on main thread.
runOnUiThread(new Runnable() {
#Override
public void run() {
// go ahead and update UI
Timer.setText("Hello");
}
});
runOnUiThread is an Activity method. See http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29.
You need to call MyActivityName.this.runOnUiThread() or more simply just runOnUiThread() as "this" will point to the scope of the Runnable you are creating and not your Activity.
Lastly, "Timer" may not be the best name for your TextView.
Related
I thought that it is not possible to access main thread views in a new thread!
But why below codes runs without any problem?!
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
new Thread(new Runnable() {
#Override
public void run() {
try {
textView.append(InetAddress.getByName("192.168.1.252").getHostName() + "\n\n");
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}).start();
}
As it stands here:
For example, below is some code for a click listener that downloads an
image from a separate thread and displays it in an ImageView:
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork("http://example.com/image.png");
mImageView.setImageBitmap(b);
}
}).start();
}
At first, this seems to work fine, because it creates a new thread to
handle the network operation. However, it violates the second rule of
the single-threaded model: do not access the Android UI toolkit from
outside the UI thread—this sample modifies the ImageView from the
worker thread instead of the UI thread. This can result in undefined
and unexpected behavior, which can be difficult and time-consuming to
track down.
So it works, but not recommended.
There are some recommended way to do this instead:
To fix this problem, Android offers several ways to access the UI
thread from other threads. Here is a list of methods that can help:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
try this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
new Thread(new Runnable() {
#Override
public void run() {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.append(InetAddress.getByName("192.168.1.252").getHostName() + "\n\n");
}
});
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}).start();
}
runOnUiThread - is method from activity. if you work inside fragment you can call getActivity().runOnUiThread
The solution is to run the UI thread inside your new thread.
Here is an example using anko.
btn_login.text = "LOGING IN"
doAsync {
authenticate(email, password)
uiThread { btn_login.text = "LOGIN" }
}
I want to Update UI from background thread and if user wants to interact with UI while updating then the UI should not blocked by background thread.
Please Help me out.
This can be done using handlers to post UI updates from background thread. You can refer https://developer.android.com/training/multiple-threads/communicate-ui.html for code sample.
Using this you can update UI from backgorund thread
runOnUiThread()
runOnUiThread(new Runnable() {
#Override
public void run() {
//ui update stuff
}
});
You can use handler to serve this purpose.
A simple example:
Create a class:
class Task implements Runnable {
#Override
public void run() {
for (int i = 0; i <= 20; i++) {
final int value = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
progressBar.setProgress(value);
}
});
}
}
}
Then call it from where you want to update the UI like this:
new Thread(new Task()).start();
Complete Example can be found here.
Or you can also go with different approach. Using runOnUiThread method will also allow you to achieve your expected result.
Example:
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});
I am using following code to update a list after certain time.
Myactivity {
setTimer() {
Runnable r = new Runnable() {
run() {
if(!isListUpdated) {
update();//n/w operation
} else {
show();//this is a UI operation
listupdated = false;
}
Handler.postDelayed(this,next); //repeat after next
}
new Thread(r).start();
}
}
}
After 2 - 3 iterations it is giving NetworkOnMainThreadException. Can somebody tell what is wrong in this code?
You should not do network operation in Main Thread. Create a separate thread and do nw operation there.
You can use AsyncTask, Service or separate thread . Where you ll do network operation. and update via BroadcastReceiver, Handler or AsyncTask.
Read about AsyncTask here
This exception usually occurs when you try to perform network operations in the main thread. Use an AsyncTask for your network operations.
Consider using runOnUiThread to perform UI operations in Non-UI Thread.
Your code snippet should be something like follows.
Runnable runnable = new Runnable() {
public void run() {
if (!isListUpdated) {
runOnUiThread(new Runnable() {
public void run() {
update(); //n/w operation
}
});
} else {
runOnUiThread(new Runnable() {
public void run() {
show(); //n/w operation
}
});
listupdated = false;
}
handler.postDelayed(runnable, next);
}
};
NetworkOnMainThreadException:
The exception that is thrown when an application attempts to perform a
networking operation on its main thread.
so you need to Use Thread, runOnUiThread, AsyncTask , Handler , or HandlerThread for Updating UI elements from background Thread.
an example using thread and runOnUiThread :
public void myThread(){
Thread th=new Thread() {
#Override
public void run() {
try
{
while(true) {
Current_Activity.this.runOnUiThread( new Runnable() {
#Override
public void run() {
//UPDATE UI FROM HERE
}
});
}
}catch (InterruptedException e) {
// TODO: handle exception
}
}
};
th.start();
}
I guess you are using honeycomb version, you better use AsyncTask it will solve your problem.
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 a syncing service that I want a progress bar for, because it takes >1 minute to sync all the data and I don't want to use indeterminate progress. I have a Handler for the syncing functions and am referencing and correctly updating the progressBar's progress but the UI does not update.
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//Sync calls
updateProgress(getContext());
}
};
public static void updateProgress(Context c){
layout = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
progress_view = layout.inflate(R.layout.sync_dialog, null);
mProgressStatus += mProgressStep;
mProgress = (ProgressBar) progress_view.findViewById(R.id.progress);
mProgress.setProgress(mProgressStatus);
}
I have tried using an ASynchTask class with no success. Any help is appreciated.
Let this my example of right use of Handler.
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
bar.incrementProgressBy(5);
if (bar.getProgress() == 100) {
bar.setProgress(0);
Toast.makeText(ThreadsDemoActivity.this, "Progress is finished.", Toast.LENGTH_SHORT).show();
}
}
};
Then you have to create Thread(now it do only some simulation or work)
#Override
public void onStart() {
super.onStart();
bar.setProgress(0);
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
try {
for (int i = 0; i < 20 && isRunning; i++) {
Thread.sleep(300);
handler.sendMessage(handler.obtainMessage());
}
}
catch (Throwable t) {
}
}
});
isRunning = true;
backgroundThread.start();
}
public void onStop() {
super.onStop();
isRunning = false;
}
Also in onCreate method you have to declare and initialise progressBar
bar = (ProgressBar) findViewById(R.id.progBar)
So this is good but not always. More complex approach offers AsyncTask. It's very complex and strong tool and when i would recommend to you something so clearly it's AnyncTask. It's generic type and has one method named doInBackground() that are using for long-time tasks and trasfers your task to background. There is one rule that you cannot update UI from background thread. You cannot but AsyncTask offers onProgressUpdate() method that are using for updating UI. But enough, if you want, have look at AsyncTask.
Regards
you should use Thread or AsyncTask for that,And only handler update progressBar meanwhile you sync all the data.
See this Example and put your sync code in doInBackground method