when I read document about asyntask, they say that: "should not" update UI thread in doInbackground because doInbackground work on different thread.
that means : this action will dangerous because UI Thread isn't thread-safe. I understand it. but when I try for test what happen when I update UI Thread in this function. I receive error: (but error doesn't not look like because aysnchonize, but because we CANNOT do it)
(TextView)((Activity)context).findViewById(R.id.text)).setText("StackOverFlow");
//context: reference of context object of UI Thread
Please explain for me. Does we shouldn't or mustn't .
thanks :)
what I have understand so far with android is...,
we can't update UI thread from background thread.
May be it is the case they have stopped us to update UI from background thread.
The reason for that is very clear... # OS level there will be so many thread will be running.
And also
different thread from different application, And in that case It will be chaos on the screen, if we can update UI from bg-thread
Inside the doInBackgroundyou will not get the UI access. If You Want to take UI access publishProgress from doInBackgroundyou will go to the onProgressUpdate from there do what you wan to show on UI.
Below is the Code you will check for your reference :
class DownloadAsyncTask extends AsyncTask
{
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = ProgressDialog.show(Login.this, "", "Please Wait ...");
}
#Override
protected Void doInBackground(String... arg0) {
int status1 = validationuser(username);
Log.i("MyLog", "Inside the doInBackground is came"+status1);
if(status1 == 1)
{
publishProgress(status1+ "Valid User Code","1",""+status1);
}
else
{
publishProgress(status1+ " Invalid Valid User Code","0",""+status1);
}
return null;
}
#Override
protected void onProgressUpdate(String...values){
super.onProgressUpdate(values);
int index = Integer.parseInt(values[2]);
if(index == 1)
{
USERIDLOGIN = edittextuserName.getText().toString();
Intent intent=new Intent(Login.this, CollectionModuleandDownload.class);
/*Toast.makeText(Login.this, "Valid User Password", Toast.LENGTH_SHORT).show();*/
startActivity(intent);
progressDialog.dismiss();
}
else
{
Toast.makeText(Login.this, "Invalid Username & Password", Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
}
}
#Override
protected void onPostExecute(Void result){
super.onPostExecute(result);
/*if(progressDialog != null)
{
progressDialog.dismiss();
}*/
}
}
so you have to update ui only on the OnPostExecute & OnPreExecute.
here's a good example of asynctask. give it a try
you call it by
new SaveProfile().execute();
then this...
private class SaveProfile extends AsyncTask<String, Void, Boolean>{
#Override
protected Boolean doInBackground(String... params) {
//---------- so your stuff here.... non ui related
Log.v("response from saving",response);
if(response.equals("1")){
return true;
}else{
return false;
}
}
protected void onPostExecute(Boolean result) {
if(result) {
//------ UPDATE UI HERE
Toast.makeText(ProfileCompanyActivity.this, "profile saved", 2500).show();
}else{
Toast.makeText(ProfileCompanyActivity.this, "an error occured", 2500).show();
}
}
}
When you create a Aysnc task the doInBackground method runs in the separate thread from UI thread. So you cannot update the UI from this method.
The OnPostExecute and onPreExecute method execute in the same thread as UI thread. For further reading go here
If only one thread is allowed to touch the user interface, Android can guarantee that nothing vital is changed while it’s measuring views and rendering them to the screen
It is because .. User Interface can be updated only on mainthread..all the user interface objects in your screen are maintained by this mainthread....now if you try to change the user interface from some other thread(do in background)in this case.. it causes error because..for example.. if you try to change the seekbar(some widget) value from other than main thread.. and the user is trying to put a different value...then it is ambiguous for android.. as to which thread it should listen... hope it clarifies your doubt..
So, it is like we should'nt try to.. and because of its security.. we cannot try also.. as it gives error.. =]
doInBackground is used to perform heavy calculations or any background work you want to perform in your activity.
when the operation in your doinbackground method finished the on postexecute methods upadates your ui..
in short doinbackground is not used to update ui.
I think the answer is that we mustn't
It just doesn't seem logical to me..
its like trying to change the radio station at another car driving beside you..
the architecture just doesn't work that way.. you can decide on a radio station before you set off to your road trip or when you stop driving and theoretically you can yell to him and ask him to change the station but you cannot do it yourself.
As doInBackground() runs on separate thread and onPostExecute runs on UIMain thread and as per constraint provided by Android you cannot update UIMain Thread from other thread.
Because of above mentioned reason you are getting mentioned message while you are running your application.
Related
I'm trying to do an Android game using a Thread which repeats a loop for draw, move and others.
I have a problem with the execution of a method, which searches a value with a "do while" loop. When this method is executed, the thread does not continue until this process does not end.
What would be the best option for avoid this? Make another thread within that method? If you can give an example I'd really appreciate it.
Here's some pseudocode:
void mainLoop(){
drawElements();
moveElements();
//...
//...
reposition();
}
void reposition(){
// this stops my thread
do{
// do stuff
}while(!end);
// do stuff
}
As wqrahd suggested use AsyncTask.
I assume mainLoop is a main UI thread.
public class RepositionClass extends AsyncTask {
private Context mContext;
public RepositionClass(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
// do UI related here, this function will run in main thread context.
}
#Override
protected Boolean doInBackground(String... params) {
// call non-ui(computation intensive) part of reposition function here.
return true;
}
#Override
protected void onPostExecute(Boolean result) {
// do UI related part of reposition function here.
}
}
Creating another thread won't help you if you still have to block and wait for the loop to complete the search. The problem really is what is happening in the "do stuff" loop, you just need to optimize that to solve the issue.
use asyntask and in asyntask's doInBackground , do your thread work and in asyntask's onPostExecute call your repositionMethod.
I know that progress dialog will stop spinning if it's not terminated immediately inside onPostExecute(). However, I have some methods to call inside onPostExecute() and I cannot transfer them to doInBackground() because these methods should run on UI. Is there a possible way to continue the progressDialog after calling these methods without stopping it to spin?
Here is the onPostExecute of my AsyncTask:
protected String doInBackground(final String... strings) {
//Network activity here
}
protected void onPostExecute(String unused){
//progressdialog stops spinning here, cannot change the message also
try {
if(response.equals("HOST ERROR") || response.equals("CONNECTION ERROR") || response.equals("ERROR")){
new AlertDialog.Builder(context).setTitle("Error").setMessage("Cannot connect to the internet.").setNeutralButton("Close", null).setIcon(android.R.drawable.ic_delete).show();
}
else{
doc = Jsoup.parse(response);
Intent cc = new Intent(activity,com.sblive.aufschoolbliz.GradeBook.class);
subjectCodes = getSubjectCodes(); //this parsing method should run on UI
professors = getProfs(); //this parsing method should run on UI
grades = getGrades(); //this parsing method should run on UI
cc.putExtra("subjectCodes", subjectCodes);
cc.putExtra("professors", professors);
cc.putExtra("grades", grades);
if(this.pd.isShowing()) {
this.pd.dismiss();
}
context.startActivity(cc);
}
}
catch (NullPointerException e) {
}
}
<<< EDIT: >>>
Ok forget about what I posted, silly me. Of course anything that modifies user interface needs to be called/dismissed on the UI thread.
So what I would do is run everything possible during doInBackground(), and creating/dissmissing the dialog or anything that requires to be run on the UI thread explicitly like this:
this.runOnUiThread(new Runnable() {
public void run() {
/*Code required to run on UI thread*/ }
});
And im afraid that's as much as you can do without overdoing way too much.
I have written the following code within the main class for an async worker
private class Renderer extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "works... ", Toast.LENGTH_LONG).show();
return null;
}
protected void onProgressUpdate(Integer... progress) {
}
protected void onPostExecute(Long result) {
}
}
But calling this crashes the app
public void render(View v)
{
new Renderer().execute();
}
Can some one tell me what's going wrong?
You can't do a Toast in doInBackground, you will get Can't create handler inside thread that has not called Looper.prepare().
If it's just for testing at this stage (which your code seems to imply), consider instead just writing some log output for now.
Alternatively put your Toast either onPreExecute or onPostExecute
More info: How to raise a toast in AsyncTask, I am prompted to used the Looper
You are showing toast in doInbackground which is not possible. Do it in onPostExecute
protected void onPostExecute(Long result) {
Toast.makeText(getApplicationContext(), "works... ", Toast.LENGTH_LONG).show();
}
doInbackground is invoked on the background thread. You should update ui on the ui thread. You can alos display toast in onProgressUpdate.
More info at
http://developer.android.com/reference/android/os/AsyncTask.html
Check the topic under the section The 4 steps.
You can't access UI thread from background thread.
An AsyncTask is a helper around Threads and Handlers. It helps you to perform a background task and update the UI regularly.
Thus, the methods of AsyncTask run on different Threads:
doInBackground runs in a background Thread
onProgressUpdate and onPostExecute run on the UI Thread.
Now, you can only modify the UI in the UI Thread (=main Thread). This is why your code leads to a crash. Simply moving your Toast into onPostExecute will solve your problem.
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "works... ", Toast.LENGTH_LONG).show();
}
});`
Try to do all ui work on main thread.
I am following the guide on Processes and Threads to implement an AsyncTask in an android activity in which I will perform some database access. However, my code has to handle an exception in doInBackground.
My current thinking is to provide a Toast popup to inform the user of this exception, but now I am afraid this too "violates the second rule of the single-threaded model: do not access the Android UI toolkit from outside the UI thread" (as per the guide).
Would I be wrong in providing a Toast popup? Is there a better way to handle exceptions in the doInBackground method?
Will the exception cause you to stop what doInBackground is processing?
If yes, store what exception you encountered, exit doInBackground and show the Toast in onPostExecute
If no, pass the exception information to onProgressUpdate with publishProgress.
Trying to pop-up the Toast in doInBackground will not work.
You can use runOnUIThread to update UI from background thread
#Override
protected void doInBackground(Void... params) {
try{
// do some stuff
}catch(Exception ex){
ex.printStackTrace();
final String message = ex.getMessage();
yourActivity.runOnUiThread(new Runnable() {
public void run() {
// show toast
Toast.makeText(getApplicationContext, message, Toast.LENGTH_SHORT).show();
}
});
}
}
In an activity I load rows of a listview which takes much time, therefore I put this task in a separate thread to allow displaying a progressDialog.
I do the following
private void doMyStuff() {
listItems.clear();
progressDialog.show();
new Thread(new Runnable() {
#Override
public void run() {
for () {
listItems.add(something to add);
}
handler.sendEmptyMessage(0);
progressDialog.dismiss();
}
}).start();
}
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == 0) {
adapter.notifyDataSetChanged();
}
};
};
I have sometimes a bug which raises an IllegalStateException. First of all I was surprised, because programming thread like that is what I usually do in standard Java programs.
The bug appears only "sometimes" and it does not appear when doing step by step debugging.
This lead me to search around the web and I found some questions in SO related to this and I must admit that things are not clear to my mind.
As I call the notifyDataSetChanged() only when the thread finished why does it sometimes raises an exception.
Can someone confirm me that this way of doing is wrong, and that I MUST use async task and perhaps explain me why ???
I need to have a progressDialog displayed, can someone give me a simple example of AsyncTask populating a listview AND displaying a progressDialog of the populating progress.
Thanks
UPDATE
jtanveer gave me the answer to the asynctask question. Now the others pointed out that the dismiss is not in the handler, which I correct.
According to the article given by jtanveer on "Painless Threading" they say that
Android offers several ways to access the UI thread from other threads which one of them is HANDLER.
Does someone know why putting the dismissed in the handler did not solve my problem ? for me listItem.add has nothing to do with UI ? Am I wrong on that point ?
For me, in my code the only UI is adapter and progressdialog ? Any commentary or explanation is welcome.
FINAL ANSWER
stjom gave a working answer for my specific code. Running the runOnUiThread in the handler. It's working but I am surprised because I thought the handler was run in the Ui Thread ...
Thanx to all for all your answers.
define an inner class like below:
private class LoadListTask extends AsyncTask<String, Void, Integer> {
protected void onPreExecute() {
progressDialog.show();
}
protected Integer doInBackground(String... params) {
for () {
listItems.add(something to add);
}
return 0;
}
protected void onPostExecute(Integer result) {
progressDialog.dismiss();
if (result == 0) {
adapter.notifyDataSetChanged();
}
}
}
if you need, you can refer to this article.
whenever you call adapter.notifyDataSetChanged(); it identifies any changes to your listItems object. if any change is found, it will update the UI accordingly which I think causes your problem. you can call
runOnUiThread(new Runnable() {
public void run() {
adapter.notifyDataSetChanged();
}
});
inside your handler.
You don't need to use AsyncTask, its just a convenience.
As far as why your current implementation doesn't work sometimes -
You should dismiss your progress dialog from the UI thread, so that needs to go in your handler, not your background thread.