How to use wait() and notify() in Android - 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.

Related

Can not create handler inside thread that has not called Looper.prepare()

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();

Android catch unhandled exception and show the dialog

I want to handle unhandled exception in my app without any third-party libraries.
So i write a code.
Activity :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Thread.setDefaultUncaughtExceptionHandler(new ReportHelper(this));
throw new NullPointerException();
}
My crash handler :
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.widget.Toast;
/**
* Created by S-Shustikov on 08.06.14.
*/
public class ReportHelper implements Thread.UncaughtExceptionHandler {
private final AlertDialog dialog;
private Context context;
public ReportHelper(Context context) {
this.context = context;
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage("Application was stopped...")
.setPositiveButton("Report to developer about this problem.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
})
.setNegativeButton("Exit", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Not worked!
dialog.dismiss();
System.exit(0);
android.os.Process.killProcess(android.os.Process.myPid());
}
});
dialog = builder.create();
}
#Override
public void uncaughtException(Thread thread, Throwable ex) {
showToastInThread("OOPS!");
}
public void showToastInThread(final String str){
new Thread() {
#Override
public void run() {
Looper.prepare();
Toast.makeText(context, "OOPS! Application crashed", Toast.LENGTH_SHORT).show();
if(!dialog.isShowing())
dialog.show();
Looper.loop();
}
}.start();
}
}
When i start app as you see i throwed NullPointerException. Toast in my handling logic was showed, and dialog was showed too. BUT! Dialog clicks was not handling correct. I mean logic in onClick method was not worked. What the problem and how i can fix that?
In my case, I moved AlertDialog.Builder in thread run function like this:
public void showToastInThread(final String str){
new Thread() {
#Override
public void run() {
Looper.prepare();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage("Application was stopped...")
.setPositiveButton("Report to developer about this problem.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
})
.setNegativeButton("Exit", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Not worked!
dialog.dismiss();
System.exit(0);
android.os.Process.killProcess(android.os.Process.myPid());
}
});
dialog = builder.create();
Toast.makeText(context, "OOPS! Application crashed", Toast.LENGTH_SHORT).show();
if(!dialog.isShowing())
dialog.show();
Looper.loop();
}
}.start();
}
and all thing work perfectly.
Hope this help you.
According this post, the state of the application is unknown, when setDefaultUncaughtExceptionHandler is called. This means that your onClick listeners may not be active anymore.
Why not use this method:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
setContentView(R.layout.main);
Thread.setDefaultUncaughtExceptionHandler(new ReportHelper(this));
throw new NullPointerException();
} catch (NullPointerException e) {
new ReportHelper(this);
}
}
and remove ReportHelper implementing the Thread.UncaughtExceptionHandler interface.
Your method of not explicitly catching exceptions can be seen as an anti-pattern.
Since an exception occurs on the UI-Thread: the state of this thread is probably unexpected
So try simply this in your click handler :
.setNegativeButton("Exit", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
android.os.Process.killProcess(android.os.Process.myPid());
}
});

AlertDialog not working as expected

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);
}
});

Can't create handler inside thread that has not called Looper.prepare()-Alertdialogbox [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can’t create handler inside thread that has not called Looper.prepare()
I want to call the alertdialogbox in the thread as follows
public class connect implements Runnable
{
public void run() //run method
{
AlertDialog.Builder alert = new AlertDialog.Builder(cordovaExample.activity);
alert.setTitle("Confirm");
alert.setMessage("Are you sure?");
alert.setPositiveButton("YES", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Do nothing but close the dialog
dialog.dismiss();
}
});
alert.setNegativeButton("NO", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Do nothing
dialog.dismiss();
}
});
AlertDialog s = alert.create();
alert.show();
}
}
I am calling this thread from the following activity
public class cordovaExample extends DroidGap
{
Context mcontext;
public static cordovaExample activity;
private static MediaPlayer music=null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
activity=this;
super.init();
new Thread(new connect(this)).start();
}
}
but its giving error
Can't create handler inside thread that has not called Looper.prepare()
Any help will be appreciated
Write this line in App UI thread
alert.show();
Something like this
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
alert.show();
}
});
you cant do changes in ui while thread is running.If u want to do so,Use Handler or runOnUiThead or best option is to use AsyncTask.

Android - How to make some validations in sequence

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();
}
}
}

Categories

Resources