How android update ui - android

Android recommend update ui in the ui thread,but i found that i can update the ui in the non-ui thread directly like below:
public class MainActivity extends Activity {
private TextView textView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
new Thread(new Runnable() {
#Override
public void run() {
textView.setText("SecondThread");
}
}).start();
}
}
That's run correctly,but if i sleep the thread 1000ms:
public class MainActivity extends Activity {
private TextView textView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
new Thread(new Runnable() {
#Override
public void run() {
try {
**Thread.sleep(1000);**
} catch (InterruptedException e) {
e.printStackTrace();
}
textView.setText("SecondThread");
}
}).start();
}
}
I get the error"Only the original thread that created a view hierarchy can touch its views",i try to change the sleep value much times,i found when i set the value 135 or less,it can run correctly:
Thread.sleep(135);
Thread.sleep(134);
Thread.sleep(...);
That's very interesting!But why it happen?I can't find any way to make sense of that,is anyone can help me?thanks!

If you are trying to touch views from background thread you should consider using runOnUiThread method, which accepts runnable as argument in which you can update views
EDIT: Also I would recommed you to use AsyncTask to achieve your goals, it has two callbacks onPreExecute and onPostExecute, whiche are invoked on the UI thread

so will always work
new Thread(new Runnable() {
#Override
public void run() {
try {
**Thread.sleep(1000);**
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runable(){
#Override
public void run(){
textView.setText("SecondThread");
});
}
}).start();
There is another way to use the Handler()

Related

Access to main thread views from another thread

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" }
}

How to make a image visible after completion of Thread?

I am making a project in which i am using the progressdialog and i want to show this progress dialog on creation of activity and i am able to that. In the on create method i want the image to be invisible and i want image to be visible after completion of progress dialog but it is throwing exception in the line imagevisible();
The logcat is:
04-12 12:48:35.309: E/AndroidRuntime(4994): at com.example.project1.ShowPassword$waiter.run(ShowPassword.java:59)
Code
ImageView iv;
ProgressDialog p;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.showpass);
iv=(ImageView)findViewById(R.id.imageView1);
iv.setVisibility(View.INVISIBLE);
p= new ProgressDialog(this);
p.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
p.setTitle("Getting Password: ");
p.setMessage("Loading:");
p.setMax(100);
p.show();
Thread t=new Thread(new waiter());
t.start();
public class waiter extends Thread{
public void run(){
for(int i=0; i<5; i++){
p.incrementProgressBy(20);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}p.dismiss();
imagevisible();
}
}
public void imagevisible(){
iv.setVisibility(View.VISIBLE);
}
You can't change UI from non UI thread. You can use runOnUiThread method of Activity:
public class waiter extends Thread{
public void run(){
//...
runOnUiThread(new Runnable() {
#Override
public void run() {
imagevisible();
}
});
}
}
What you want is an AsyncTask. Implement doInBackground() (runs in the background) and onPostExecute() (runs on the UI thread).
https://developer.android.com/reference/android/os/AsyncTask.html

Is there a way I can put some delay in setcontentView in android?

I have a SetContentView(R.layout.camera);
I want this layout to be start executing after some milliseconds....till then it should be blank. How can I achieve this in android?
For this Write your onCreate() like this..Then it will work..
Thread t = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
t = new Thread(new Runnable() {
#Override
public void run() {
try {
t.sleep(5000);
runOnUiThread(new Runnable() {
public void run() {
setContentView(R.layout.activity_main);
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t.start();
}
you can use handler for make delay
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//setcontentview
}
};
in oncreate methode
Message m = Message.obtainMessage();
handler.sendMessageDelayed(m, delayMillis);
Your activity will not be visible unless onResume() will get called, Do some operation in main Thread or onCreate() Method it will block your main thread and UI will not be displayed until your operation gets completed.
Create root View with all the components and visibility set to INVISIBLE or GONE and then show it after delay. You can use Handler and postDelayed to execute a code after delay.

setContentView execute too late

I have a problem, I make a simple application to show you my problem.
I want that setContentView executes and displays the .xml BEFORE the Sleep is executed. I thought everything will be execute in order?
Is there anyone how can say me why it doesn't do that?
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// do something
}
Thanks a lot!
EDIT:
Here is the real OnCreate, seems to be a bigger problem.
Everything with the sleep worked fine, but with the Connect method there are problems.
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ConnectBluetooth();
}
In the ConnectBluetooth() method, I just create a new Socket and try a connection.
With a ned thread or a handler it doesn't seems to work, what should I do then? Use something like an asynctask?
Thanks a lot in common!
The layout isn't displayed until after the creation process has finished, after onResume() is called. However there is no callback for when the layout is displayed, but you can use a Handler and Runnable to do this.
Create a couple field variables:
Handler handler = new Handler();
Runnable delay = new Runnable() {
#Override
public void run() {
// Do something
}
};
And onCreate() call:
handler.postDelayed(delay, 10000);
When you call sleep, you are pausing the UI thread. This will prevent onCreate from returning, which will prevent the framework from completing initialization of your activity, including displaying your view hierarchy.
You should never pause the UI thread like that. If you want to do something after 10 seconds, you can start a separate thread that will do it at the right time:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread() {
#Override
public void run() {
try {
Thread.sleep(10000);
doSomething();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}
A cleaner approach would be to use a Handler:
Handler mHandler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
doSomething();
}
}, 10000);
}

How do we use runOnUiThread in Android?

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.

Categories

Resources