Call an AsyncTask method in ActivityMain from fragment - android

Previous I haved that AsyncTask on main activity and called with:
new SyncGetLocations(ActivityMain.this).execute();
Now,I move it to a fragment and don't know now how to call it from MainActivity.
AsyncTask look alike :
private static class SyncGetLocations extends AsyncTask<Void, Void, Void> {
private WeakReference<ActivityMap> activityReference;
SyncGetLocations(ActivityMap context) {
activityReference = new WeakReference<>(context);
}
#Override
protected void onPreExecute() {
}
#Override
protected Void doInBackground(Void... voids) {
}
#Override
protected void onPostExecute(Void aVoid) {
}
}

Either
From MainActivity find your fragment:
val fragment = getSupportFragmentManager().findFragmentByTag(...) or findFragmentByID(...)
and then call a method in this fragment to launch the asyncTask
fragent.callAsyncTask()
Or
make your asynctask public or remove it from fragment to be its own class and call it froim every where you want
I suggest you to make asyntask not an inner class of fragment of activity it you wants to call it from everywhere

Try attaching Listener to your fragment with a method like
public interface FragmentInteractionListener{
void onClick();
}
In your fragment
private FragmentInteractionListener fragmentListener;
#Override
public void onDetach() {
super.onDetach();
fragmentListener = null;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof FragmentInteractionListener) {
fragmentListener = (FragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement FragmentInteractionListener");
}
}
And under onClick event call it like this
fragmentListener.onClick();
Then in your activity implement the FragmentInteractionListener
OR
((SomeActivity)getActivity()).someMethod();

Related

Android Fragment with attached AsyncTask gives null after commit in Activity

I try to understand basic design pattern behind implementing AsyncTask and attaching it to Fragment. I follow numerous tutorials and implemented code (which gives nothing):
1) my Fragment class which contains AsyncTask:
public class MyFragment extends Fragment
{
public interface TaskCallback
{
void onPreExecute();
void onProgressUpdate(Integer... i);
void onPostExecute();
}
private TaskCallback mCallback;
private Task mTask;
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
mCallback = (TaskCallback) activity;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRetainInstance(true);
mTask = new Task();
mTask.execute();
}
private class Task extends AsyncTask<Void, Integer, Void>
{
#Override
protected void onPreExecute()
{
mCallback.onPreExecute();
}
#Override
protected Void doInBackground(Void... params)
{
for (int i=0; i<100; i++)
{
publishProgress(i*10);
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values)
{
mCallback.onProgressUpdate(values);
}
#Override
protected void onPostExecute(Void aVoid)
{
mCallback.onPostExecute();
}
}
}
2) my Main Activity code
public class MainActivity extends ActionBarActivity implements MyFragment.TaskCallback
{
private ProgressBar mProgress;
private MyFragment mTaskFragment;
private final static String TAG_FRAGMENT = "Fragment Task";
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgress = (ProgressBar) findViewById(R.id.progressBar1);
mProgress.setProgress(0);
//create fragment manager and fragment instance
FragmentManager mFM = getSupportFragmentManager();
mTaskFragment = (MyFragment) mFM.findFragmentByTag(TAG_FRAGMENT);
if(mFM == null)
{
mTaskFragment = new MyFragment();
mFM.beginTransaction().add(mTaskFragment, TAG_FRAGMENT).commit();
}
//I added this method, but to no help, the same without this method
mFM.executePendingTransactions();
}
#Override
public void onPreExecute()
{
mProgress.setVisibility(View.VISIBLE);
}
#Override
public void onProgressUpdate(Integer... i)
{
mProgress.setProgress(i[0]);
}
#Override
public void onPostExecute()
{
mProgress.setVisibility(View.INVISIBLE);
}
}
Basically, when run the code by Debug, after
mTaskFragment = (MyFragment) mFM.findFragmentByTag(TAG_FRAGMENT);
if(mFM == null)
{
mTaskFragment = new MyFragment();
mFM.beginTransaction().add(mTaskFragment, TAG_FRAGMENT).commit();
}
Gives mTaskFragment = null
I suppose here is the problem (mTaskFragment = null), the code doesn't create instance of MyFragment.
The question: how should I change the code to update ProgressBar from background by using this (Fragment + AsyncTask) pattern?
another question: Fragment onAttached(Activity a) is deprecated, now we should use onAttached(Context context), does it mean it should be implemented like: mCallback = (TaskCallback) context;?
Replace if(mFM == null) with if(mTaskFragment == null) you want to check if the fragment is null not the FragmentManager.
Also the updated method for:
public void onAttach(Activity activity) is public void onAttach(Context context)
Using: mCallback = (TaskCallback) context; is fine as Context is a superclass of Activty (just make sure your Activity is implementing the interface)

OrientationChange handling Activity, Fragment, AsyncTask and DialogFragments?

Hi there I'm thinking about what is the correct and best way to handle Activity, Fragment, AsyncTask and DialogFragments together.
My current state is that I start my Activity and replace its ContentView with my Fragment, in which I got an EditText and one Button.
Tapping my Button executes an AsyncTasks which Requests random things and takes some time. Meanwhile I display a DialogFragment begging for patience.
Desired behavior is that, e.g. I rotate my screen my DialogFragment keeps being displayed for the time my AsyncTask is running. After that I want to show up a simple toast displaying the information I got from my HttpRequest.
Compact overview about how I thought it would work:
BaseFragment keeps a WeakReference to the Activity it's attached to
AsyncTask keeps a WeakReference to Fragment which exectures it
AsyncTasks onPreExecute() shows up the DialogFragment
AsyncTasks onPostExecute() dissmisses the DialogFragment
BaseFragment holds DialogFragment
Unfortunately this is not the way it works, on orientation change my DialogFragment keeps being displayed and no toast is showing up.
What am I doing wrong ?
public class BaseFragment extends Fragment{
private static final String TAG = BaseFragment.class.getSimpleName();
protected WeakReference<AppCompatActivity> mActivity;
private TemplateDialogFragment dialogFragment;
public WeakReference<AppCompatActivity> getAppCompatActivity(){ return mActivity; }
#Override
public void onAttach(Context context) {
if(!(context instanceof AppCompatActivity)) {
throw new IllegalStateException(TAG + " is not attached to an AppCompatActivity.");
}
mActivity = new WeakReference<>((AppCompatActivity) context);
super.onAttach(context);
}
#Override
public void onDetach() {
mActivity = null;
super.onDetach();
}
#Override
public void onStart() {
super.onStart();
showContent();
}
public void showContent(){
}
public void showDialog(String title, String content){
dialogFragment = new TemplateDialogFragment();
Bundle bundle = new Bundle();
bundle.putString(TemplateDialogFragment.DIALOG_TITLE, title);
bundle.putString(TemplateDialogFragment.DIALOG_MESSAGE, content);
dialogFragment.setArguments(bundle);
dialogFragment.show(getFragmentManager(), TemplateDialogFragment.FRAGMENT_TAG);
}
public void notifyTaskFinished(String result) {
dismissDialog();
if(mActivity != null && !mActivity.get().isFinishing()) {
Toast.makeText(mActivity.get().getApplicationContext(), result, Toast.LENGTH_LONG).show();
}
}
private void dismissDialog(){
if(dialogFragment != null && dialogFragment.isAdded()) {
dialogFragment.dismissAllowingStateLoss();
}
}
}
...
public class TemplateFragment extends BaseFragment {
private static final String TAG = TemplateFragment.class.getSimpleName();
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.test_fragment, container, false);
}
#Override
public void showContent() {
super.showContent();
Button startTask = (Button) getAppCompatActivity().get().findViewById(R.id.button0);
final BaseFragment instance = this;
startTask.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
CustomAsyncTask task = new CustomAsyncTask(instance);
EditText input = (EditText) getAppCompatActivity().get().findViewById(R.id.text0);
task.execute(input.getText().toString());
}
});
}
private static class CustomAsyncTask extends AsyncTask<String, Void, String> {
WeakReference<BaseFragment> weakBaseFragmentReference;
private CustomAsyncTask(BaseFragment fragment) {
weakBaseFragmentReference = new WeakReference<>(fragment);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
weakBaseFragmentReference.get().showDialog("Executing", "Working on the request...");
}
#Override
protected String doInBackground(String... params) {
HttpURLConnection con = HttpUrlConnectionFactory.createUrlConnection("https://www.httpbin.org/bytes/" + (params[0] == null ? "1" : params[0]));
return HttpRequester.doGet(con).getResponseAsString();
}
#Override
protected void onPostExecute(String response) {
super.onPostExecute(response);
if(weakBaseFragmentReference.get() == null) {
return;
}
weakBaseFragmentReference.get().notifyTaskFinished(response);
}
}
}
*Edit:
After some time researching this theme I'm sure a Service is the best solution for most of my field of use. Also I used AsyncTaskLoaders a lot, because there is a smooth control of lifecycle....
Use progress bar instead of DialogFragment.
AsyncTask should only be used for tasks that take quite few seconds.
AsyncTask doesn't respect Activity lifecycle, and can lead to memory leaks.
Check some gotchas.
You can try AsyncTaskLoader to survive configuration changes.

Android equivalent of getActivity() from/in ActionBarActivity

Like my title says, i'm looking for an equivalent of getActivity() in my ActionBarActivity class in my Android project.
I want to pass an Activity parameter in AsyncTask declaration object, because i'm using an Activity object in my custom AsyncTask extended class
Here an example simplest code of my project
public class EventCreator extends ActionBarActivity {
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_even_creator);
View v = getLayoutInflater().inflate(R.layout.activity_even_creator,null);
this.context = this.getBaseContext();
final Button createButton = (Button)findViewById(R.id.createEventButton);
createButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AsyncTask<Void,Void,Boolean> eventCreatorSend = new SendEvents(/* here need activity object */);
eventCreatorSend.execute();
}
});
}
class SendEvents extends AsyncTask<Void,Void,Boolean> {
public Activity act;
SendEvents(Activity a) {
this.act = a;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
((LinearLayout)act.findViewById(R.id.layout_loader_create_event)).setVisibility(View.VISIBLE);
}
#Override
protected Boolean doInBackground(Void... params) {
SystemClock.sleep(5000);
return true;
}
#Override
protected void onPostExecute(Boolean params) {
if (params){
((LinearLayout)act.findViewById(R.id.layout_loader_create_event)).setVisibility(View.GONE);
act.finish();
}
else {
((LinearLayout)act.findViewById(R.id.layout_loader_create_event)).setVisibility(View.VISIBLE);
Toast.makeText(act,"Fail to send event",Toast.LENGTH_SHORT).show();
}
}
};
}
In a time, i thought use getParent() from ActionBarActivity class, but it return a null object.
So how to get the Activity object i want in ActionBarActivity class ?
Try nameofactivity.this instead getActivity()
I always use getActivity() in Fragments Activities and .this in any other kind of Activity.
Oh damn !
I just found a solution just after posting my ask.
I use MyClass.this, and it's done. Like this :
AsyncTask<Void,Void,Boolean> eventCreatorSend = new SendEvents(EventCreator.this);
eventCreatorSend.execute();
Hope that's can help someone !
The easiest way is an Activity variable
// in your fragment
Activity myActivity;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//fragment shouts "i know my father!!!"
myActivity = activity; //
}
now your activity instance(The father) can be represented anywhere

Android - Function execute listener

Hey i don't know if that's the right way to do it but if it is how can i do it...
I have one abstact class with AsyncTask
public abstract class A{
A(){
new Task().execute();
}
public abstract void postAction();
private class Task extends AsyncTask<String, String, String>{
protected String doInBackground(String... args)
{
//smth
}
protected void onPostExecute(String file_url){
postAction();
}
}
}
After that i have class that extends A class and overrides it's postAction() method:
public class B extends A{
B(){
//smth
}
postAction(){
//some action
}
}
In my activity i have instance of B and i want to perform action when postAction is called... so i want function listener if possible and how can i do it
class C extends Activity{
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
//somethingggg happeiningggg
}
MyListener listener = new MyListener(){
onPostActionCalled()
{
//start another activity or smt :D
}
};
}
So i have class for json response(class A) and class B that extends it and overrides it's post method so i can do what i want for specific situation(expect different data or smth else nvm)
In my activity i want to perform action when class B's post method is called
I don't know if i need to do listener or handler idk at all....
Stefan is right, why complicate things?
See this real simple example of threading:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new MyTask(new TaskListener() {
#Override
public void finished(boolean result) {
// back on main thread after task finishes
}
}).execute();
}
private interface TaskListener{
void finished(boolean result);
}
private class MyTask extends AsyncTask<Object, Integer, Boolean>{
private TaskListener mListener;
public MyTask(TaskListener mListener) {
super();
this.mListener = mListener;
}
#Override
protected Boolean doInBackground(Object... params) {
// long running background operation
return true;
}
#Override
protected void onPostExecute(Boolean result) {
mListener.finished(result);
super.onPostExecute(result);
}
}
}

Finish the calling activity when AsyncTask completes

My calling activity:
public class Hello extends Activity {
public void onCreate(Bundle savedInstanceState) {
MyTask mt = new MyTask(this);
mt.execute();
}
Now In MyTask (an external class):
public class MyTask extends AsyncTask<Void, Void, Void> {
private Context mContext;
public MyTask(Context context) {
mContext = context;
}
//doinbackground, etc
protected void onPostExecute() {
mContext.finish();
}
Other things are working as expected if I remove mContext.finish() above.
But if I'm calling mContext.finish() , I'm getting an error: The method finish() is undefined for the type Context (Eclipse doesn't show finish() when I write mContext. so that suggests I'm using finish() wrongly.)
What do I need to do to finish the calling activity Hello after MyTask completes the task
((Activity)mContext).finish();
Would be the correct way to cast a Context to an Activity and call its finish() method. Not sure why you'd want to finish an Activity from an AsyncTask though
What you can try to do instead of calling context.finish(), why don't you do a callback interface like this:
public interface TaskCallback{
void done();
}
Then you implement this into your Activity
public Hello extends Activity implements TaskCallback{
.....BUNCH OF ACTIVITY CODE.....
public void onCreate(Bundle savedInstanceState) {
MyTask mt = new MyTask(this);
mt.execute();
}
public void done() {
finish();
}
}
And instead of having Context as a parameter you have TaskCallback
public class MyTask extends AsyncTask<Void, Void, Void> {
private TaskCallback mCallback;
public MyTask(TaskCallback callback) {
mCallback = callback;
}
//doinbackground, etc
protected void onPostExecute() {
mCallback.done();
}
There you go, it gives you more flexibility to custom each implementation.
I got the same situation, then I do as follows:
public class MyTask extends AsyncTask<Void, Void, Void> {
private Activity mActivity;
private Context mContext;
public MyTask(Activity activity) {
mActivity = activity;
mContext = mActivity.getApplicationContext();
}
//doinbackground, etc
protected void onPostExecute() {
mActivity.finish();
}
Hope it help :)
Define a method in your activity class like this:
public void FinishAfterAsyncTask()
{
this.finish();
}
And call this method from the OnPostExecute method of the AsynTask class.
You could create a new private AsyncTask extended from your public one.
In this private AsyncTask you have access to the Activity stuff and you can override the onPostExecute method to finish it.
Your truly AsyncTask
public class MyPublicAsyncTask extends AsyncTask<Void, Void, Void> {
Context context;
public GetHorariosAsyncTask(Context ctx){
context = ctx;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
// prepare yourself for an async work
}
#Override
protected Void doInBackground(Void... params) {
// Do yout cool async stuff
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// you're finish, let's tell to user
}
}
Your Activity with private AsyncTask
public class MyActivity extends Activity {
Activity mAct;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mAct = this;
}
private class MyPrivateAsyncTask extends MyPublicAsyncTask {
public MyPrivateAsyncTask(Context ctx) {
super(ctx);
// TODO Auto-generated constructor stub
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
// our async task is completed! let's take care of this activity
mAct.finish();
}
}
}
Can you try
this.finish()
Seems like its because of calling it using mContext that it says undefined.

Categories

Resources