I am using Pager Adapter and I want to call fragment method from activity. I tried with callback interface but I get null pointer exception because Fragment fragment = new Fragment() doesn't call onCreate() of that fragment. Any ideas how should I do this? This is my code:
MainActivity:
public interface Communicator {
void passStatus(String status);
}
private Communicator communicator;
public void setCommunicator(Communicator communicator)
{
this.communicator = communicator;
}
#Override
protected void onPause() {
super.onPause();
if(communicator != null)
{
communicator.passStatus("STOP");
}
}
#Override
protected void onResume() {
super.onResume();
if(communicator != null)
{
communicator.passStatus("START");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabLayout = findViewById(R.id.tabBar);
viewPager = findViewById(R.id.viewPager);
Fragment fragment = new Fragment();
setCommunicator(new Communicator() {
#Override
public void passStatus(String status) {
if(status == "START")
{
fragment.Start();
}
else if(status == "STOP")
{
fragment.Stop();
}
}
});
PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager());
pagerAdapter.addFragment(fragment, "Some fragment");
pagerAdapter.addFragment(new AnotherFragment(), "Another fragment");
viewPager.setAdapter(pagerAdapter);
tabLayout.setupWithViewPager(viewPager);
}
You can use SharedViewModel : https://developer.android.com/topic/libraries/architecture/viewmodel#sharing
You will create SharedViewModel in activity and export a LiveData for start or stop.
In your fragment, you will observer LiveData of SharedViewModel.
Class for one call event:
import androidx.lifecycle.Observer
open class Event<out T>(private val content: T) {
#Suppress("MemberVisibilityCanBePrivate")
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
override fun onChanged(event: Event<T>?) {
event?.getContentIfNotHandled()?.let {
onEventUnhandledContent(it)
}
}
}
You can this, either by using SharedViewModel, Interfaces callbacks, Broadcast Receivers and also by using getSupportFragmentManager.
But the thing is that you will have to manage the things with null checks while accessing the views of the Fragment because in case if the Fragment is detached that will give a NullPointerException.
Related
I have the following setup:
I have an Activity that launches a FragmentA.
FragmentA contains a recyclerView and an adapter.
I have an interfaceA in the adapter which is implemented in FragmentA so that I get notified which position was clicked.
I have a second interfaceB that I created in the FragmentA, which is implemented in the Activity that launched FragmentA in step 1.
Finally, I'm launching FragmentB from the Activity based on data I get from interfaceB.
Everything is working fine, however the flow is tedious, and demands a lot of boilerplate code.
THE GOAL is to have the activity launch fragmentB that contains data from a single clicked item from the recyclerView within FragmentA.
Question: Can it be achieved differently?
Code Below:
Activity launches FragmentA:
Fragment fragment = fragmentManager.findFragmentByTag(FragmentA.class.getName());
if (fragment == null) {
fragment = Fragment.instantiate(this, FragmentA.class.getName());
}
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction
.replace(R.id.fragmentLayout, fragment, FragmentA.class.getName())
.addToBackStack(FragmentA.class.getName())
.commit();
Inside FragmentA we have recyclerView, and interfaceA implemented in the adapter:
Adapter Class:
public class AdapterA extends RecyclerView.Adapter< AdapterA.ViewHolderA> {
//instances
private Context context;
private List<Data> dataList;
private OnItemClickListener onItemListClickListener;
//Constructor
public AdapterA (Context context, List<Data> dataList, OnItemClickListener onItemListClickListener {
this.context = context;
this.dataList = dataList;
this.onItemListClickListener = onItemListClickListener;
}
onCreateViewHolder....
onBindViewHolder....
getItemCount...
class ViewHolderA RecyclerView.ViewHolder {
//instances..
//Constructor...
}
}
interface class interfaceA:
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
interface class interfaceB:
public interface SingleItemEventListener {
void onSingleItemClicked(int position);
}
FragmentA class:
//Instances
private AdapterA adapter;
private RecyclerView recyclerView;
private onSingleItemClicked singleItemEventListener;
onAttach...
onCreateView...
#Override
public void onStart() {
super.onStart();
//Setting adapter
onSetAdapter();
}
private void onSetAdapter() {
List<Data> dataList;
dataList = getData();
adapter = new AdapterA(context, dataList, new OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
singleItemEventListener.onSingleItemClicked(position);
}
});
In the Activity, we are implementing onSingleItemClicked callback to receive the event and launch FragmentB with data received from the interface callback:
ActivityA implements SingleItemEventListener {
#Override
public void onSingleItemClicked(int position) {
Data data = getData(position);
if (data != null) {
Bundle bundle = new Bundle();
bundle.putParcelable("single_data_key", data);
Fragment fragmentB = fragmentManager.findFragmentByTag(FragmentB.class.getName());
if (fragmentB == null && bundle != null) {
fragmentB = Fragment.instantiate(this, FragmentB.class.getName(), bundle);
}
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction
.replace(R.id.FragmentLayout, fragmentB, FragmentB.class.getName())
.addToBackStack(FragmentB.class.getName())
.commit();
}
}
}
Add ViewModel to your activity and use it to communicate between all you components, activity and both fragments.
You can get access to the activity's ViewModel from your fragment
MyViewModel model = ViewModelProviders.of(getActivity()).get(MyViewModel.class);
Use LiveData for communication, post an action to it from your fragment and listen to it in your activity to start another fragment.
You can do the same task using only single interface rather than two or you can share view models between fragments and activity.
Method 1 : Using single interface
Define Interface as
public interface FragmentCallbackListener {
void onItemClick(View view, int position);
}
Let your Activity implement it :
ActivityA extend Activity implements FragmentCallbackListener {
#Override
public void onItemClick(View view, int position) {
....
}
}
Fragments which are attached to activity implementing FragmentCallbackListener should override onAttach() of fragment as:
public class FragmentA extends Fragment {
private FragmentCallbackListener mListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the listener. If not, it throws an exception
try {
mListener = (FragmentCallbackListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement FragmentCallbackListener");
}
}
}
Pass same listener instance to Adapter :
adapter = new AdapterA(context, dataList, mListener);
Method 2 : Using shared view model
Define view model as :
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Data> selected = new MutableLiveData<Data>();
public void select(Data data) {
selected.setValue(data);
}
public LiveData<Data> getSelected() {
return selected;
}
}
Inside FragmentA
public class FragmentA extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
...
adapter = new AdapterA(context, datalist, model);
}
}
Inside adapter's view onClickListener :
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
model.select(view.getTag()); //or use getData(position) to return selected data
}
});
Inside ActivityA
ActivityA extend Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(this).get(SharedViewModel.class);
model.getSelected().observe(this, data -> {
// launch the new fragment B with selected data
});
}
}
For more details, read https://developer.android.com/training/basics/fragments/communicating
Without an external library, have you considered using a broadcast?
It still requires boilerplate, but depending on your opinion can be a bit cleaner (the activity wont need to to be an instance of any interface, you don't need any 'god object' models)
In FragmentA's adapter, when an item is clicked you send a broadcast with an explicit action and the arguments as extras. In the activity you register (and unregister) a broadcast receiver (no need to alter manifest). Finally the receiver starts FragmentB as usual.
Fragment A / Adapter
Intent item = new Intent(MY_CONSTANT);
item.putExtra(MY_EXTRA_CONSTANT, position);
getActivity().sentBroadcast(intent);
Activity
private final BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int position = intent.getIntExtra(MY_EXTRA_CONSTANT, -1);
//TODO: Move your FragmentB transaction here
}
};
void onPause() {
unregisterReceiver(myReceiver);
}
void onResume() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(MY_CONSTANT);
registerReceiver(myReceiver, intentFilter);
}
You can achieve it without using Interface, BroadcastReceiver and ViewModel.
Check below code:
ActivityA.java
public class ActivityA extends AppCompatActivity {
ActivityTestBinding mBinding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_test);
pushFragment(new FragmentA());
}
/**
* #param fragment pass fragment you want to replace
*/
public void pushFragment(Fragment fragment) {
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped && manager.findFragmentByTag(backStateName) == null) {
// if fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.container, fragment, backStateName);
ft.addToBackStack(backStateName);
ft.commit();
}
}
#Override
public void onBackPressed() {
try {
if (getSupportFragmentManager().getBackStackEntryCount() <= 1) {
finish();
} else {
getSupportFragmentManager().popBackStack();
}
} catch (Exception e) {
super.onBackPressed();
}
}
}
Here pushFragment method is generalized for all fragment.
And in onBackPressed() it will check BackStackEntryCount. If there is 1 or less count that means only last fragment is in backstack and finish(); will be called and exit application. If there is >1 count in BackStackEntryCount then it will pop last fragment.
In your AdapterA.java:
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (context instanceof ActivityA) {
FragmentB mFragmentB = new FragmentB();
Bundle bundle = new Bundle();
bundle.putParcelable("single_data_key", dataList.get(getAdapterPosition()));
mFragmentB.setArguments(bundle);
((ActivityA) context).pushFragment(mFragmentB);
}
}
});
Here you already passing context of ActivityA. So you can check that if (context instanceof ActivityA) then you can call pushFragment method of ActivityA by using Type Casting.
So this is less boilerplate code you can integrate in your Android Project.
I am reading about how to interact between UI and background thread here.
This article has following note:
The AsyncTask does not handle configuration changes automatically,
i.e. if the activity is recreated. The programmer has to handle that
in his coding. A common solution to this is to declare the AsyncTask
in a retained headless fragment.
I dont understand what is retained headless fragment.
For example, in this way I can add fragment:
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.frame, new MyFragment());
transaction.commit();
And in fragment I can execute AsyncTask like this:
MyTask myTask = new MyTask();
String[] args = {"Hello"};
myTask.execute(args);
Is this called "to declare the AsyncTask in a retained headless fragment"?
Headless fragment is nothing but a fragment which does not have a view. In onCreate() of the fragment lifeCycle, use setRetainInstance(true);. This will not destroy the fragment even if the activity recreates. So if an AsyncTask is running in fragment, on recreation of the activity, you wont lose the AsyncTask.
In onCreate of the activity, you have to add the fragment with a tag. Before adding, check if the fragment exist using getFragmentManager().findFragmentByTag(TAG), if the fragment is null then create a new instance of the fragment and add it.
In Fragment there will not be any view inflated, so no need to override onCreateView().
An example of headlessFragment :
public class HeadlessProgressFragment extends Fragment {
private ProgressListener mProgressListener;
private AsyncTask<Void, Integer, Void> mProgressTask;
public interface ProgressListener {
void updateProgress(int progress);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
public void setProgressListener(Context context) {
mProgressListener = (ProgressListener) context;
}
public void startProgress(final int size) {
if (mProgressTask == null || mProgressTask.getStatus() != AsyncTask.Status.RUNNING || mProgressTask.getStatus() == AsyncTask.Status.FINISHED) {
mProgressTask = new AsyncTask<Void, Integer, Void>() {
#Override
protected Void doInBackground(Void... params) {
for (int index = 0; index < size; index++) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
publishProgress(index + 1);
}
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if (mProgressListener != null) {
mProgressListener.updateProgress(values[0]);
}
}
};
mProgressTask.execute();
}
}
}
In Activity Something like this :
public class MainActivity extends FragmentActivity implements HeadlessProgressFragment.ProgressListener {
private static final String TAG = "progress_fragment";
private ProgressBar mProgressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dummy_view);
mHeadlessProgressFragment = (HeadlessProgressFragment) getSupportFragmentManager().findFragmentByTag(TAG);
if (mHeadlessProgressFragment == null) {
mHeadlessProgressFragment = new HeadlessProgressFragment();
getSupportFragmentManager().beginTransaction().add(mHeadlessProgressFragment,TAG).commit();
}
mHeadlessProgressFragment.setProgressListener(this);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
final Button startFillBtn = (Button) findViewById(R.id.btn_start_filling);
startFillBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mHeadlessProgressFragment.startProgress(100);
}
});
}
#Override
public void updateProgress(int progress) {
mProgressBar.setProgress(progress);
}
}
As i simplified the complexity in my case by Just update your UI (if you have to) by checking the calling fragment or activity is present or not. Start the asynctask by assigning the weakreference of calling entity.
I have a problem that I don't know how to solve. How do you hide a toolbar in a specific fragment, I have already been searching around on the internet and what I found was communicating activity and fragment would solve it. But it doesn't work for me at all, here is my code:
main_activity:
public class MainActivity extends ActionBarActivity implements like_frag.OnHideToolbar{
....
public void onHidingToolbar(int position){
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
if(toolbar == null){
getSupportActionBar().hide();
}else{
getSupportActionBar().hide();
}
}
like_frag.java
public class like_frag extends Fragment {
OnHideToolbar mCallback;
Toolbar toolbar;
public interface OnHideToolbar {
public void onHidingToolbar(int position);
}
public void onAttach(Activity activity){
try{
mCallback = (OnHideToolbar) activity;
}catch(ClassCastException e){
throw new ClassCastException(activity.toString() + "error implementing");
}
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View rootView = inflater.inflate(R.layout.swipefrag, container, false);
toolbar = (Toolbar)getActivity().findViewById(R.id.toolbar);
return rootView;
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
}
thanks in advance.
I have a drawer inside the toolbar.
Put this code in fragment in which you want to hide toolbar...
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().hide();
}
#Override
public void onStop() {
super.onStop();
((AppCompatActivity)getActivity()).getSupportActionBar().show();
}
In the fragment's onCreate method call:
((AppCompatActivity) getActivity()).getSupportActionBar().hide();
Replace AppCompateActivity with the activity class you used.
Edited:
You could simply use the onResume method to call hide() and the onStop method to call show() as suggested in some of the comments.
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().hide();
}
#Override
public void onStop() {
super.onStop();
((AppCompatActivity)getActivity()).getSupportActionBar().show();
}
If you are using the new Navigation Component, add this while setting up the toolbar
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
#Override
public void onDestinationChanged(#NonNull NavController controller,
#NonNull NavDestination destination, #Nullable Bundle arguments) {
if(destination.getId() == R.id.full_screen_destination) {
toolbar.setVisibility(View.GONE);
bottomNavigationView.setVisibility(View.GONE);
} else {
toolbar.setVisibility(View.VISIBLE);
bottomNavigationView.setVisibility(View.VISIBLE);
}
}
});
And for Kotlin, you can do the following:
navController.addOnDestinationChangedListener { _, destination, _ ->
if(destination.getId() == R.id.full_screen_destination) {
toolbar.setVisibility(View.GONE)
bottomNavigationView.setVisibility(View.GONE);
} else {
toolbar.setVisibility(View.VISIBLE)
bottomNavigationView.setVisibility(View.VISIBLE);
}
}
Create an interface in the fragment and use it to tell the parent activity to hide the toolbar.
Add these lines to your fragment:
private OnEventListener listener;
public interface OnEventListener {
void hideToolbar() ;
}
public void setOnEventListener(OnEventListener listener) {
this.listener = listener;
}
After creating your fragment in the main activity add:
myFragment.setOnEventListener(new MyFragment.OnEventListener() {
#Override
public void hideToolbar() {
getSupportActionBar().hide();
}
});
Whenever you need to hide the toolbar execute:
listener.hideToolbar();
from inside your fragment.
Just add these methods to the fragment where you want to diable the toolbar ,and also in the fragment's onStop() make it visible again.
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().hide();
}
#Override
public void onStop() {
super.onStop();
((AppCompatActivity)getActivity()).getSupportActionBar().show();
}
in kotlin hide and show supportActionBar as follows:
override fun onResume() {
super.onResume()
(activity as AppCompatActivity).supportActionBar?.hide()
}
override fun onStop() {
super.onStop()
(activity as AppCompatActivity).supportActionBar?.show()
}
and if you want to have your own custom toolbar, in OncreateView set:
//your Custom toolbar in xml
val toolbar = binding.toolbar
(activity as AppCompatActivity).setSupportActionBar(toolbar)
Simply use supportActionBar?.hide() or supportActionBar?.show().
If you are using NavigationController:
navController.addOnDestinationChangedListener { controller, destination, arguments ->
if (destination.id == R.id.loginSuccessFragment) {
supportActionBar?.hide()
} else {
supportActionBar?.show()
}
}
Put this code in fragment in which you want to hide toolbar...
Add this( ((AppCompatActivity)getActivity()).getSupportActionBar().hide();) in onCreateView or in onResume.
and do this in onDestroy()
#Override
public void onDestroy() {
super.onDestroy();
((AppCompatActivity)getActivity()).getSupportActionBar().show();}
use getSupportActionBar().hide(); and getSupportActionBar().show(); in lifeCycle methods
You can try it.
#Override
public void onDestinationChanged(#NonNull NavController controller, #NonNull NavDestination destination, #Nullable Bundle arguments) {
if (destination.getId() == R.id.nav_dashboard){
if (toolbar !=null){
toolbar.setVisibility(View.GONE);
}
}else {
toolbar.setVisibility(View.VISIBLE);
}
}
I have a parent fragment, within this. Upon a button click, a child dialog fragment is getting created.
Now I would like to know how to call parent fragment function from child dialog fragment.
Here is the sample code :
/**SampleFragment.java**/
public class SampleFragment extends Fragment {
// Instantiate view & add event handlers
public void onButtonClick(....) {
// Create a dialog framgent
}
public void refreshView() {
}
}
/**SampleDialogFragment.java**/
public class SampleDialogFragment extends DialogFragment {
// Instantiate view for dialog
public void onButtonClick(...) {
// Call parent fragment method, i.e call refreshView() of SampleFragment
}
}
In a Fragment:
SampleDialogFragment dialogFragment = new SampleDialogFragment();
dialogFragment.show(getChildFragmentManager());
In a DialogFragment:
((SampleFragment) getParentFragment()).refreshView();
After calling this method, you can access public methods of a parent fragment.
In say your parent fragment, SettingsFragment for example. Note the setTargetFragment()
public void onButtonClick(....)
{
PrefLanguageDialogFragment prefLang = PrefLanguageDialogFragment.newInstance();
prefLang.setTargetFragment(SettingsFragment.this, 1337);
prefLang.show(getFragmentManager(), "dialog");
}
In our dialog, note the getTargetFragment()
SettingsFragment frag = (SettingsFragment)getTargetFragment();
if(frag != null){
frag.refreshSomething();
}
when you want add SampleFragment to your activity set it a tag, e.g "SampleFragment".
then
public void onButtonClick(...){
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
SampleFragment parent = (SampleFragment)fm.findFragmentByTag("SampleFragment");
parent.refreshview();
}
have not test it but it may help:-)
The best way is to go for interface, declare an interface in nested fragment -
public interface checkingClickListener
{
public void checkingClickListener(String data);
}
then attach this interface to parent fragment -
public void onAttachFragment(Fragment fragment)
{
try
{
clickListener = (checkingClickListener) fragment;
} catch (ClassCastException e)
{
throw new ClassCastException(fragment.toString() + " must implement checkingClickListener");
}
}
#Override
public void onCreate(Bundle savedInstanceState)
{
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
this.mContext = getActivity().getApplicationContext();
onAttachFragment(getParentFragment());
....
}
you need to call this listener on some button click -
#Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.tv_submit:
if (clickListener != null)
{
clickListener.checkingClickListener("sending data");
}
break;
}
}
Implement this interface in parent fragment -
public class Fragment_Parent extends Fragment implements Nested_Fragment.checkingClickListener
{
....
#Override
public void checkingClickListener(final List<Player> players_list)
{
FragmentManager fragmentManager = getChildFragmentManager();
SomeOtherNestFrag someOtherNestFrag = (SomeOtherNestFrag) fragmentManager.findFragmentByTag([Tag of your fragment which you should use when you add]);
if(someOtherNestFrag != null)
{
// your some other frag need to provide some data back based on views.
SomeData somedata = someOtherNestFrag.getSomeData();
// it can be a string, or int, or some custom java object.
}
}
}
Hope this helps you.
I know I came a bit too late to the party and over the past 3 years (or maybe longer) there've been thousands and thousands of discussion like this one (unfortunately most of them involving activities and not fragments), but I'm curious about one thing.
Having the following piece of code, can mFragment be null when the AsyncTask's callback onError() or onSuccess() gets called after the screen orientation changes? So the AsyncTask starts, I rotate the screen of the device and at some point the AsyncTask will return an error or a success. When this happens, can the mFragment be null?
I already know that this cannot happen when dealing with Activities because basically no messages will be processed between a call to onRetainNonConfigurationInstance() of the previous instance and onCreate() of the new instance of the activity.
Unfortunately I couldn't find anything about this rule when it comes to fragments.
Do you guys know anything about this?
Thank you for your answers!
public class Fragment extends Fragment {
private WorkerFragment mWorkerFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mWorkerFragment =(WorkerFragment)getFragmentManager().findFragmentByTag("worker_fragment");
if (mWorkerFragment == null) {
mWorkerFragment = new WorkerFragment();
getFragmentManager().beginTransaction().add(mWorkerFragment, "worker_fragment").commit();
}
if (savedInstanceState == null) {
mWorkerFragment.performAsyncTask();
}
private static class WorkerFragment extends Fragment {
private TypeOfAsyncTask mAsyncTask;
private Fragment mFragment;
private Callback mCallback = new Callback() {
#Override
public void onError(Error error) {
// Can mFragment be null here?
mFragment.onSendRequestError(error);
}
#Override
public void onSuccess(Result result) {
// Can mFragment be null here?
mFragment.onSendRequestSuccess(result);
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mFragment = (Fragment) getTargetFragment();
}
#Override
public void onDetach() {
super.onDetach();
mFragment = null;
}
private void performAsyncTask() {
mAsyncTask = new TypeOfAsyncTask(mCallback);
mAsyncTask.execute();
}
}
}