I am implementing an android app.My problem no wis that when I send the data from the client to the server I want the client to know that the data was sent successfully. I have implemented an AlertDialog but when I send the data,I get a message "Can't create handler inside thread that has not called Looper.prepare()". I have attached my code below.
private void saveOrder(final Order order) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
getConnection().saveOrder(order);
handleSuccessSaveOrder();
}
catch (Exception exc) {
Log.d("--- ERROR ---", exc.getMessage());
handleException(exc.getMessage());
}
}
});
thread.start();
}
private void handleSuccessSaveOrder() {
showAlert(Farsi.Convert(" j "),R.drawable.warning);
//showActivity(MainMenuActivity.class);
}
private void showAlert(String message, int iconId) {
alert = new AlertDialog.Builder(ReviewOrderActivity.this);
alert.setTitle("Status Dialog");
alert.setMessage(message);
alert.setIcon(iconId);
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
showActivity(MainMenuActivity.class); } });
alert.show();
}
You cannot modify the ui from a non ui thread, use runOnUiThread:
private void saveOrder(final Order order) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
getConnection().saveOrder(order);
runOnUiThread(new Runnable() {
public void run() {
handleSuccessSaveOrder();
}
});
}
catch (Exception exc) {
Log.d("--- ERROR ---", exc.getMessage());
handleException(exc.getMessage());
}
}
});
thread.start();
}
you can not change UI from backgroung thread.
use like this
private void handleSuccessSaveOrder() {
ReviewOrderActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
showAlert(Farsi.Convert(" j "),R.drawable.warning);
}
});
//showActivity(MainMenuActivity.class);
}
Make Handler for display AlertDialog and Try below code instead of your above code, it will solve your problem.
private void saveOrder(final Order order) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
getConnection().saveOrder(order);
mHandler.sendEmptyMessage(0);
}
catch (Exception exc) {
Log.d("--- ERROR ---", exc.getMessage());
handleException(exc.getMessage());
}
}
});
thread.start();
}
public Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
handleSuccessSaveOrder();
}
};
private void handleSuccessSaveOrder() {
showAlert(Farsi.Convert(" j "),R.drawable.warning);
}
private void showAlert(String message, int iconId) {
alert = new AlertDialog.Builder(ReviewOrderActivity.this);
alert.setTitle("Status Dialog");
alert.setMessage(message);
alert.setIcon(iconId);
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
showActivity(MainMenuActivity.class);
}
});
alert.show();
}
"Can't create handler inside thread that has not called Looper.prepare()" is due to:
Cannot display the Alert dialog in UI thread while running the process in the background thread.
So, place the alert dialog in UI thread in your handleSuccessSaveOrder() as below:
this.runOnUiThread(new Runnable() {
public void run() {
showAlert(Farsi.Convert(" j "),R.drawable.warning);
}
});
Related
I tried to show an alert dialog after some delay:
Thread thread = new Thread() {
#Override
public void run() {
try {
synchronized (this) {
wait(3000);
}
} catch (InterruptedException ex) {
}
final AlertDialog.Builder builder = new AlertDialog.Builder(stop_watch.fa);
builder.setMessage("Want to exit?");
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
locator_activity.fa.finish();
}
});
AlertDialog alertDialog = builder.create();
alertDialog.show();
}
};
thread.start();
After launching app. When it's time to show alertdialog the app stopped working. And it shows problem:-
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
AlertDialogs are UI elements and so the work needs to be executed on the UI Thread:
new Thread() {
public void run() {
activity.this.runOnUiThread(new Runnable() {
public void run() {
// Show dialog..
}
});
}
}.start();
Hi i know there are lot of answers to this topic. But I tried a lot and it doesn't work. I want to show a toast inside a thread of a service. How can i solve this problem. Using getApplicationContext() etc. doesn't work.
I start the Service from an Activity (no bounding).
public class CarDataService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
...
startThreadUpdatingDatabase();
Toast.makeText(this, message, Toast.LENGTH_LONG).show(); //it works
}
private void startThreadUpdatingDatabase(){
Log.d("Database", "startThreadUpdatingDatabase(was called)");
new Thread(new Runnable() {
public void run(){
..
// here i want to use a toast!!!
}
}).start();
}
}
Thank you!
You have to start the thread:
new Thread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),"Your message",Toast.LENGTH_LONG).show();
}
}).start();
public Contect context;
member variable
onStartCommand(){
context = getApplicationContext)
}
acquivre reference to the context before you start the thread
new Thread(new Runnable() {
#Override
public void run() {
Toast.makeText(context,"Your message",Toast.LENGTH_LONG).show();
}
}).start();
and there you go
use AsyncTask instead that helps in context management
http://www.androidsnippets.com/use-toast-wherever-you-want
Handler h = new Handler(context.getMainLooper());
h.post(new Runnable() {
#Override
public void run() {
Toast.makeText(context,message,Toast.LENGTH_LONG).show();
}
});
see if this works out
Show your Toast using UI-Thread
new Thread(new Runnable() {
#Override
public void run() {
// SHOW TOAST
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(yourContext, "Hello from UI-thread", Toast.LENGTH_SHORT).show();
}
});
//... start DB work
}
}).start();
If you have no access to an activity, so do it this way:
new Thread(new Runnable() {
#Override
public void run() {
// no activity, so use Handler & mainlooper
new Handler(Looper.getMainLooper()).post(
new Runnable() {
public void run() {
// yourContext is Activity or Application context
Toast.makeText(yourContext, "Hello from UI-thread", Toast.LENGTH_SHORT).show();
}
}
);
//... start DB work
}
}).start();
Look at this: Static Way to get Context on android?
I am trying to open a AlertDialog. When this AlertDialog is opened, the threads need to wait for user input in order to continue its program. I read that I need to lock the object thats need to wait and notified. When I run this code on my phone. The alertdialog won't show, and it looks like the app is looping, because after a few seconds I get a message that the app isn't responding. Below you will find the code I wrote.. By the way. I am a virgin to android programming. So please be gentle :P
public class EditTagActivity extends Activity{
AlertDialog alertDialog;
Runnable h = new Runnable()
{
# Override
public void run()
{
alertDialog.show();
synchronized(g)
{
try
{
Log.d("Threads", "g.wait()");
g.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
};
Runnable g = new Runnable()
{
#Override
public void run()
{
Log.d("Threads", "createAlertDialog()");
createAlertDialog();
runOnUiThread(h);
}
};
public AlertDialog alert;
Runnable test = new dialogManager();
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_tag);
Log.d("Threads", "setup()");
setup();
}
void setup()
{
Log.d("Threads", "g.run()");
g.run();
}
void createAlertDialog()
{
Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Alert");
alert.setMessage("Flaq");
alert.setPositiveButton("OK", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
synchronized(g)
{
Log.d("Threads", "g.notifyAll");
g.notifyAll();
}
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
synchronized(g)
{
Log.d("Threads", "g.notifyAll");
g.notifyAll();
}
}
});
alertDialog = alert.create();
}
}
Instead of Java's Thread and Runnable approach, you should use Android's AsyncTask, It helps you resolve this more simply by overriding the onPreExecute and onPostExecute methods to handle things just before and after running the code in background.
This post has a good example for using the AsyncTask class.
here is my code,
public ProgressDialog loadingdialog;
public void ShowManager() {
//do something
}
public void startScan() {
loadingdialog = ProgressDialog.show(WifiManagementActivity.this,
"","Scanning Please Wait",true);
new Thread() {
public void run() {
try {
sleep(4000);
ShowManager();
} catch(Exception e) {
Log.e("threadmessage",e.getMessage());
}
loadingdialog.dismiss();
}
}.start();
}
startScan();
A basic progressdialog show function, but on the line where ShowManager() is called, getting error ,
01-07 23:11:36.081: ERROR/threadmessage(576): Only the original thread
that created a view hierarchy can touch its views.
EDIT:
ShowManager() is a function that change the view elements. shortly something like,
public void ShowManager()
{
TextView mainText = (TextView) findViewById(R.id.wifiText);
mainText.setText("editted");
}
I found the answer. I don't like to answer my own question but maybe this will help someone else. We cannot update most UI objects while in a separate thread. We must create a handler and update the view inside it.
public ProgressDialog loadingdialog;
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
loadingdialog.dismiss();
ShowManager();
}
};
public void ShowManager()
{
TextView mainText = (TextView) findViewById(R.id.wifiText);
mainText.setText("editted");
}
public void startScan() {
loadingdialog = ProgressDialog.show(WifiManagementActivity.this,
"","Scanning Please Wait",true);
new Thread() {
public void run() {
try {
sleep(4000);
handler.sendEmptyMessage(0);
} catch(Exception e) {
Log.e("threadmessage",e.getMessage());
}
}
}.start();
}
startScan();
use this instead of just loadingdialog.dismiss()
runOnUiThread(new Runnable() {
#Override
public void run() {
loadingdialog.dismiss();
}
});
This is because you are trying to dismiss the dialog from the thread, while it was created in the main UI thread. Try moving the ProgressDialog.show statement inside the Thread. I would prefer using AsyncTask as they are much simpler to manage as in this example
something like this it's 'ok':
public void startScan() {
new Thread() {
public void run() {
loadingdialog = ProgressDialog.show(WifiManagementActivity.this,
"","Scanning Please Wait",true);
try {
sleep(4000);
ShowManager();
} catch(Exception e) {
Log.e("threadmessage",e.getMessage());
}
loadingdialog.dismiss();
}
}.start();
}
note the position of ProgressDialog.show(...), here the dialog.dismiss() is called in the thread that created the dialog.
but the cleanest way to achive that it's by using AsynTask
I need to do some validations sequentially and some of them involve complex database operations.
So, I need to do this in a separated thread of UI Thread, ok?
But some validations show messages to user, what need confirmation and
when user confirm, the next validation should be call.
This code example explains what I want to implement:
void makeValidation1(){
if(condition1Valid()){
makeValidation2();
}else{
DialogInterface.OnClickListener onClick = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
makeValidation2();
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setMessage("really want to do this?")
.setPositiveButton("Yes", onClick);
builder.create().show();
}
}
void makeValidation2(){
if(condition2Valid()){
}else{
//...
}
}
boolean condition1Valid() {
// complex database Operations
return false;
}
boolean condition2Valid() {
//complex database Operations
return false;
}
//...
void makeValidation9(){
//...
}
My question is: What the best way/pattern to implement this?
1 - Create one asyncTask for each validation? (I cant create only one AsyncTask, because confirmation messages can stop flux).
2 - Create a Runnable for each validation and create thread to run that when need call next validation?
3 - ???
edit
I tested this code #BinaryBazooka, but isnt work. Any help?
public class MainActivity extends Activity implements OnClickListener {
Thread mThread;
ProgressDialog mProgressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button = new Button(this);
button.setText("Start");
setContentView(button, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
button.setOnClickListener(this);
}
#Override
public void onClick(View v) {
mThread = new Thread(new Runnable() {
#Override
public void run() {
validations();
}
});
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Start Thread?");
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.show();
mThread.run();
}
});
builder.create().show();
}
void validations(){
//this method go on separated thread
validation1();
validation2();
validation3();
}
void validation1(){
if(true){
final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("Validation 1 failed. Go validation 2?");
builder.setPositiveButton("Go", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mProgressDialog.show();
//if user confirm, continue validation thread
mThread.notify();
}
});
builder.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
//if user cancel, stop validation thread
mThread.interrupt();
}
});
runOnUiThread(new Runnable() {
#Override
public void run() {
mProgressDialog.hide();
builder.create().show();
}
});
try {
synchronized (mThread) {
//wait for user confirmation
mThread.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void validation2() {
if(true){
final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("validacao 2 failed. Go validation 3?");
builder.setPositiveButton("Go", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mProgressDialog.show();
mThread.notify();
}
});
builder.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
mThread.interrupt();
}
});
runOnUiThread(new Runnable() {
#Override
public void run() {
mProgressDialog.hide();
builder.create().show();
}
});
try {
synchronized (mThread) {
mThread.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void validation3() {
Log.i("TAG", "<<<<<<<<<< >>>>>>>>>>>>");
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "finished", Toast.LENGTH_SHORT);
}
});
}
}
I would create a new thread and sleep it during these dialog calls, you can access the UI directly from within your runnable with..
runOnUiThread(new Runnable() {
public void run() {}
});
So something like..
Thread someThread = new Thread(new Runnable() {
#Override
public void run(){
runOnUiThread(new Runnable() {
public void run()
{
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.msg);
builder.setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
someThread.notify();
}
});
AlertDialog alert = builder.create();
alert.show();
}
});
}
someThread.wait();
Works with AsyncTask. Ty.
Code:
public class MainActivity extends Activity implements OnClickListener {
//Thread mThread;
ProgressDialog mProgressDialog;
private ValidationsAsyncTask async;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button = new Button(this);
button.setText("Start");
setContentView(button, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
button.setOnClickListener(this);
}
#Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Start Thread?");
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.show();
async = new ValidationsAsyncTask();
async.execute();
}
});
builder.create().show();
}
void validation1(){
if(true){
runOnUiThread(new Runnable() {
#Override
public void run() {
final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("Validation 1 failed. Go validation 2?");
builder.setPositiveButton("Go", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mProgressDialog.show();
//if user confirm, continue validation thread
synchronized (async) {
async.notify();
}
}
});
builder.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
//if user cancel, stop validation thread
async.cancel(true);
}
});
mProgressDialog.hide();
builder.create().show();
}
});
Log.i("TAG - validation1", Thread.currentThread().getName());
try {
synchronized (async) {
//wait for user confirmation
async.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void validation2() {
if(true){
runOnUiThread(new Runnable() {
#Override
public void run() {
final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("validacao 2 failed. Go validation 3?");
builder.setPositiveButton("Go", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mProgressDialog.show();
synchronized (async) {
async.notify();
}
}
});
builder.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
async.cancel(true);
}
});
mProgressDialog.hide();
builder.create().show();
}
});
try {
synchronized (async) {
async.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void validation3() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mProgressDialog.dismiss();
Toast.makeText(MainActivity.this, "finished", Toast.LENGTH_SHORT).show();
}
});
}
class ValidationsAsyncTask extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
validation1();
validation2();
validation3();
return null;
}
#Override
protected void onCancelled() {
Toast.makeText(MainActivity.this, "cancelled", Toast.LENGTH_LONG).show();
}
}
}