I'm having some problems running a thread in my android application, It should show a dialog asking the user something and if the user clicks yes, a loading dialog should appear while it's doing something in the background, I created a thread but when I click the yes button, the UI still locks up until the process is done.
Code:
Dialog:
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("LOGO.bin Was Not Found, Would You Like To Extract It?")
.setTitle("LOGO Not Found!");
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
getAndExtract();
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
System.exit(0);
}
});
AlertDialog dialog = builder.create();
dialog.show();
getAndExtract:
public void getAndExtract()
{
new Thread(new Runnable() {
#Override
public void run() {
try {
showLoad("Grabbing Logo...");
getLogo();
Thread.sleep(2000);
progressDialog.cancel();
showLoad("Extracting Images...");
extractImages();
Thread.sleep(2000);
progressDialog.cancel();
}catch (InterruptedException iE)
{
iE.printStackTrace();
}
}
}).run();
}
showLoad:
progressDialog.setMessage(msg);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.show();
basics of extractImages:
Command cmd = new Command(0, "LogoInjector -i " + getFilesDir() + "/LOGO.bin -d -g " + getFilesDir() + "/");
RootTools.getShell(true).add(cmd);
basics of getLogo:
Command cmd = new Command(0, "dd if=/dev/block/mmcblk0p" + partitionIndex + " of=" + getFilesDir() + "/LOGO.bin");
RootTools.getShell(true).add(cmd);
I also tried putting showLoad in runOnUiThread but there was no change... if I remove progressDialog.cancel(); it does show the loading dialog but after the extract is already complete. I press Yes and it just hangs until getLogo() and extractImages() both completed
Can anyone help me find out why this isn't working?
Thanks!
Try using AsyncTask:
final AsyncTask<Void,Void,Void> asyncTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// do whatever you need to do in background
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute( aVoid);
// do after finished
}
};
asyncTask.execute();
Hope that helps =]
Related
I am trying to send email using async method as shown below and everything is working fine..
Now I would like to display a dialog on successfull email.
This is my async code:
public void sending(View v) {
try {
LongOperation l=new LongOperation();
l.execute();
Toast.makeText(this, l.get(), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e("SendMail", e.getMessage(), e);
}
}
public class LongOperation extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
try{GMailSender sender = new GMailSender("XXX#gmail.com","Pwd");
sender.sendMail("Sub",
"body",
"sender",
"recepient");
}
catch(Exception e){Log.e("error",e.getMessage(),e);return "Email Not Sent";}
return "Email Sent";
}
#Override
protected void onPostExecute(String result)
{
}
#Override
protected void onPreExecute()
{
}
#Override
protected void onProgressUpdate(Void... values)
{
}
In the above code if the mail is not sent I'm getting a toast as "Email Sent" and If not send the email I would get "Email Not Sent"
1)In the place of toasts I would like to display a dialog.
2)I have done it in onPostExecute and it worked fine.
But here comes the problem.Suppose if there is no internet connection and user clicks the button both the toast "Email Not sent" and the dialog is displaying after onPostExecute method.
I would only like to display the dialog.
So how do I modify the above code inorder to remove the toasts and only get the dialog for successfull and unsuccessfull email.
Here is my dialog code:
new AlertDialog.Builder(MainActivity.this)
.setTitle("Info")
.setMessage("Sample message.")
.setPositiveButton("OK",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
Log.d("AlertDialog","Positive");
}}).show();
Still not completely sure I understand the problem but maybe this is what you want.
public void sending(View v) {
try {
LongOperation l=new LongOperation();
l.execute();
} catch (Exception e) {
Log.e("SendMail", e.getMessage(), e);
}
}
public class LongOperation extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
try{GMailSender sender = new GMailSender("XXX#gmail.com","Pwd");
sender.sendMail("Sub",
"body",
"sender",
"recepient");
}
catch(Exception e){Log.e("error",e.getMessage(),e);return "Email Not Sent";}
return "Email Sent";
}
#Override
protected void onPostExecute(String result)
{
if ("Email Sent".equals(result))
{
new AlertDialog.Builder(MainActivity.this)
.setTitle("Info")
.setMessage("Sample message.")
.setPositiveButton("OK",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
Log.d("AlertDialog","Positive");
}}).show();
}
#Override
protected void onPreExecute()
{
}
#Override
protected void onProgressUpdate(Void... values)
{
}
I simply removed the Toast since you don't want that at all. Then I placed the Dialog code in onPostExecute() and checked the result passed to it from doInBackground(). I only showed it if the result is "Email Sent". You can change that to pass back a different result from doInBackground() if it isn't sent and show a different message in your Dialog.
Edit
I almost forgot to mention, you almost never want to use .get() on an AsyncTask. It is a blocking call which means everything will halt until your task is finished. You update the UI in any task method besides doInBackground() or you use an interface with a callback.
See this answer if you need an interface
For some reason my call to AsyncTask.cancel only works once, i.e. for the first instance of the task, and never again. The first task cancels beautifully and hits the onCancelled method. All the others seem to ignore the cancel() call and end up in onPostExecute.
The task is executed from a service:
public class ZitFtpService extends Service implements ZitFtpServiceInterface
{
//Blah blah
public void connect(String server, int port)
{
if(!isConnecting){
isConnecting = true;
ConnectTask task = new ConnectTask();
task.execute(server, String.valueOf(port));
}
}
//Blah blah blah
As you can see it is a new instance every time. I can't see why the first one would behave differently from the subsequent ones. The AsyncTask is a private inner class:
private class ConnectTask extends AsyncTask<String, String, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
boolean result = false;
try {
publishProgress(
"start", "Connecting to "+ params[0] + ":" + params[1]);
Log.v("ZIT", params[0] + " " + params[1] + " " + params.length);
conn.connect(params[0], Integer.valueOf(params[1]), 1000);
result = true;
} catch (NumberFormatException e) {
Log.e("ZIT", e.getMessage());
} catch (IOException e) {
failMessage = e.getMessage();
e.printStackTrace();
}
return Boolean.valueOf(result);
}
private void cancelConnect() {
try {
conn.disconnect();
} catch (IOException e) {
e.printStackTrace();
} finally {
conn = new ZMobileFTPImpl();
}
if(!(dialog==null)) {
dialog.dismiss();
}
}
#Override
protected void onCancelled() {
Log.v("ZIT", "I was cancelled.");
isConnecting = false;
}
#Override
protected void onProgressUpdate(String... values) {
if(dialog == null) {
dialog = new ProgressDialog(progressActivity);
dialog.setCancelable(true);
dialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
ConnectTask.this.cancel(true);
cancelConnect();
dialog.dismiss();
}
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
}
dialog.setMessage(values[1]);
dialog.setCancelable(true);
dialog.show();
}
#Override
protected void onPostExecute(Boolean result) {
dialog.dismiss();
if(!result) {
AlertDialog.Builder builder =
new AlertDialog.Builder(progressActivity);
builder.setMessage(failMessage).setTitle("Error");
failMessage = "";
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog failDialog = builder.create();
failDialog.show();
}
isConnecting = false;
}
}
From Doc's
There are a few threading rules that must be followed for this class to work properly:
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
So, you can call an AsyncTask multiple times by creating new instance every time like
new ConnectTask().execute(params);
This is intentional as you can only execute an AsyncTask instance once, you can run task.execute multiple times though...
Anyhow, I believe you forgot to add the super.onCancelled in following override:
#Override
public void onCancelled() {
//...
super.onCancelled();
}
Try if that helped, and otherwise you should share the error or log so we can troubleshoot that :)
On click of a button, I want to open a dialog box. On that dialog box I want to set the text dynamically (somewhat like a stopwatch) with the text which will come via a loop. Could someone please guide me with sample code? I tried many examples given on the net but not able to successfully achieve the result.
//Button where the action starts
public void onClickStart(View v) {
final Dialog dialog = new Dialog(MainActivity.this);
dialog.setContentView(R.layout.activity_details);
dialog.setTitle("Your Step Details");
dialog.show();
DisplayTask dd= new DisplayTask();
dd.execute();
}
public void doWork(){
final Handler handler=new Handler();
new Thread(new Runnable (){
boolean isRunning=true;
#Override
public void run() {
while(isRunning){
try{
handler.post(new Runnable(){
#Override
public void run() {
try{
TextView txtCurrentTime= (TextView)findViewById(R.id.txtLeft);
Date dt = new Date();
int hours = dt.getHours();
int minutes = dt.getMinutes();
int seconds = dt.getSeconds();
String curTime = hours + ":" + minutes + ":" + seconds;
txtCurrentTime.setText(curTime);
}catch (Exception e) {}
}
});
}catch(Exception e){
}
}
}
}).start();
}
public class DisplayTask extends AsyncTask<Void , Void, Void> {
protected void onPostExecute(){
MainActivity main= new Mai`enter code here`nActivity();
main.doWork();
}
#Override
protected Void doInBackground(Void... params) {
onPostExecute();
return null;
}
}
If you want to do something on a timer, AsyncTask isn't the right method. Use a Handler, and post a message to it using postMessageDelayed. This will let you do something in a few milliseconds/seconds, but it will happen on the UI thread.
I want to create a dialogBuilder with a text field and a button on it. The idea is to make the program wait for any further actions until the text in the field is entered and the OK button is clicked. Below is the code:
private static final Object wait = new int[0];
private static String result = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Handler h = new Handler();
final Context context = MainActivity.this;
h.post(new Runnable() {
public void run() {
final Builder dialogBuilder = new AlertDialog.Builder(context);
dialogBuilder.setTitle(R.string.app_name);
final LinearLayout panel = new LinearLayout(context);
panel.setOrientation(LinearLayout.VERTICAL);
final TextView label = new TextView(context);
label.setId(1);
label.setText(R.string.app_name);
panel.addView(label);
final EditText input = new EditText(context);
input.setId(2);
input.setSingleLine();
input.setInputType(InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_URI
| InputType.TYPE_TEXT_VARIATION_PHONETIC);
final ScrollView view = new ScrollView(context);
panel.addView(input);
view.addView(panel);
dialogBuilder
.setCancelable(true)
.setPositiveButton(R.string.app_name,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int id) {
result = input.getText().toString();
synchronized (wait) {
wait.notifyAll();
}
dialog.dismiss();
}
}).setView(view);
dialogBuilder.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface arg0) {
result = null;
synchronized (wait) {
wait.notifyAll();
}
}
});
dialogBuilder.create().show();
}
});
String localResult = null;
try {
synchronized (wait) {
Log.d("Waiting", "Waiting " + localResult);
wait.wait();
}
localResult = result;
result = null;
if (localResult == null) {
// user is requesting cancel
throw new RuntimeException("Cancelled by user");
}
Log.d("RESULT ", "RESULT " + localResult);
} catch (InterruptedException e) {
localResult = result;
result = null;
if (localResult == null) {
// user is requesting cancel
Log.d("CANCELED ", "CANCELED " + localResult);
throw new RuntimeException("Cancelled by user");
}
}
Log.d("RESULT AFTER THE DIALOG", "RESULT AFTER THE DIALOG " + result);
}
The program is going to Log.d("Waiting", "Waiting " + localResult); and after that just waiting. NO DIALOG BUILDER IS SHOWN on the activity window. I used the debug mode and saw that the program flow is not entering the run() method, but the value of the Handler.post() is true. And for this reason the dialog is not shown, and the program is waiting.
I have tried to remove the moment with waiting (remove the Handler.post()), just to see if the dialog will show, and it showed and all moved well, but the result was not I am needing - I want the program to wait the input from the dialog ... I am really out of ideas.
Would you please give me some suggestions as I am really out of ideas.
Thanks a lot!
Handlers don't run in a separate thread. So when you call wait() :
synchronized (wait) {
Log.d("Waiting", "Waiting " + localResult);
wait.wait();
}
It waits indefinitely since the handler runs on the same thread as the current thread. Your Runnable can only be executed after the onCreate() method finishes but this will never happen because you just called wait().
You should reconsider your idea and find a workaround (for example, show the dialog the usual way and disable the "OK" button as long as the user does not enter a valid text). But calling wait() on the UI thread cannot go well.
You should be running the display of the Dialog in the UI Thread, not a seperate thread.
An example would be something like this:
In the onCreate()
runOnUiThread(new Runnable() {
#Override
public void run() {
// Display progress dialog when loading contacts
dialog = new ProgressDialog(this);
// continue with config of Dialog
}
});
// Execute the Asynchronus Task
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// code to execute in background
return null;
}
#Override
protected void onPostExecute(Void result) {
// Dismiss the dialog after inBackground is done
if (dialog != null)
dialog.dismiss();
super.onPostExecute(result);
}
}.execute((Void[]) null);
Specifically what is happening here is the Dialog is being displayed on the UI thread and then the AsyncTask is executing in the background while the Dialog is running. Then at the end of the execution we dismiss the dialog.
i am calling this function from the menu and calls the upload(item) function to pass the index of the selected priority.
public void showPriorityDialog()
{
final CharSequence[] priority = {"1 Hour", "12 Hours", "24 Hours", "Cancel"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Select Priority");
builder.setItems(priority, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if(item != 3)
upload(item);
}
});
AlertDialog alert = builder.create();
alert.show();
}
however, whenever i call the upload function, the thread doesn't run in background, and the OS thinks that the app is not responding due to executing timeout.
public void upload(int priority)
{
final int _priority = priority;
uploadThread = new Thread()
{
#Override
public void run()
{
try
{
super.run();
mHandler.post(new Runnable() {
#Override
public void run() {
try
{
//ftp commands...
}
catch (Exception e)
{
Toast.makeText(getApplicationContext(), e.toString() , Toast.LENGTH_SHORT).show();
}
}
});
}
catch (Exception e)
{
Toast.makeText(getApplicationContext(), e.toString() , Toast.LENGTH_SHORT).show();
}
}
};
uploadThread.start();
}
am i doing something wrong? TIA
When you do mHandler.post(), your entire Runnable executes on UI thread and your background thread just exits. To fix, do FTP before posting to handler. Then do mHandler.post() to have Toast appear. Note that you catch also need to display Toast via post.