I know this is a kind of weird title to describe the question. I have a code as below:
new AlertDialog.Builder(getActivity()).setView(myScrollView)
.setPositiveButton("Sent Query", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
try {
JSONStringURL = myURL_here;
image = new AsyncTaskParseJson1(JSONStringURL).execute().get();
if (image.size() == 0) {
Toast.makeText(getActivity(), "no data", Toast.LENGTH_LONG).show();
} else {
overlayImage(image);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}.show();
when i press "Positive Button", the app should cancel the AlertDialog immediately, and then execute the AsyncTask. Unfortunately, the AlertDialog will lag for 3~4 sec and then run the AsyncTask makes the UX feel really bad, but i have no idea why it will lag?
NEVER use AsyncTask.get(). That makes you wait for the task to finish, which totally ruins the idea of it being asynchronous. The fact the function even exists is a design flaw in Android. Instead, anything that needs to be done after the AsyncTask finishes should be done in onPostExecute() of the task (or in a function called from there).
Obviously this is your problem- you aren't closing the dialog and doing the task in parallel, you're waiting for the task to finish (remember the UI will not update until control is returned to the UI thread looper).
You have to use these changes
dialog.dismiss();
In place of
dialog.cancel();
Related
I'm working on an android app and I need to fetch data from internet.
I declare an "private Progress dialog" in Homepage.java.
In onCreate() method, call the function
dialog = ProgressDialog.show(Homepage.this, "Connecting", "Please wait for a while...", true);
And create another thread to fetch the data, and in finally block, call
"dialog.dismiss()"
The whole onResume() code is shown in below.
#Override
protected void onResume(){
super.onResume();
Log.e(TAG, "onResume");
dialog = ProgressDialog.show(Homepage.this, "Connecting", "Please wait for a while..", true);
/******Start fetching data.******/
Thread getDataThread = new Thread() {
#Override
public void run() {
try {
try {
getData();
} catch (JSONException e) {
alert_error();
e.printStackTrace();
} catch (IOException e) {
alert_error();
e.printStackTrace();
} finally {
dialog.dismiss();
}
} catch (SQLException e) {
alert_error();
e.printStackTrace();
} catch (ExecutionException e) {
alert_error();
e.printStackTrace();
} catch (InterruptedException e) {
alert_error();
e.printStackTrace();
}finally{
dialog.dismiss();
}
}
};
getDataThread.start();
}
At first, this worked great.(the spinner showed)
But at some point(I don't remember when), the dialog still works, but the spinner disappear
Show as below(place marked with red line should be the place where spinner display)
Spinner is gone
The dialog still works, but all ProgressDialog called anywhere from this app, the spinner is gone.(not even show up)
If I changed the getting data from internet part to sleeping for 10 secs
Which is shown below
#Override
protected void onResume(){
super.onResume();
Log.e(TAG, "onResume");
dialog = ProgressDialog.show(Homepage.this, "Connecting", "Please wait for a while...", true);
/******Start fetching data.******/
Thread getDataThread = new Thread() {
#Override
public void run() {
try {
sleep(10*1000);
} catch (InterruptedException e) {
e.printStackTrace();
dialog.dismiss;
}
}
};
getDataThread.start();
}
The spinner still doesn't show up.
I think that might be something related to global settings or values in my project, I create a empty activity with only one method other than super.onCreate and setContentView
I called
"ProgressDialog dialog = ProgressDialog.show(Homepage.this, "123", "456", true);"
and the spinner still doesn't show up!
But if I create a new project and added the same code, it works!
Thanks in advance!
I think the problem is in your phone setting, I had the same issue once, what you need to do is:
Go to developer options in your phone setting.
Turn transition on (in my case i had them turned off to make the phone act fast)
Restart the app and hopefully spinner will be there.
UPDATE:
Or you can try a library like Material Dialogs for that purpose, its one of my favorites, all you need to do is
Compile
compile 'com.afollestad.material-dialogs:core:0.8.6.0'
and then where you want to show the dialog
new MaterialDialog.Builder(this)
.title(R.string.progress_dialog)
.content(R.string.please_wait)
.progress(true, 0)
.show();
you can find more info here to customize it further and usage details.
Hope it helps
I'm trying to update the UI multiple times in an AsyncTask.
First of all the UI should update, if a request was accepted and later it should run the publishProgress, but If I return a value in the requestAccepted method the other acceptedFiles method will never be executed, but I want it to execute and update the UI before from this task
#Override
protected Void doInBackground(FileInformationHandler... params) {
try {
handler.createSecureSocket("192.168.3.29", 7431);
ProtocolHandler phandler = new ProtocolHandler(handler.getInputStream(), handler.getOutputStream());
phandler.sendInitialisation();
ConfirmationHandler cHandler = new ConfirmationHandler(handler.getInputStream(), handler.getOutputStream());
cHandler.addListener(new ConfirmationReceivedListener() {
#Override
public void requestAccepted(boolean b) {
// Update UI without stopping the asynctask
}
#Override
public void acceptedFiles(int[] ints) {
fileSender.addListener(new ProcessListener() {
#Override
public void processChanged(int i, long l) {
publishProgress(i);
}
});
}
});
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
First of all you don't need to use an Async task if you are anyways doing the long running operation in a separate thread and have callbacks for different states.
So in your case why can't you simply so all of this in the main thread and in the callbacks just update the UI.
But if you still want to use the Async task then since the doInBackground executes in a separate thread, you can do whatever long running operation is in the method serially and keep using the publishProgress method to update the UI whenever you want. since you are using the callback interface in your case the method will return null and the control with go into the 'onPostExecute'.
IMO using a callback interface in the doInBackground method is not the right approach and defeats the purpose of asyncTask async task.
I have some asynctasks in my application that do network functions (download/upload files,http requests) in the background.While these actions are in progress I use ProgressDialog in order to display messages about the progress of the task. However some tasks may require more time to complete (for example downloading a file on a slow network) and this is something unwanted in the application.
How can I set a parameter to control the duration of each asynctask? I want the asynctask to complete at some point regardless of the completion of the job in the task. I have to make the asynctask call the onPostExecute method.
I read about this http://developer.android.com/reference/android/os/AsyncTask.html#get%28long,%20java.util.concurrent.TimeUnit%29
This was not very helpful because the UI would freeze and there was no actual control of the duration of the asynctask
This is a part of my code
public void downloadFiles(String address) {
String mainUrl =address;
//// I overrride the onPostExecute to get
/// results and call another asynctask
new Downloader(this){ //<--asynctask
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
TestResults=result;
//another method called that creates another asynctask
uploadFiles(mainUrl);
}
}.execute(mainUrl);
}
I also tried to use a Handler like this
But it didn't work either.
Is there a way to make the asynctask return results (which means to make asynctask call onPostExecute method) after a period of time ?
Using a while loop in the doInBackground method of asnctask is not the solution. I guess I need a timer from the mainUI to make the asynctask return results.
PS I have my application using fragments, that is why I call new Downloader(this) to pass the gui from the fragment.
Just tried this:
public void downloadFiles(String address) {
String mainUrl =address;
final Downloader tempObject =new Downloader(this){
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
downloadResults=result;
}
};
try {
tempObject.execute(mainUrl).get(3000L, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This would make the UI freeze for 3 seconds and then the task would be evoked.... Which is not what I want.
Also tried out this:
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run() {
if ( tempObject.getStatus() == Downloader.Status.RUNNING )
tempObject.cancel(true);
}
}, 5000 );
This would cause the message of onProgressUpdate of asynctask to stop, however the asynctask keeps running....
Any ideas ?
The methodology of the Handler function needs something additional to work. The solution to the problem lies here
AsyncTask may be canceled, however the doInbackground method is still running. Actually the task is set to value "cancel", but the doInbackgroung will still be running until it finishes. To solve this we must periodically check within a loop in doInbackground to see whether the task was set to cancel. Although this is not exactly what I wanted to do, this seems to be the only solution.
In doInBackground we have to check for the status of the task to see whether it was cancelled or not. So actually ,someone could just have the timer inside the doInbackground and make life easier without using the handler class.
I find it disappointing that one can not just terminate the execution of a synctask at will..... If anyone has a better idea, please let me know.
I am implementing following simple functionality.
I have a simple button, clicking on which I am able to login to Facebook. I am using Facebook SDK for the same. When I click , the src image of the button(imageview) also gets updated.
Up to this point everything works fine. But when i click on the same button for logging out
I get a
android.os.networkonmainthreadexception
exception.
Can anyone please help me solve this issue?
EDIT:
my code is as follows:
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.fb_button:
try{
if(fb.isSessionValid())
{
try {
fb.logout(getBaseContext());
update_fb_buttonimage();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//button close session
}
else
{
fb.authorize(LoginPage.this, new DialogListener(){
#Override
public void onFacebookError(FacebookError e)
{
Toast.makeText(LoginPage.this, "on Facebook error", Toast.LENGTH_SHORT).show();
}
#Override
public void onError(DialogError e)
{
Toast.makeText(LoginPage.this, "on error", Toast.LENGTH_SHORT).show();
}
#Override
public void onComplete(Bundle values)
{
update_fb_buttonimage();
Toast.makeText(getBaseContext(), "onComplete works",Toast.LENGTH_LONG).show();
}
#Override
public void onCancel()
{
}
});
//login in to facebook
}
}catch(Exception e){
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
}
thankyou!
The problem here is simply that you need to make your web service calls (or what-have-you) on a separate thread. So, quite simply, you’ll need to look into how to do threading with Android. Unfortunately this can be a bit of a pain because you need to make your service calls on a separate thread, but you need to update the UI on the main thread. Normally this would require passing data between the threads, which involves handlers or other complexities. Luckily the Android platform provides the Async Task to handle this, which alleviates some of this complexity and may help you avoid some clutter in your code.
This exception is thrown when an application attempts to perform a networking operation on its main thread. Run your code in AsyncTask
I must use Thread in an Android project. Sometimes, it works corectly, however sometimes does not; it does not start (does not call SendToServer() method)or it starts but return to another function suddenly (return updated; line)before the thread does not finish.
Note: affected value is bigger than 0, it gives condition and it goes to if statement.
Here is the my code sample;
public static Boolean MyUpdateFunction(MyObject myobject){
Boolean updated=false;
//Code for updating local database
int affected= SqliteDb.update(....);
if(affected>0)
{
//Send updated data to server
//For this I must use Thread(I can't use AsyncThread)
updated=true;
SendToServer();
}
return updated;
}
public static void SendToServer()
{
try{
;
Thread th=new Thread(new Runnable() {
public void run() {
try {
//Create data and send it to server
//.......
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
th.start();
th.join();
}
catch(SQLException e)
{
Toast.makeText(myContext,"ERROR: "+e.getMessage(), Toast.LENGTH_LONG).show();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Other people are correct in that an AsyncTask is the way forward, but the direct problem due to what you're experiencing is this (and as such, I would recommend reading up on how Threading works):
When you start the thread, it begins a new process. The UI thread (which is generally where the majority of your code is) continues. So your code will fire the thread with SendToServer(), and then by definition will immediately return updated, as the UI thread immediately goes to the next line.
What you need is a callback from your Thread, which is handled in the onPostExecute() method of an AsyncTask. There's a good tutorial on how to use them and what they do here
Edit:
I've just seen from a comment above that you can't use Asynctasks, fair enough, but you still need a callback/event fired from your Thread to return any results
Instead of using threads and your variables (updated and affected), you can use AsyncTasks: see: http://developer.android.com/reference/android/os/AsyncTask.html
With AsyncTask, you have some methods which are doing exactly what you want:
onPreExecute
doInBackground
onPostExecute
So, what you can do is to check your condition in onPreExecute, then do your SendToServer in the doInBackground and onPostExecute do what you need.