I am trying to close progress dialog after exception occurred, but my current scenario is not allowing me to.
I have 3 classes:
MainActivity
SecondClass
ThirdClass
From MainActivity I am running a task using AsyncTask and shows a progress dialog, while a task is done in background.
#Override
public void onCreate(Bundle savedInstanceState)
{
// my code ...
BackgroundTask bt = new BackgroundTask();
bt.execute();
}
private class BackgroundTask extends AsyncTask<Void, Void, Void>
{
private ProgressDialog PD;
#Override
protected void onPreExecute()
{
PD = new ProgressDialog(getActivity());
PD.setMessage("Performing background tasks...");
PD.setCancelable(false);
PD.show();
}
#Override
protected Void doInBackground(Void... arg0)
{
// call SecondClass's getMyPhotos method to perform some tasks
// ...
return null;
}
protected void onPostExecute(Void... arg0)
{
Log.i("MainActivity", "--called--");
}
}
My SecondClass is simple Java class with some methods
public class SecondClass
{
// ....
public void getMyPhotos()
{
// from here I call ThirdClass's internetRelatedStuff method
}
}
And lastly in ThirdClass I am doing some internet related stuff in AsyncTask:
public class ThirdClass
{
// ....
public void internetRelatedStuff()
{
try
{
// again some other stuff...
// LoadImage asyncTask
LoadImage loadImg = new LoadImage();
loadImg.execute();
}
catch(Exception e)
{
if(e.getErrorCode() == 34)
{
// if I get an exception here, how am I suppose to close close Progress dialog
// of MainActivity
}
}
}
private class LoadImage extends AsyncTask<.......>
{
// .....
}
}
So in my ThirdClass's try/catch, is it possible if an exception occurred, I can close the Progress dialog which is showing from MainActivity?
Yes, there are multiple ways to do this. you can pass the ProgressDialog object in the MainActivity to the SecondClass's getMyPhotos() method then to the ThirdClass constructor then dismiss the dialog
There are couple of ways you can do this, let me point out two ....
You can pass your dialog from activity to SecondClass and then from SecondClass to third class, and use it there to close the dialog ... You will have define ProgressDialog in both second and thirdclass,
Create a static variable ProgressDialog in Activity and a static function closeDialogs()
where you can close your dialogs and you can call it using static ref. from third class,
I personally like this one ....
Related
In an existing app I have an activity with an inner class which extends AsyncTask, this looks like the following:
public class Activity_1 extends BaseActivity {
....
new async().execute();
...
public class asyncextends AsyncTask<Void, Void, String> {
protected String doInBackground(Void... progress) { ... }
protected void onPreExecute() { ... }
protected void onPostExecute(String result) { ... }
}
}
Now, I need to call the same doInBackground-method from another activity, but the onPostExecute() of the this inner class operates on some local UI variables and hence it's not possible to use it from outside the clas.
Is there any way I can call this AsyncTask, and just override the onPostExecute andonPreExecute-method, or shall I create yet another inner-class in the other activity, do the same background thing (of course move it to common utility-class or something), etc...?
You can make a separate abstract package private class, extending AsyncTask and implementing doInBackground() method:
abstract class MyAsyncTask extends AsyncTask<Void, Void, String> {
#Override
final protected String doInBackground(Void... progress) {
// do stuff, common to both activities in here
}
}
And in your activities just inherit from MyAsyncTask (new class probably should be private, by the way), implementing onPostExecute() and onPreExecute() methods:
public class Activity_1 extends BaseActivity {
...
new Async1().execute();
...
private class Async1 extends MyAsyncTask {
#Override
protected void onPreExecute(){
// Activity 1 GUI stuff
}
#Override
protected void onPostExecute(String result) {
// Activity 1 GUI stuff
}
}
}
If onPreExecute and onPostExecute contain some common actions as well, you can apply the following pattern:
abstract class MyAsyncTask extends AsyncTask<Void, Void, String> {
public interface MyAsyncTaskListener {
void onPreExecuteConcluded();
void onPostExecuteConcluded(String result);
}
private MyAsyncTaskListener mListener;
final public void setListener(MyAsyncTaskListener listener) {
mListener = listener;
}
#Override
final protected String doInBackground(Void... progress) {
// do stuff, common to both activities in here
}
#Override
final protected void onPreExecute() {
// common stuff
...
if (mListener != null)
mListener.onPreExecuteConcluded();
}
#Override
final protected void onPostExecute(String result) {
// common stuff
...
if (mListener != null)
mListener.onPostExecuteConcluded(result);
}
}
and use it in your activity as following:
public class Activity_1 extends BaseActivity {
...
MyAsyncTask aTask = new MyAsyncTask();
aTask.setListener(new MyAsyncTask.MyAsyncTaskListener() {
#Override
void onPreExecuteConcluded() {
// gui stuff
}
#Override
void onPostExecuteConcluded(String result) {
// gui stuff
}
});
aTask.execute();
...
}
You can also have your Activity implement MyAsyncTaskListener as well:
public class Activity_1 extends BaseActivity implements MyAsyncTask.MyAsyncTaskListener {
#Override
void onPreExecuteConcluded() {
// gui stuff
}
#Override
void onPostExecuteConcluded(String result) {
// gui stuff
}
...
MyAsyncTask aTask = new MyAsyncTask();
aTask.setListener(this);
aTask.execute();
...
}
I wrote the code from the head, so it might contain errors, but it should illustrate the idea.
Its so simple just Simply build an object of main class and than call the inner class like this
OuterMainClass outer = new OuterMainClass();
outer.new InnerAsyncClass(param)
.execute();
this answer is too late to help you but hope it help others.
Thanks
1.Create a constructor of AsynckTask in ClassOne.
2.Crate object or ClassOne by new keyword.
3.Call Async Task by object
ClassOne{
class AsyncParmas extends AsyncTask {
public ADDloadGeofenceDetails() {
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Object doInBackground(Object... params) {
}
}
Class ClassTwo{
ClassOne obj= new ClassOne ();
obj.new AsyncParmas ().execute();
}
}
GoodLuck Who were facing problem.
If we create one static method which is in one class and and will be execute in any class in doInBackground of AsyncTask we can easily update UI through same class and even in different class .
I hate inner class.
I've a main activity who launches a 'short-life' AsyncTask.
AsyncTask is in a separate file, is not an inner class of main activity
I need async task updates a textView from main Activity.
I know i can update a TextView from onProgressUpdate, if AsyncTask is a inner class
But how from an external, indipendent, async task ?
UPDATE: This looks like working :
In acitivty i call the task
backgroundTask = new BackgroundTask(this);
backgroundTask.execute();
In the constructor i've
public BackgroundTask(Activity myContext)
{
debug = (TextView) myContext.findViewById(R.id.debugText);
}
where debug was a private field of AsyncTask.
So onProgressUpdate I can
debug.append(text);
Thanks for all of you suggestions
AsyncTask is always separate class from Activity, but I suspect you mean it is in different file than your activity class file, so you cannot benefit from being activity's inner class. Simply pass Activity context as argument to your Async Task (i.e. to its constructor)
class MyAsyncTask extends AsyncTask<URL, Integer, Long> {
WeakReference<Activity> mWeakActivity;
public MyAsyncTask(Activity activity) {
mWeakActivity = new WeakReference<Activity>(activity);
}
...
and use when you need it (remember to NOT use in during doInBackground()) i.e. so when you would normally call
int id = findViewById(...)
in AsyncTask you call i.e.
Activity activity = mWeakActivity.get();
if (activity != null) {
int id = activity.findViewById(...);
}
Note that our Activity can be gone while doInBackground() is in progress (so the reference returned can become null), but by using WeakReference we do not prevent GC from collecting it (and leaking memory) and as Activity is gone, it's usually pointless to even try to update it state (still, depending on your logic you may want to do something like changing internal state or update DB, but touching UI must be skipped).
Using Interface
1) Create one Interface
public interface OnDataSendToActivity {
public void sendData(String str);
}
2) Implements it in your Activity
public class MainActivity extends Activity implements OnDataSendToActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
new AsyncTest(this).execute(new String[]{"AnyData"}); // start your task
}
#Override
public void sendData(String str) {
// TODO Auto-generated method stub
}
}
3) Create constructor in AsyncTask(Activity activity){}
Register your Interface in AsyncTask file
and call interface method as below.
public class AsyncTest extends AsyncTask<String, Integer, String> {
OnDataSendToActivity dataSendToActivity;
public AsyncTest(Activity activity){
dataSendToActivity = (OnDataSendToActivity)activity;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
dataSendToActivity.sendData(result);
}
}
Here, your OnPostExecute will call after all task done by AsyncTask and will get "result"
as a parameter, returned by doInBackground(){ return "";}.
While "dataSendToActivity.sendData(result);" it will call activity's overrided method "public void sendData(String str) {}".
An edge case to remember: Be sure to pass this, i.e. you current activity's context to AsyncTask and not create another instance of your activity, otherwise your Activity will be destroyed and new one is created.
Make an static function in your activity class passing context in it to update your text view and then call this function in your AsynkTask class to update.
In Activity class:
public static void updateTextView(){
//your code here
}
In AynckTask class call this function.
Just pass the context (activity or whatever) to your AsyncTask in a constructor and then in onSuccess or onProgressUpdate call whatever you need on the context.
I wrote a small extension to AsyncTask for this kind of scenario. It allows you to keep your AsyncTask in a separate class, but also gives you convenient access to the Tasks's completion:
public abstract class ListenableAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result>{
#Override
protected final void onPostExecute(Result result) {
notifyListenerOnPostExecute(result);
}
private AsyncTaskListener<Result> mListener;
public interface AsyncTaskListener<Result>{
public void onPostExecute(Result result);
}
public void listenWith(AsyncTaskListener<Result> l){
mListener = l;
}
private void notifyListenerOnPostExecute(Result result){
if(mListener != null)
mListener.onPostExecute(result);
}
}
So first you extend ListenableAsyncTask instead of AsyncTask. Then in your UI code, make a concrete instance and set listenWith(...).
The Question has already been answered, still im posting how it should be done i guess..
Mainactivity class
public class MainActivity extends Activity implements OnClickListener
{
TextView Ctemp;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Ctemp = (TextView) findViewById(R.id.Ctemp);
doConv = (Button) findViewById(R.id.doConv);
doConv.setOnClickListener(this);
}
#Override
public void onClick(View arg0) // The conversion to do
{
new asyncConvert(this).execute();
}
}
now in the async class
public class asyncConvert extends AsyncTask<Void, Void, String>
{
SoapPrimitive response = null;
Context context;
public asyncConvert(Context callerclass)
{
contextGUI = callerclass;
}
.
.
.
.
protected void onPostExecute(String result)
{
((MainActivity) contextGUI).Ctemp.setText(result); // changing TextView
}
}
/**
* Background Async Task to Load all product by making HTTP Request
* */
public static class updateTExtviewAsyncTask extends AsyncTask<String, String, String> {
Context context;
ProgressDialog pDialog;
String id, name;
String state_id;
//--- Constructor for getting network id from asking method
public updateTExtviewAsyncTask(Context context,String id,String city)
{
context = context;
state_id = id;
city_name = city;
}
/* *
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute()
{
super.onPreExecute();
pDialog = ProgressDialog.show(context, "","Please wait...", true, true);
pDialog.show();
}
/**
* getting All products from url
* */
protected String doInBackground(String... args)
{
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
YourClass.UpdateTextViewData("Textview data");
}
}
// place this code inside your activity class and also declare updating textview static
public static void UpdateTextViewData(String tvData)
{
tv.setText(tvData);
}
I have a tabgroup having multiple activities. In one of the tabs i have two activities between whom i want to place a progress dialog.For this i am using Asynk Task. Following is my AsynkTask class which i have made an inner class for AboutUs activity:
private class TheTask extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
progDialog = ProgressDialog.show(AboutUs.this.getParent(), "Loading... ",
"please wait....", true);
}
#Override
protected Void doInBackground(Void... params) {
final Intent aboutusIntent = new Intent(getParent(), Departments.class);
final TabGroupActivity parentActivity = (TabGroupActivity)getParent();
parentActivity.startChildActivity("Departments", aboutusIntent);
return null;
}
#Override
protected void onPostExecute(Void result) {
if(progDialog.isShowing())
{
progDialog.dismiss();
}
}
}
I am calling this class in my AboutUs activity :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aboutus);
.
.
.
.
/* Button for going to Departments */
Button ourdepbtn = (Button) findViewById(R.id.departmentsbutton);
ourdepbtn.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
//ourDepartments();
new TheTask().execute();
return false;
}
});
}
However this does'nt start a new activity i.e. Departments. The progress dialog appears and then disappears but activity never loads.
Any suggestions..??
First, you cannot start an activity from a non GUI thread (which Async doInBackground() is). Just start directly inside your Button.onClick() (why you use onTouch?) listener.
If you want to show up a ProgressDialog for the new Activity as soon as possible, you need to create it in the new (child) Activity onCreate(), as your ProgressDialog is connected to the new (child) activity (is it?). Take care about the order of creating layouts (create the ProgressDialog after calling setContentView()).
I am not very sure why you want to show that ProgressDialog. Is there something which delays the display of the childActivity? You loading some data? Then, the Dialog should be related to that loading task (Async I guess).
private class TheTask extends AsyncTask{
Context con;
Intent aboutusIntent;
TabGroupActivity parentActivity;
private TheTask(Context context)
{
this.con=context;
}
#Override
protected void onPreExecute() {
progDialog = ProgressDialog.show(con, "Loading... ",
"please wait....", true);
}
#Override
protected Void doInBackground(Void... params) {
aboutusIntent = new Intent(con, Departments.class);
parentActivity = (TabGroupActivity)getParent();
return null;
}
#Override
protected void onPostExecute(Void result) {
if(progDialog.isShowing())
{
progDialog.dismiss();
}
parentActivity.startChildActivity("Departments", aboutusIntent);
}
}
Thanks for your suggestions Oliver :)
When an Activity terminates, e.g. after screen orientation changing, is that possible to change an AsyncTask activity context? Else it will create an error because when the activity terminates AsyncTask's activity context is gone too.
My homework done is the following:
public void onSaveInstanceState(Bundle savedInstanceState) <- doesn't solve
public Object onRetainNonConfigurationInstance() <- doesn't solve
android:configChanges="keyboardHidden|orientation"
<- solved but doesn't handle well relative layouts
What do you pass on your onRetainNonConfigurationInstance()? What I do is pass an object to it containing the AsyncTask, and then I try to retrieve the value in getLastNonConfigurationInstance().
EDIT: On second thought, it would depend on what you want to do after a configuration change. If you want to terminate the AsyncTask, and then call cancel() on it. If you want to continue its processing even after an orientation change, then you have to hold on to the task.
You can do that by saving the Activity in the AsyncTask like this:
private MyAsyncTask searchTask;
#Override
public void onCreate(Bundle savedInstance){
super.onCreate(savedInstance);
if (getLastNonConfigurationInstance()!=null) {
SavedObject savedObj = (SavedObject)getLastNonConfigurationInstance();
searchTask = savedObj.getAsyncTask();
searchTask.attach(this);
} else {
searchTask = new MyAsyncTask(this);
searchTask.execute();
}
}
#Override
public Object onRetainNonConfigurationInstance(){
searchTask.detach();
final SavedObject savedObj = new SavedObject();
savedObj.setAsyncTask(searchTask);
return savedObj;
}
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
MyActivity parentActivity = null;
MyAsyncTask (MyActivity activity) {
attach(activity);
}
void attach(MyActivity activity) {
this.parentActivity=activity;
}
void detach() {
parentActivity=null;
}
// Do your thread processing here
}
private class SavedObject {
private MyAsyncTask asyncTask;
public void setAsyncTask(MyAsyncTask asyncTask){
this.asyncTask = asyncTask;
}
public MyAsyncTask getAsyncTask() {
return asyncTask;
}
}
in the OnCancel method of your asynch task put finish();
public void onCancel(DialogInterface dialog) {
cancel(true);
dialog.dismiss();
finish();
}
Dear Android hackers,
I am trying to do the following in my Android App: When the User clicks on a list item in a ListActivity, a ProgressDialog should show up, some preloading should happen and after it's done, another Activity should be called using an intent.
I tried different approaches. What didn't work at all was using an Async Task. Apparently I cannot show, dismiss or edit my ProgressDialog out of the Async Task, if that Class is not a Member of my original Activity.
I switched to a simple Thread then, this is how I'm trying to do it:
dialog = ProgressDialog.show(BookmarkActivity.this, "", "Loading...",true);
new Thread() {
public void run() {
// do something
dialog.setMessage("Change Message...");
// do more
dialog.dismiss();
// ...
Intent intent = new Intent(BookmarkActivity.this, ThreadActivity.class);
BookmarkActivity.this.startActivity(intent);
}
}.start();
This works almost, but the changing of the dialog message does not. I'm getting errors saying something about "leaked windows". (I can post the complete log if it is needed).
My questions:
How can I use an Async Task for this, where the Class has it's own file?
How can I change the ProgressDialog out of my Thread or AsyncTask without causing an error for changing the UI in another thread?
Thanks in advance, Jan Oliver
Ok, with the help of Jason, I put together this Async Task. That works!
public class ThreadPreLoader extends AsyncTask<Object, String, Void> {
private Activity mActivity;
private ProgressDialog mDialog;
public ThreadPreLoader(Activity activity) {
mActivity = activity;
}
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage("Loading...");
mDialog.show();
}
protected Void doInBackground(Object... args) {
publishProgress("Loading something else..");
return null;
}
protected void onProgressUpdate(String... msg) {
mDialog.setMessage(msg[0]);
}
protected void onPostExecute(Void result) {
mDialog.dismiss();
}
}
Thanks again, Jason.
You should use an Async Task, Define a custom Async Task which receives the context (this) of the original activity.
Then keep that context for later Dismissing the dialog.
From your doInBackground() method you can call postProgress( int progress) which will cause onProgressUpdate() to be called in the async task , this method is on the UI thread so it will not cause cross thread errors.
Once doInBackground() is complete the method onComplete() will also be called on the UI thread, this is where you can use your saved context and dissmiss the dialog (context.dissmissDialog()
Take a look at Android's Handler class. If you create the Handler in the onCreate method of your activity, Runnables that are sent to the post method of the handler are then run on the UI thread of your activity:
Handler h;
protected void onCreate(Bundle bundle) {
h = new Handler;
new Thread() {
public void run() {
// your run code
h.post(new Runnable() { /* change dialog here */ });
}
}.start();
}
I'm not sure that's the best option, but worth a try.
In AsyncTask
You should do you work which need time in doInBackground and calling intent like things, that you need to do after this task should be in onPostExecute
public class ThreadPreLoader extends AsyncTask<Object, String, Void> {
private Activity mActivity;
private ProgressDialog mDialog;
public ThreadPreLoader(Activity activity) {
mActivity = activity;
}
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage("Loading...");
mDialog.show();
}
protected Void doInBackground(Object... args) {
//do more
publishProgress("Loading something and reached somewhere..");
//do more
publishProgress("Loading something and reached somewhere..");
//do more
return null;
}
protected void onProgressUpdate(String msg) {
mDialog.setMessage(msg);
}
protected void onPostExecute() {
Intent intent = new Intent(BookmarkActivity.this, ThreadActivity.class);
BookmarkActivity.this.startActivity(intent);
mDialog.dismiss();
}
}