I have a class with DownloadPicture method which is executing an AsyncTask. The class is not a subclass of class MainActivity extends Activity. How can I show ProgressDialogs by using DownloadPicture method? I think I can pass MainActivity.this to class conatructor, but is there any other way?
Try this way,hope this will help you to solve your problem.
Pass your activity context to DownloadPicture class in constructor and initialize ProgressDialogs in onPreExecute() :
public class ProgressDialogs extends AsyncTask<Void,Void,Void>{
private Context context;
private ProgressDialog progressDialog;
public ProgressDialogs(Context context){
this.context=context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = ProgressDialog.show(context, "dialog title","dialog message", true);
}
#Override
protected Void doInBackground(Void... params) {
// do you background code here
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(progressDialog!=null && progressDialog.isShowing()){
progressDialog.dismiss();
}
}
}
Use an Interface to callback to activity from your AsyncTask. And you can do whatever with ProgressDialog from your activity. Can explain in detail if you can provide your code sample.
Related
I'm trying to do the simple act of hiding/showing ProgressBar according to AsyncTask state ,
I have two classes one extends FragmentActivity and second AsyncTask.
MainActivity.java
public class MainActivity extends FragmentActivity {
public static ProgressBar mProgressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
}
#Override
protected void onStart() {
super.onStart();
// What will happen to the progress bar here?
}
#Override
protected void onStop() {
super.onStop();
// What will happen to the progress bar here?
}
#Override
protected void onResume() {
super.onResume();
// What will happen to the progress bar here?
}
}
MyAsyncTask.java
public class MyAsyncTask extends AsyncTask<Void,Void, Void> {
#Override
protected Void doInBackground() {
// start download some images from cloud
// Here the progress bar should start to appear in MainActivity
// mProgressBar.setVisibility(View.VISIBLE);
}
#Override
protected void onPostExecute(Void result) {
Log.d(TAG, "Finished book downloading images the cloud");
// Here the progress bar should start to disappear in MainActivity
// mProgressBar.setVisibility(View.GONE);
}
}
main_activity.xml
<ProgressBar
android:id="#+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
Hope you understand me, thank to everyone who can help.
The progress bar should appear in onPreExecute() method (still in UI thread). Then you dismiss it when you get back to UI thread in onPostExecute method.
public class MyAsyncTask extends AsyncTask<Void,Void, Void> {
#Override
protected void onPreExecute(Void result) {
Log.d(TAG, "Finished book downloading images the cloud");
// Here the progress bar should start to disappear in MainActivity
mProgressBar.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground() {
// start download some images from cloud
// there is a time cost operation
}
#Override
protected void onPostExecute(Void result) {
Log.d(TAG, "Finished book downloading images the cloud");
// Here the progress bar should start to disappear in MainActivity
// mProgressBar.setVisibility(View.GONE);
}
}
You should use onPreExecute() method to show the dialog.
Here is MainActivity
#Override
protected void onResume() {
super.onResume();
new MyAsyncTask().execute();
}
I think you should read APIs first.
Use preExecute and postExecute methods as they run on UI thread.
public class MyAsyncTask extends AsyncTask<Void,Void, Void> {
ProgressBar pBar;
#Override
protected void onPreExecute(Void result) {
pBar=new ProgressBar(getContext());
pBar.show();
}
#Override
protected void onPostExecute(Void result) {
if(pBar !=null and pBar.isShowing()){
pBar.dismiss();
}
}
}
Use interface in Asyntask class for communicate with Activity class
public class MyAsyncTask extends AsyncTask<Void,Void,Void> {
//use context for activity reference
private Context context_;
public MyAsyncTask(Context context) {
this.context_=context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(mCallBack!=null ){
mCallBack.onSuccess("Success");
}else {
mCallBack.onError("Error");
}
}
MyAsyncCallBack mCallBack=null;
public MyAsyncCallBack getmCallBack() {
return mCallBack;
}
public void setmCallBack(MyAsyncCallBack mCallBack) {
this.mCallBack = mCallBack;
}
public interface MyAsyncCallBack{
public void onSuccess(String successMessage);
public void onError(String successMessage);
}
}
Call AsynckTask Class from activity class.Before calling asyntask start progress. and after completing work in asyntask return activity via interface and hide progress.
startProgress();
MyAsyncTask mTask=new MyAsyncTask(YourActivity.this);
mTask.setmCallBack(new MyAsyncTask.MyAsyncCallBack() {
#Override
public void onSuccess(String successMessage) {
//do success work and hide progress
hideProgress();
}
#Override
public void onError(String successMessage) {
//do error work and hide progress
hideProgress();
}
});
mTask.execute();
I want to generate a TextView inside AsyncTask's onPostExecute like this :
protected class AsyncTranslator extends AsyncTask<String, JSONObject, String>
{
#Override
protected String doInBackground(String... params) {
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String mymeaning) {
TextView myView = new TextView(this);
myView.setText(Html.fromHtml(myString));
}
}
But it gives error telling me that this cannot be applied to AsyncTranslator.
Can you tell me how I can generate textViews inside AsyncTask onPostExecute? Thanks.
From the documentation the possible constructors are
TextView(Context context)
TextView(Context context, AttributeSet attrs)
TextView(Context context, AttributeSet attrs, int defStyleAttr)
TextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
but you are doing
TextView myView = new TextView(this);
inside AsyncTranslator which is incorrect.
You can easily create a TextView inside your AsyncTask if you have a reference to your context. See this thread to get a reference to your context.
EDIT
It seems that you already have a reference to your context, so just do
TextView myView = new TextView(context);
In AsyncTask you shouldn't make operations on base UI thread and here you are trying to do it. Try to create new Interface which lets you to pass the result.
public interface asyncTaskInterface {
public void printEditText();
}
Then in your AsyncTask:
protected class AsyncTranslator extends AsyncTask<String, JSONObject, String>
{
public asyncTaskInterface delegate;
#Override
protected String doInBackground(String... params) {
}
#Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(context, "Please wait.", Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute(String mymeaning) {
delegate.printEditText();
}
}
In your result class you have to implement the interface and pass the class to your async task as delegate:
public class myClassActivity implements asyncTaskInterface ...
before you will call async task assign the delegate:
AsyncTranslator translator = new AsyncTranslator();
translator.delegate = this;
translator.execute();
At the end in your activity overwrite the method from your intrface and build in it the TextView.
First create an interface like this:
public interface onTextViewCreatedListener {
public void onTextViewCreated(TextView tv);
}
Then change your AsyncTranslator class like this
protected class AsyncTranslator extends AsyncTask<String, JSONObject, String>
{
private onTextViewCreatedListener onTextViewCreatedListener;
public AsyncTranslator(onTextViewCreatedListener onTextViewCreatedListener){
this.onTextViewCreatedListener = onTextViewCreatedListener;
}
#Override
protected String doInBackground(String... params) {
}
#Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(context, "Please wait.", Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute(String mymeaning) {
//since you have passed context to Toast in onPreExecute use that context here also.
TextView myView = new TextView(context);
myView.setText(Html.fromHtml(myString));
if(onTextViewCreatedListener!=null){
onTextViewCreatedListener.onTextViewCreated(myView);
}
}
}
and then use AsyncTranslator class in your activity class like this:
AsyncTranslator asyncTranslator = new AsyncTranslator(new onTextViewCreatedListener() {
#Override
public void onTextViewCreated(TextView tv) {
//you can use your created textview here
}
});
that context should be passed from your activity where you are going to call aynctask.execute()
Learning what I can from the internet and youtube, I'm sure I am not handling this in the appropriate way. I have an existing app which includes a slide out navigation drawer using fragments. I am now trying to get an activity to run within that fragment without any luck. It works when ran on it's own, but after trying to combine the two, I am not able to get "draftactivity" to run properly. The fragment operates as it should.
public class tapsfragment extends Fragment {
public static tapsfragment newInstance() {
tapsfragment fragment = new tapsfragment();
return fragment;
}
public tapsfragment(){}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((MainActivity) activity).onSectionAttached(2);
}
public class DraftActivity extends Activity {
TextView draftfeed;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.draft_activity);
draftfeed = (TextView) findViewById(R.id.draftfeed);
new PostAsync().execute();
}
class PostAsync extends AsyncTask<Void, Void, Void> {
ProgressDialog pd;
XMLHelper helper;
#Override
protected void onPreExecute() {
pd = ProgressDialog.show(DraftActivity.this, "Taps", "Loading posts for ******.com ...", true, false);
}
#Override
protected Void doInBackground(Void... arg0) {
helper = new XMLHelper();
helper.get();
return null;
}
#Override
protected void onPostExecute(Void result) {
StringBuilder builder = new StringBuilder();
for (ItemValue post : helper.posts) {
builder.append("\nPost: " + post.getTitle());
builder.append("\n");
}
draftfeed.setText(builder.toString());
pd.dismiss();
}
}
Activity can't run in a fragment, it's the other way around.
I have an AsyncTask which shows a ProgressDialog. The AsyncTask is started when the activity is started:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_layout);
new MyTask().execute();
}
// ... other code
private class MyTask extends AsyncTask<Void, Void, Void>{
private ProgressDialog dialog = new ProgressDialog(MyActivity.this);
#Override
protected void onPreExecute() {
dialog.show();
}
#Override
protected Void doInBackground(Void... voids) {
// get data from a server
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
// call to a method in MyActivity which updates the UI.
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
}
This code works perfectly, untill I rotate my screen. Which makes sense, because the context that was used to create the dialog doesn't exist anymore (because the activity is re-created when rotating), and a window leak is caused.
The only solution I could think of isn't a really nice one: create a static instance of the task and dialog, and simply dismiss the dialog when the activity is destroyed, and recreate the dialog in the oncreate method if the task is still running.
So how would I solve something like this without losing functionality (so the dialog must always be shown when the task is running, and rotating the device should be allowed)?
As Raghunandan suggested in his comment, I looked into Fragments and solved my problem.
I created a Fragment which starts my AsyncTask, as explained in the blogpost that Raghunandan provided.
And to make sure that my Dialog didn't get leaked, I created a DialogFragment, as described here (Basic Dialog).
Here's my working code:
My Activity:
public class MyActivity extends Activity implements MyTaskFragment.TaskCallbacks {
private MyTaskFragment task;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_layout);
FragmentManager fm = getFragmentManager();
task = (MyTaskFragment) fm.findFragmentByTag("myTask");
if (task == null) {
task = new MyTaskFragment();
fm.beginTransaction().add(task, "myTask").commit();
}
}
#Override
public void onPreExecute() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("myDialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
StringProgressDialogFragment dialog = StringProgressDialogFragment.newInstance("My message");
dialog.show(ft, "myDialog");
}
#Override
public void onPostExecute() {
StringProgressDialogFragment dialog = (StringProgressDialogFragment) getFragmentManager().findFragmentByTag("myDialog");
if (dialog!=null) {
dialog.dismiss();
}
// update UI
}
// ... other code
}
My Task fragment:
public class MyTaskFragment extends Fragment {
private TaskCallbacks mCallbacks;
private Task mTask;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (TaskCallbacks) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Retain this fragment across configuration changes.
setRetainInstance(true);
// Create and execute the background task.
mTask = new Task();
mTask.execute();
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
private class Task extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
mCallbacks.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
// do stuff
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
mCallbacks.onPostExecute();
}
}
public static interface TaskCallbacks {
void onPreExecute();
void onPostExecute();
}
}
My Dialog fragment:
public class StringProgressDialogFragment extends DialogFragment {
private String message;
public static StringProgressDialogFragment newInstance(String message) {
StringProgressDialogFragment dialog = new StringProgressDialogFragment();
Bundle args = new Bundle();
args.putString("message", message);
dialog.setArguments(args);
return dialog;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
ProgressDialog dialog = new ProgressDialog(getActivity());
message = getArguments().getString("message");
dialog.setMessage(message);
return dialog;
}
}
New Loaders API can help you (available via support package) - man. They will solve problem with rotation, but not a mem. leak. To solve mem. leaks write your own "AsyncTask" (with a "clearContext" routine) and clear it's context in activity's onDestroy (or onPause, depends on your architecture). It may looks like a bicycle, but the task takes max 1 day, and you will have a full control on all the resources you background worker use.
By the way: consider using dialogs through fragments, because it solves dialog kill on screen rotation.
try with sample. it will work. basically just restrict the oncreate call by handling the config change. this solution may help you.
public class MainActivity extends Activity {
LoadProgrssdata task = new LoadProgrssdata();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, "oncreate called", Toast.LENGTH_SHORT).show();
task.execute();
}
public class LoadProgrssdata extends AsyncTask<Void, Void, Void> {
ProgressDialog progressDialog;
//declare other objects as per your need
#Override
protected void onPreExecute()
{
progressDialog= ProgressDialog.show(MainActivity.this, "Progress Dialog Title Text","Process Description Text", true);
//do initialization of required objects objects here
};
#Override
protected Void doInBackground(Void... params)
{
//do loading operation here
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
progressDialog.dismiss();
};
}
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.e("orientation ", "landscape");
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Log.e("orientation ", "portrait");
}
}
}
and in android manifest file:
<activity
android:name="com.example.MainActivity"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden|screenSize" />
I managed to fix this problem by trying to catch any crash that, may occurs, in doInBackground.
I have two classes; the first is an asynctask and the other is an ConnectionDetector class
which contains the code shown here (3rd step),
public class myTask extends AsyncTask<String,Void,String>{
private Context context;
ConnectionDetector connectiondetector = new ConnectionDetector(context);
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
//CHECK INTERNET CONNECTION
if(connectiondetector.isConnectingToInternet()){ //method from connectiondetector.java
//do something
}
}
when I run this code I get a null pointer exception at the if statement.
is it because of the context, how do I fix this?
the asynctask class is called from a different activity ( partosrecord.class )
Pass context to the constructor of oyur asynctask from your activity class
new myTask(ActivityName.this).execute(params);
In your asynctask
public class myTask extends AsyncTask<String,Void,String>{
ConnectionDetector connectiondetector
Context mcontext;
public myTask(Context context)
{
mcontext= context;
connectiondetector = new ConnectionDetector(mcontext);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if(connectiondetector.isConnectingToInternet()){
//dosomething
}
}
Code where u call asynctask:-
myTask site = new myTask(this);
site.execute();
or use this below code on AsyncTask
public class myTask extends AsyncTask<String,Void,String>{
private Context context;
ConnectionDetector connectiondetector
public myTask(Context con)
{
context=con;
connectiondetector = new ConnectionDetector(context);
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
//CHECK INTERNET CONNECTION
if(connectiondetector.isConnectingToInternet()){ //method from connectiondetector.java
//do something }
}