Seems like the displayView variable is not compatible with void, i try to add a progress dialog into a navigation drawer, every time that an element its selected
public class AsyncClass extends AsyncTask<Void, String, Void> {
private Context context;
ProgressDialog dialog = new ProgressDialog(context);
public AsyncClass(Context cxt) {
context = cxt;
}
#Override
protected void onPreExecute() {
dialog.setTitle("Please wait");
dialog.show();
}
#Override
protected Void doInBackground(Void... unused) {
public void displayView(int position) { /*the message here is :void is an invalid type for the variable displayView*/
Fragment fragment = null;
switch (position) {
case 1:
fragment = new HomeFragment();
break;
case 2:
fragment = new CalendarioFragment();
break;
case 5:
fragment = new ContactoFragment();
break;
case 6:
fragment = new OnclickFragment();
break;
default:
break;
}
if (fragment != null) {
try{
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();
// update selected item and tit|le, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
catch(Exception E)
{
Log.e("MainActivity", "Error in creating fragment");
}
}
else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
SystemClock.sleep(2000);
return (null);
}
#Override
protected void onPostExecute(Void unused) {
dialog.dismiss();
}
}
it says "void is an invalid type for the variable displayView"
First of all Java doesn't support nested methods, which you are doing in doInBackground(). This is the reason for given error. Check here in details.
Another thing is that, doInBackground() will be running on background thread so don't update UI from there. AsyncTask is used only for long running operations. You can consider moving you doInBackground() code to relevant Activity or Fragment.
Related
I use the GMS Drive sample demo.
I want to select a file (with Drive dialog open file), download the file, then finish the activity.
My problem is if I use finish() in the onActivityResult, I cannot get the result in my main activity, if I use finish() in the onPostExecute, the dialog is not closed, and I need to press "Cancel" to return to my main activity (with the result). I would like to return without pressing "cancel" button...
I use the RetrieveContentsActivity and PickFileWithOpenerActivity from the demo.
Here is my code :
public class RestoreActivity extends DriveActivity {
private static final int REQUEST_CODE_OPENER = 1;
#Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
IntentSender intentSender = Drive.DriveApi
.newOpenFileActivityBuilder()
.setSelectionFilter(Filters.contains(SearchableField.TITLE, "settings"))
.build(getGoogleApiClient());
try {
startIntentSenderForResult(intentSender, REQUEST_CODE_OPENER, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.w(TAG, "Unable to send intent", e);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_OPENER:
if (resultCode == RESULT_OK) {
DriveId driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
new RetrieveDriveFileContentsAsyncTask(RestoreActivity.this).execute(driveId);
}
finish(); // if I put finish() here, I cannot get the result in onActivityResult (main activity)
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
final private class RetrieveDriveFileContentsAsyncTask extends ApiClientAsyncTask<DriveId, Boolean, String> {
public RetrieveDriveFileContentsAsyncTask(Context context) {
super(context);
}
#Override
protected String doInBackgroundConnected(DriveId... params) {
String contents = null;
DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(), params[0]);
DriveApi.DriveContentsResult driveContentsResult = file.open(getGoogleApiClient(), DriveFile.MODE_READ_ONLY, null).await();
if (!driveContentsResult.getStatus().isSuccess()) {
return null;
}
DriveContents driveContents = driveContentsResult.getDriveContents();
BufferedReader reader = new BufferedReader(
new InputStreamReader(driveContents.getInputStream()));
StringBuilder builder = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
builder.append(line);
}
contents = builder.toString();
} catch (IOException e) {
Log.e(TAG, "IOException while reading from the stream " + e.toString());
}
driveContents.discard(getGoogleApiClient());
return contents;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Intent returnIntent = new Intent();
returnIntent.putExtra("settings",result);
if (result == null) {
Log.w(TAG, "Error");
setResult(RESULT_CANCELED,returnIntent);
} else {
Log.i(TAG, "OK");
setResult(RESULT_OK,returnIntent);
}
// if I put finish() here nothing happens, and dialog is still opened till I press "Cancel" button
}
}
}
How can I return to the main activity after onPostExecute and stop intent DriveApi ?
Thanks
I found a solution that I don't like : make it in 2 steps.
pick the file using the PickFileActivity from demo, return the driveId by declaring it public in MainActivity (public static DriveId driveId) and changing code like this :
MainActivity.driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
move the AsyncTask in my MainActivity.
If someone find another solution ?
I am trying to use AsyncTask and the activity is working perfectly but I am facing a problem. The problem comes after I have pressed back button, because pressing this button my app crashes. I have seen other posts saying that I must cancel the task in onStop() and onDestroy() but still crashes. Does anyone have any idea how can I solve that?
private class MyAsyncTask extends AsyncTask<Void, Integer, Boolean> {
#Override
protected Boolean doInBackground(Void... args0) {
for(int i=1; i<=10; i++) {
try{
if(isCancelled())
break;
publishProgress(i*10);
Thread.sleep(1000);
}catch (InterruptedException e){}
}
return null;
}
/*
* it will update the publishProgress method and it will
* update the interface (if it's necessary)
*/
#Override
protected void onProgressUpdate(Integer... values) {
int progreso = values[0].intValue();
pbarProgreso.setProgress(progreso); // showing progress
pbarProgreso.setSecondaryProgress(progreso + 5);
}
/*
* Initializing progressBar
*/
#Override
protected void onPreExecute() {
pbarProgreso.setMax(100); // maximum value for process bar
pbarProgreso.setProgress(0); // minimum value to start
}
#Override
protected void onPostExecute(Boolean result) {
if(!this.isCancelled())
Toast.makeText(getApplicationContext(), "Task finished!",
Toast.LENGTH_SHORT).show();
}
#Override
protected void onCancelled() {
Toast.makeText(getApplicationContext(), "Task cancelled!",
Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onStop() {
super.onStop();
if(task != null && task.getStatus() == Status.RUNNING){
task.cancel(true);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if(task != null && task.getStatus() == Status.RUNNING) {
task.cancel(true);
}
}
It's because when you press back button, AsyncTask continues to work, and when it do context related work, that context no longer exists, and a crash happens, it's better to use a "isResumed" boolean indicator variable inside an activity, and set it to false in onPause and set to true inside onResume, and inside an AsyncTask do context related things, inside an if condition.
Or if this code is inside a fragment, can use isAdded() method, to check if fragment is active or not. Cancel is also important, but there may be a delay, between an Activity pause and AsyncTask cancel, so keeping that variable is important.
I've 10 apps which uses AsyncTasks. As you know i show progressdialog in asynctasks to show progress of the task. But there is a problem that i couldn't solve so far about progressdialog.
Here is one of my AsyncTask class (which is not in a other class);
public class GetBalanceAsyncTask extends AsyncTask<Void, Void, String> {
Context context;
ProgressDialog pd;
public GetBakiyeAsyncTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(Void... arg0) {
String userAgent = HttpHelper.getRandomUserAgent(context);
return HttpHelper.post(PreferenceHelper.getBalanceQueryAPI(context), userAgent);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pd = ProgressDialog.show(context, "","Please wait...",true);
}
#Override
protected void onPostExecute(String result) {
try {
if (pd != null & pd.isShowing()) {
pd.dismiss();
pd = null;
}
} catch (IllegalArgumentException e) {
pd = null;
e.printStackTrace();
}
if (result != null & result.length() > 0) {
Utils.doTask(result);
} else {
Utils.ShowToast(context,
"An error has occurred, please try again.",
STYLE_CONFIRM, LENGTH_LONG);
}
super.onPostExecute(result);
}
}
and the execption is
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:381)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:226)
at android.view.Window$LocalWindowManager.removeView(Window.java:432)
at android.app.Dialog.dismissDialog(Dialog.java:278)
at android.app.Dialog.access$000(Dialog.java:71)
at android.app.Dialog$1.run(Dialog.java:111)
at android.app.Dialog.dismiss(Dialog.java:268)
at fragments.RuyalarFragment$getRuyalarAsyncTask.onPostExecute(GetBalanceAsyncTask.java:27)
at fragments.RuyalarFragment$getRuyalarAsyncTask.onPostExecute(GetBalanceAsyncTask.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:417)
at android.os.AsyncTask.access$300(AsyncTask.java:127)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
at dalvik.system.NativeStart.main(NativeStart.java)
I've searched the solution almost everywhere but there is no working results. Most of answers contain use isFinishing, onDestroy or something like this but no body is sure which is working.
Thanks for advice.
How to reproduce the bug:
Enable this option on your device: Settings -> Developer Options -> Don't keep Activities.
Press Home button while the 'AsyncTask' is executing and the ProgressDialog is showing.
The Android OS will destroy an activity as soon as it is hidden. When onPostExecute is called the Activity will be in "finishing" state and the ProgressDialog will be not attached to Activity.
How to fix it:
Check for the activity state in your onPostExecute method.
Dismiss the ProgressDialog in onDestroy method. Otherwise, android.view.WindowLeaked exception will be thrown. This exception usually comes from dialogs that are still active when the activity is finishing.
try this code :
public class YourActivity extends Activity {
<...>
private void showProgressDialog() {
if (pDialog == null) {
pDialog = new ProgressDialog(StartActivity.this);
pDialog.setMessage("Loading. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
}
pDialog.show();
}
private void dismissProgressDialog() {
if (pDialog != null && pDialog.isShowing()) {
pDialog.dismiss();
}
}
#Override
protected void onDestroy() {
dismissProgressDialog();
super.onDestroy();
}
class LoadAllProducts extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
showProgressDialog();
}
/**
* getting All products from url
* */
protected String doInBackground(String... args)
{
doMoreStuff("internet");
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url)
{
if (YourActivity.this.isDestroyed()) {
return;
}
dismissProgressDialog();
something(note);
}
}
}
Late to the party, but really this question has many duplicates on SO.
The most comprehensive summary of solutions I've found is here.
Basically use a retained Fragment to connect your AsyncTask to the new Activity.
I'm developing an android app that requires to make UI changes according to a background thread processing results, I tried the following code at first:
Thread run_time = new Thread (){
public void run(){
ConnectToServer connect = new ConnectToServer(null);
while(true){
String server_response = connect.getServerResponse();
if(!server_response.equals(null)){
setResponse(server_response);
response_received();
}
}
}
};
run_time.start();
but my App crashes because i tried to make a UI changes from that background thread, then I tried that way:
runOnUiThread(new Runnable() {
public void run(){
ConnectToServer connect = new ConnectToServer(null);
while(true){
String server_response = connect.getServerResponse();
if(!server_response.equals(null)){
setResponse(server_response);
response_received();
}
}
}
});
but i got that exception:
01-29 16:42:17.045: ERROR/AndroidRuntime(605): android.os.NetworkOnMainThreadException
01-29 16:42:17.045: ERROR/AndroidRuntime(605): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1084)
01-29 16:42:17.045: ERROR/AndroidRuntime(605): at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:151)
01-29 16:42:17.045: ERROR/AndroidRuntime(605): at libcore.io.IoBridge.recvfrom(IoBridge.java:503)
01-29 16:42:17.045: ERROR/AndroidRuntime(605): at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
01-29 16:42:17.045: ERROR/AndroidRuntime(605): at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:46)
and after search i found that I must run the code as AsyncTask to avoid these problems, but when attempting to use it i found that it's must be used with small tasks only not like a thread that runs in the background all the run_time.
So, what's the best day to run a thread or a task in the background in whole the run_time and also reflect it's changes to the UI.
EDIT:
For Long running network work you have a few options.
First and formost check the android docs on this topic:
http://developer.android.com/training/basics/network-ops/index.html
Next, I generally use Services for this type of thing:
https://developer.android.com/guide/components/services.html
I will point you at the vogella tutorial for this as well:
http://www.vogella.com/tutorials/AndroidServices/article.html
For communication from threads/asynctasks/services to the UI use Handlers:
Use Handlers:
static public class MyThread extends Thread {
#Override
public void run() {
try {
// Simulate a slow network
try {
new Thread().sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
downloadBitmap = downloadBitmap("http://www.devoxx.com/download/attachments/4751369/DV11");
// Updates the user interface
handler.sendEmptyMessage(0);
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
}
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// cal uiMethods here...
imageView.setImageBitmap(downloadBitmap);
// dialog.dismiss();
}
};
Taken from this tutorial:
http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html
You can make this more interesting by defining constant_codes which corespond to the desired action:
private int DO_THIS = 0x0;
private int DO_THAT = 0x1;
// in your UI:
public void handleMessage(Message msg) {
// cal uiMethods here...
switch(msg.what()){
case(DO_THIS):
// do stuff
break;
case(DO_THAT):
// do other stuff
break;
}
}
// in your thread:
Message m = handler.obtainMessage(DO_THIS);
handler.sendMessage(m);
If the thread code (asynch task, service etc...) is separate from the UI you can use Broadcasts to pass the data between the two and then use Handlers from there to act on the UI thread.
you need to use handlers
here is documntation: https://developer.android.com/training/multiple-threads/communicate-ui.html
Use this code - it may contain compile time error you have to do it correct
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Connect connect = new Connect();
connect.execute();
}
class Connect extends AsyncTask<Void, String, Void>
{
#Override
protected Void doInBackground(Void... params)
{
ConnectToServer connect = new ConnectToServer(null);
while(true)
{
String server_response = connect.getServerResponse();
if(!server_response.equals(null))
{
publishProgress(server_response);
//setResponse(server_response);
response_received();
}
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
setResponse(values[0]);
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
}
}
You need "handlers" along with "loopers" for optimization
Example:
public void myMethod(){
Thread background = new Thread(new Runnable(){
#Override
public void run(){
Looper.prepare();
//Do your server process here
Runnable r=new Runnable() {
#Override
public void run() {
//update your UI from here
}
};
handler.post(r);
Looper.loop();
}
});
background.start();
}
And of course this is without using AsyncTask
I have the following code:
try {
res = new Utils(ubc_context).new DownloadCalendarTask().execute().get();
} catch (InterruptedException e) {
Log.v("downloadcalendar", "interruptedexecution : " + e.getLocalizedMessage());
res = false;
} catch (ExecutionException e) {
Log.v("downloadcalendar", "executionexception : " + e.getLocalizedMessage());
res = false;
}
Log.v("displaymenu", "A");
public class Utils {
private Context context;
public Utils(Context context) {
this.context = context;
}
public class DownloadCalendarTask extends AsyncTask<Void, Void, Boolean> {
private ProgressDialog dialog;
public DownloadCalendarTask() {
dialog = new ProgressDialog(context);
}
protected void onPreExecute() {
Log.v("preexecute", "A");
dialog.setMessage("Loading calendar, please wait...");
Log.v("preexecute", "B");
dialog.show();
Log.v("preexecute", "C");
}
protected Boolean doInBackground(Void... arg0) {
// do some work here...
return (Boolean) false;
}
protected void onPostExecute() {
Log.d("utils", "entered onpostexecute");
dialog.dismiss();
}
}
}
The first part of code is attached to an onClick listener for a button. When I click the button the button flashes (as it does to show it has been clicked), and then after about 8 seconds the Loading dialog appears but never finishes.
According to logcat, as soon as I click the button onPreExecute is executed as is Dialog.show(), so my first problem is why is there this 8 second delay? During these 8 seconds, logcat shows that doInBackground is being executed. However, according to logcat (this is the second problem) onPostExecute is never called (and so Dialog.dismiss()) is never run.
Logcat shows that everything following DownloadCalendarTask().execute().get() is being executed, so it's as if onPostExecute has just been skipped.
Many thanks for your help!
You are calling AsyncTask.get() which causes the UI thread to be blocked while the AsyncTask is executing.
new DownloadCalendarTask().execute().get();
If you remove the call to get() it will perform asynchronously and give the expected result.
new DownloadCalendarTask().execute();
Edit:
You will also need to update the parameters to your onPostExecute method, they need to include the result. e.g.
protected void onPostExecute(Boolean result) {