I have a fragment (YearsFragment) with a list. If I klick one item a new fragment (EventsFragment) will be executed.
The loader of the new fragment loads a new list. This works.
Now my Problem:
when I go back to the first YearsFragment and klick the same item the EventsFragment loads again. But I will get the old Loader with the old data.
EventsActivity:
public class EventsActivity extends FragmentActivity implements YearsFragment.OnYearSelectedListener, EventsFragment.OnEventSelectedListener{
private boolean screenSizeLarge;
private EventsFragment eventFrag = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.years_events);
// Check whether the activity is using the layout version with the fragment_container FrameLayout (small Display).
if (findViewById(R.id.fragment_container) != null) {
screenSizeLarge = false; //one-pane
YearsFragment firstFragment = new YearsFragment();
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, firstFragment).commit();
}else{
screenSizeLarge = true; //two-pane
}
}
#Override
public void onYearSelected(Years year) {
// The user selected the year from the YearsFragment
if (screenSizeLarge) {
// two-pane layout
// Capture the events fragment from the activity layout
eventFrag = (EventsFragment) getSupportFragmentManager().findFragmentById(R.id.event_fragment);
// Call a method in the EventFragment to update its content
eventFrag.updateEventsView(year);
} else {
//one-pane layout
if(eventFrag == null){
eventFrag = new EventsFragment();
}
Bundle args = new Bundle();
args.putInt("year", Integer.parseInt(year.getYear()));
eventFrag.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, eventFrag);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}}
YearsFragment:
public class YearsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<Years>>{
YearsAdapter adapter;
// The container Activity must implement this interface so the frag can deliver messages
OnYearSelectedListener mCallback;
public interface OnYearSelectedListener {
/** Called by YearsFragment when a list item is selected */
public void onYearSelected(Years year);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
adapter = new YearsAdapter(getActivity());
setListAdapter(adapter);
setEmptyText("No Data Here");
setListShown(false);
getLoaderManager().initLoader(0, null, this);
}
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
try{
mCallback = (OnYearSelectedListener) activity;
} catch (ClassCastException e){
throw new ClassCastException(activity.toString() +
"must implement OnYearSelectedListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
mCallback.onYearSelected(adapter.getItem(position));
}
//implements Loader
#Override
public Loader<List<Years>> onCreateLoader(int arg0, Bundle arg1) {
Log.i("YearsFragment","YearsFragment.onCreateLoader");
return new YearsLoader(getActivity());
}
#Override
public void onLoadFinished(Loader<List<Years>> arg0, List<Years> data) {
Log.i("YearsFragment","YearsFragment.onLoadFinished");
adapter.setData(data);
if(isResumed()){
setListShown(true);
}else{
setListShownNoAnimation(false);
}
}
#Override
public void onLoaderReset(Loader<List<Years>> arg0) {
Log.i("YearsFragment","YearsFragment.onLoaderReset");
adapter.setData(null);
}}
EventsFragment:
public class EventsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<Events>>{
EventsAdapter adapter;
private int year;
public EventsFragment(){
year = Calendar.getInstance().get(Calendar.YEAR);
}
// The container Activity must implement this interface so the frag can deliver messages
OnEventSelectedListener mCallback;
public interface OnEventSelectedListener {
/** Called by YearsFragment when a list item is selected */
public void onEventSelected(Events event);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
Log.i("EventsFragment","EventsFragment.onActivityCreated");
adapter = new EventsAdapter(getActivity());
setListAdapter(adapter);
setEmptyText("No Data Here");
setListShown(false);
}
#Override
public void onResume() {
super.onResume();
Bundle args = this.getArguments();
if(args != null){
year = args.getInt("year");
}
updateEventsView(year);
// The activity has become visible (it is now "resumed").
}
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
try{
mCallback = (OnEventSelectedListener) activity;
} catch (ClassCastException e){
throw new ClassCastException(activity.toString() +
"must implement OnEventsSelectedListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
mCallback.onEventSelected(adapter.getItem(position));
}
public void updateEventsView(Years year) {
this.year = Integer.parseInt(year.getYear());
getLoaderManager().initLoader(this.year, null, this);
}
public void updateEventsView(int year) {
this.year = year;
getLoaderManager().initLoader(this.year, null, this);
}
//Loader
#Override
public Loader<List<Events>> onCreateLoader(int arg0, Bundle arg1) {
Log.i("EventsFragment","EventsFragment.onCreateLoader");
return new EventsLoader(getActivity(),this.year);
}
#Override
public void onLoadFinished(Loader<List<Events>> arg0, List<Events> data) {
Log.i("EventsFragment","EventsFragment.onLoadFinished");
adapter.setData(data);
if(isResumed()){
setListShown(true);
}else{
setListShownNoAnimation(false);
}
}
#Override
public void onLoaderReset(Loader<List<Events>> arg0) {
Log.i("EventsFragment","EventsFragment.onLoaderReset");
adapter.setData(null);
} }
How I should do the resume?
greets Mr.P.
Related
I am using an interface, as is standard (best?) practice to communicate between a series of fragments. The business logic requires the app to collect some information in fragment n+1 and if the "next" button is tapped then the user goes to fragment n+2. If the "back" button is tapped then the user goes to fragment n. I am also using a nice sliding animation to display the transition from one fragment to the other depending on the direction. I cannot figure out why this is not working and I am getting the null pointer error on this line:
createPlanListener.onCreatePlan(bundle);
Here is the initial fragment Mealplan.class where I trigger the transition. I have left all of the boiler plate code generated by Android Studio as is:
public class MealplanFragment extends Fragment {
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
private FloatingActionButton createMealplan;
// bunch of variables
private Bundle bundle;
private OnCreatePlanListener createPlanListener;
public MealplanFragment() {
// Required empty public constructor
}
public static MealplanFragment newInstance(String param1, String param2) {
MealplanFragment fragment = new MealplanFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Other code that has nothing to do with the bundle or the listener
// Floating action bar
createMealplan.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
bundle.putBoolean("direction", true);
createPlanListener.onCreatePlan(bundle);
}
});
return mealplanView;
}
public void onButtonPressed(Bundle bundle) {
if (createPlanListener != null) {
createPlanListener.onCreatePlan(bundle);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mealplanContext = context;
if (context instanceof OnCreatePlanListener) {
createPlanListener = (OnCreatePlanListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
createPlanListener = null;
}
public interface OnCreatePlanListener {
void onCreatePlan(Bundle bundle);
}
#Override
public void onResume() {
super.onResume();
}
And here is MainActivity.class
public class MainActivity extends AppCompatActivity implements
MealplanFragment.OnCreatePlanListener {
// Non related variables
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// MealplanFragment is the default fragment at onCreate
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.frame_container, new MealplanFragment(), null).commit();
}
}
#Override
public void onCreatePlan(Bundle bundle) {
if (bundle != null) {
Boolean direction = bundle.getBoolean("direction");
ReceptionFragment fragment = new ReceptionFragment();
openFragment(bundle, fragment, direction);
}
}
private void openFragment(Bundle bundle, Fragment fragment, Boolean direction) {
fragment.setArguments(bundle);
//Starting fragment with animation
if (direction) {
android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_right).replace(R.id.frame_container, fragment, null);
fragmentTransaction.commit();
} else {
android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_left).replace(R.id.frame_container, fragment, null);
fragmentTransaction.commit();
}
}
}
createMealplan.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
bundle.putBoolean("direction", true);
createPlanListener.onCreatePlan(bundle);
}
});
This is your click listener. bundle is defined as class variable but never initialized and hence the null pointer exception. I would suggest that you use a local variable -> create a new instance of bundle, add data and then invoke callback. Also, createPlanListener is nullable, so you should add a check for that as well.
I'm creating an app, and I have a doubt on how to communicate between fragments, I know I must communicate to the parent activity and etcetera my question is more best practice oriented. My app consists of a MainActivity with a navigation drawer which depending on the selection calls a fragment and puts it on the main screen.
I have 2 fragments which via a button need to call another fragment (I can convert it to an activity with no problem) that opens the camera to scan a barcode (BarScanFragment) (https://github.com/dm77/barcodescanner).
My question is it possible to know which fragment called the BarScanFragment so I can send the argument to the correct fragment, and how do I achieve it.
BarScanFragment.java
public class BarScanFragment extends Fragment implements ZXingScannerView.ResultHandler{
private ZXingScannerView mScannerView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mScannerView = new ZXingScannerView(getActivity());
return mScannerView;
}
#Override
public void onResume() {
super.onResume();
mScannerView.setResultHandler(this);
mScannerView.startCamera();
}
#Override
public void onPause() {
super.onPause();
mScannerView.stopCamera();
}
#Override
public void handleResult(Result result) {
Log.i("TAG", result.getText());
Bundle args = new Bundle();
args.putString("barcodeScan", result.getText());
}
FragmentA.java
......
......
barcodeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment content = new BarScanFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.flFragmentContainer, content).addToBackStack("TRADEIN")
.commit();
/*Intent intent = new Intent(rootView.getContext(), BarcodeScannerActivity.class);
startActivity(intent);*/
}
});
Fragment b.java
.....
.....
barcodeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment content = new BarScanFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.flFragmentContainer, content).addToBackStack("INFOPRODUCT")
.commit();
/*Intent intent = new Intent(rootView.getContext(), BarcodeScannerActivity.class);
startActivity(intent);*/
}
});
Take a look on setTargetFragment and getTargetFragment. It's the easiest way to communicate back and forth between fragment.
Here there is a little example https://github.com/alexfu/TargetFragmentExample
You can add a parameter to the BarScanFragment's constructor:
public BarScanFragment(int creatorFragment) {
// Do something with creatorFragment
}
Save "creatorFragment" values in your activity:
public static final int FRAGMENT_1 = 0;
public static final int FRAGMENT_2 = 1;
Then in your button listeners create the BarScanFragment with a specific value:
Fragment content = new BarScanFragment(MainActivity.FRAGMENT_1);
or
Fragment content = new BarScanFragment(MainActivity.FRAGMENT_2);
Declare callbacks in your activity and call methods from another fragment using these callbacks
public interface Callback1 {
void callbackMethod1();
}
public interface Callback2 {
void callbackMethod2();
}
public class Activity extends ActionBarActivity implements Callback1, Callback2 {
Fragment1 mFragment1;
Fragment2 mFragment2;
#Override
public void callbackMethod1() {
mFragment2.method2();
}
#Override
public void callbackMethod2() {
mFragment1.method1();
}
}
public class Fragment1 extends Fragment {
Callback1 callback;
#Override
public void onAttach(android.app.Activity activity) {
super.onAttach(activity);
callback = (Callback1) getActivity();
}
void callMethodOfFragment1() {
callback.callbackMethod1();
}
#Override
public void onDetach() {
super.onDetach();
callback = null;
}
public void method1() {
do_sth_in_fr2();
}
}
public class Fragment2 extends Fragment {
Callback2 callback;
#Override
public void onAttach(android.app.Activity activity) {
super.onAttach(activity);
callback = (Callback2) getActivity();
}
void callMethodOfFragment2() {
callback.callbackMethod2();
}
#Override
public void onDetach() {
super.onDetach();
callback = null;
}
public void method2() {
do_sth_in_fr1();
}
}
EDIT: This question was created as part of one of my first Android projects when I was just starting out with Android application development. I'm keeping this for historical reasons, but you should consider using EventBus or RxJava instead. This is a gigantic mess.
Please DO NOT CONSIDER using this. Thank you.
In fact, if you want something cool that solves the problem of using a single activity with multiple "fragments", then use flowless with custom viewgroups.
I have implemented a way to initiate the creation of Fragments, from Fragments using a broadcast intent through the LocalBroadcastManager to tell the Activity what Fragment to instantiate.
I know this is a terribly long amount of code, but I'm not asking for debugging, it works perfectly as I intended - the data is received, the creation can be parametrized by Bundles, and Fragments don't directly instantiate other Fragments.
public abstract class FragmentCreator implements Parcelable
{
public static String fragmentCreatorKey = "fragmentCreator";
public static String fragmentCreationBroadcastMessage = "fragment-creation";
public static String fragmentDialogCreationBroadcastMessage = "fragment-dialog-creation";
protected Bundle arguments;
protected Boolean hasBundle;
public FragmentCreator(Bundle arguments, boolean hasBundle)
{
this.arguments = arguments;
this.hasBundle = hasBundle;
}
protected FragmentCreator(Parcel in)
{
hasBundle = (Boolean) in.readSerializable();
if (hasBundle == true && arguments == null)
{
arguments = in.readBundle();
}
}
public Fragment createFragment()
{
Fragment fragment = instantiateFragment();
if (arguments != null)
{
fragment.setArguments(arguments);
}
return fragment;
}
protected abstract Fragment instantiateFragment();
#Override
public int describeContents()
{
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags)
{
dest.writeSerializable(hasBundle);
if (arguments != null)
{
arguments.writeToParcel(dest, 0);
}
}
public void sendFragmentCreationMessage(Context context)
{
Intent intent = new Intent(FragmentCreator.fragmentCreationBroadcastMessage);
intent.putExtra(FragmentCreator.fragmentCreatorKey, this);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
public void sendDialogFragmentCreationMessage(Context context)
{
Intent intent = new Intent(FragmentCreator.fragmentDialogCreationBroadcastMessage);
intent.putExtra(FragmentCreator.fragmentCreatorKey, this);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
}
This way, a Fragment that is created looks like this:
public class TemplateFragment extends Fragment implements GetActionBarTitle, View.OnClickListener
{
private int titleId;
public TemplateFragment()
{
titleId = R.string.app_name;
}
#Override
public int getActionBarTitleId()
{
return titleId;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_template, container, false);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onClick(View v)
{
}
public static class Creator extends FragmentCreator
{
public Creator()
{
super(null, false);
}
public Creator(Bundle bundle)
{
super(bundle, true);
}
protected Creator(Parcel in)
{
super(in);
}
#Override
protected Fragment instantiateFragment()
{
return new TemplateFragment();
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<TemplateFragment.Creator> CREATOR = new Parcelable.Creator<TemplateFragment.Creator>()
{
#Override
public TemplateFragment.Creator createFromParcel(Parcel in)
{
return new TemplateFragment.Creator(in);
}
#Override
public TemplateFragment.Creator[] newArray(int size)
{
return new TemplateFragment.Creator[size];
}
};
}
}
The initial container activity that can process the messages looks like this:
Intent intent = new Intent();
intent.setClass(this.getActivity(), ContainerActivity.class);
intent.putExtra(FragmentCreator.fragmentCreatorKey,
new TemplateFragment.Creator());
startActivity(intent);
And the Fragments "instantiate other Fragments" like this:
Bundle bundle = new Bundle();
bundle.putParcelable("argument", data);
TemplateFragment.Creator creator = new TemplateFragment.Creator(bundle);
creator.sendFragmentCreationMessage(getActivity());
And the Container Activity receives the instantiation request:
public class ContainerActivity extends ActionBarActivity implements SetFragment, ShowDialog
{
private BroadcastReceiver mFragmentCreationMessageReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
setFragment((FragmentCreator) intent.getParcelableExtra(FragmentCreator.fragmentCreatorKey));
}
};
private BroadcastReceiver mFragmentDialogCreationMessageReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
showDialog((FragmentCreator) intent.getParcelableExtra(FragmentCreator.fragmentCreatorKey));
}
};
#Override
public void onCreate(Bundle saveInstanceState)
{
super.onCreate(saveInstanceState);
this.setContentView(R.layout.activity_container);
getActionBar().setDisplayHomeAsUpEnabled(true);
if (saveInstanceState == null)
{
Fragment fragment = ((FragmentCreator) getIntent().getParcelableExtra(
FragmentCreator.fragmentCreatorKey)).createFragment();
if (fragment != null)
{
replaceFragment(fragment);
}
}
else
{
this.getActionBar()
.setTitle(
((GetActionBarTitle) (this.getSupportFragmentManager()
.findFragmentById(R.id.activity_container_container)))
.getActionBarTitleId());
}
getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
{
public void onBackStackChanged()
{
int backCount = getSupportFragmentManager().getBackStackEntryCount();
if (backCount == 0)
{
finish();
}
}
});
}
#Override
protected void onResume()
{
LocalBroadcastManager.getInstance(this).registerReceiver(mFragmentCreationMessageReceiver,
new IntentFilter(FragmentCreator.fragmentCreationBroadcastMessage));
LocalBroadcastManager.getInstance(this).registerReceiver(mFragmentDialogCreationMessageReceiver,
new IntentFilter(FragmentCreator.fragmentDialogCreationBroadcastMessage));
super.onResume();
}
#Override
protected void onPause()
{
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mFragmentCreationMessageReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(
mFragmentDialogCreationMessageReceiver);
}
#Override
public void setFragment(FragmentCreator fragmentCreator)
{
Fragment fragment = fragmentCreator.createFragment();
replaceFragment(fragment);
}
public void replaceFragment(Fragment fragment)
{
if (fragment != null)
{
this.setTitle(((GetActionBarTitle) fragment).getActionBarTitleId());
getSupportFragmentManager().beginTransaction()
.replace(R.id.activity_container_container, fragment).addToBackStack(null).commit();
}
}
#Override
public void showDialog(FragmentCreator fragmentCreator)
{
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fragmentCreator.createFragment();
if (fragment instanceof DialogFragment)
{
DialogFragment df = (DialogFragment) fragment;
df.show(fm, "dialog");
}
else
{
Log.e(this.getClass().getSimpleName(), "showDialog() called with non-dialog parameter!");
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (item.getItemId() == android.R.id.home)
{
this.onBackPressed();
}
return super.onOptionsItemSelected(item);
}
}
My question is, is this actually a good idea, or is this a terrible case of "over-engineering" (creating a Factory for each Fragment and sending it to the Activity in the form of a local broadcast, rather than just casting the Activity of the most possible holder activity's interface and calling the function like that)?
My goal was that this way, I can use the same Activity for holding "branch" fragments, so that I don't need to make one for each menu point. Rather than just re-use the same activity, and divide all logic into fragments. (Currently it doesn't support orientation-based layout organization, I see that downside - and also that this way each Fragment needs to hold a static creator, which is extra 'boilerplate code').
If you know the answer why I shouldn't be using the local broadcast manager for this, I'll be happy to hear the response. I think it's pretty neat, but there's a chance it's just overcomplicating something simple.
You can use Interface for it so main objective of Fragment re-usability is maintained. You can implement communication between Activity-Fragment OR Fragment-Fragment via using following :
I am asuming that your moto is Fragment to communicate with its Activity and other Fragments.
If this is the case please go throught it.
To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity. The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.
Example :
# In fragment
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallback = (OnHeadlineSelectedListener) activity;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
mCallback.onArticleSelected(position);
}
}
# In Activity
public static class MainActivity extends Activity implements HeadlinesFragment.OnHeadlineSelectedListener{
public void onArticleSelected(int position) {
// Do something here
}
}
Link: http://developer.android.com/training/basics/fragments/communicating.html
I'm stuck with communication between activity and fragment using interface. I have created activity with child fragment. I wanna do some stuff with continuous thread defined in activity and during that thread when I'm getting some result at that time I wanna trigger to child fragment to do something.
My Container Activity
public class MySpaceActivity extends BaseDrawerActivity {
private OnSetLastSeenListener mListner;
public static Thread mThread = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setHeaders(Const.MY_SPACE);
super.setSubmenus(Const.MY_SPACE,
Utils.getSubmenuList(Const.MY_SPACE, MySpaceActivity.this),
submenuBean);
// super.attachFragment(submenuBean);
}
#Override
public void setHeaderSubMenu(SubmenuBean subMenuBean) {
// txt_submenu.setText(subMenuBean.getSubmenu_name());
this.submenuBean = subMenuBean;
Log.print("::::: setHeaderSubMenu ::::");
super.attachFragment(submenuBean);
}
public void setsubFragment(SubmenuBean subMenuBean) {
this.submenuBean = subMenuBean;
super.attachSubFragment(submenuBean);
}
#Override
public void onBackPressed() {
super.onBackPressed();
popLastFragment();
}
private void popLastFragment() {
if (super.getNumberOfChilds() > 1) {
super.popSubFragment();
} else {
finish();
}
}
#Override
protected Fragment getFragement() {
StudentsFragment fragment = new StudentsFragment(Const.MY_SPACE,
getSubmenubean());
return fragment;
}
public SubmenuBean getSubmenubean() {
return submenuBean;
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
mThread = new Thread(new CountDownTimer(MySpaceActivity.this));
mThread.start();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
if (mThread.isAlive()) {
mThread.interrupt();
mThread = null;
}
}
public void updateLastSeen(){
Log.print("::::::Call Interface::::::");
mListner.updateLastSeen();
}
class CountDownTimer implements Runnable {
private Context mContext;
private JSONObject mJsonObject;
private JSONArray mJsonArray;
public CountDownTimer(Context mContext) {
this.mContext = mContext;
}
// #Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
HttpChatLastSeen mChat = new HttpChatLastSeen();
mJsonObject = mChat.Http_ChatLastSeen(mContext);
String mResult = mJsonObject.getString("Result");
if (mResult.equalsIgnoreCase(String
.valueOf(Const.RESULT_OK))) {
mJsonArray = mJsonObject.getJSONArray("UserData");
for (int i = 0; i < mJsonArray.length(); i++) {
mJsonObject = mJsonArray.getJSONObject(i);
new DbStudentMasterBll(mContext).update(
"last_seen", mJsonObject
.getString("LastSeen"), Integer
.parseInt(mJsonObject
.getString("UserId")));
}
} else {
Log.print("MY LAST SEEN Response : "
+ mJsonObject.toString());
}
updateLastSeen();
Thread.sleep(15000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
Log.print("ChatLastSeenThread : ", e.getMessage());
}
}
}
}
}
My Child Fragment With Interface :
public class StudentsFragment extends Fragment implements OnSetLastSeenListener{
TextView txt_submenu;
ListView list_students;
SubmenuBean submenuBean;
int Mainmenu;
MySpaceActivity mMySpaceActivity;
ArrayList<DbStudentMasterBean> studentsList;
StudentsAdapter mAdapter = null;
OnSetLastSeenListener mListner;
public StudentsFragment() {
super();
}
public StudentsFragment(int Mainmenu, SubmenuBean submenuBean) {
this.submenuBean = submenuBean;
this.Mainmenu = Mainmenu;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_students, container,
false);
mMySpaceActivity = (MySpaceActivity) getActivity();
txt_submenu = (TextView) view.findViewById(R.id.txt_submenu);
txt_submenu.setText(submenuBean.getSubmenu_name());
txt_submenu.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mMySpaceActivity.openDrawer();
}
});
list_students = (ListView) view.findViewById(R.id.list_colleagues);
studentsList = new DbStudentMasterBll(getActivity()).getAllRecords();
mAdapter = new StudentsAdapter(getActivity(), studentsList, handler);
list_students.setAdapter(mAdapter);
list_students.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
DbStudentMasterBean bean = (DbStudentMasterBean) parent
.getAdapter().getItem(position);
Message msg = new Message();
msg.what = CHAT;
msg.obj = bean;
handler.sendMessage(msg);
}
});
return view;
}
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case CHAT:
submenuBean.setTag(VIEWCHATSTUDENT);
DbStudentMasterBean bean = (DbStudentMasterBean) msg.obj;
mMySpaceActivity.setsubFragment(submenuBean);
break;
}
};
};
#Override
public void updateLastSeen() {
// TODO Auto-generated method stub
Log.print("!!!!!!!!!Refresh Adapter!!!!!!!!!!!");
mAdapter.notifyDataSetChanged();
}
}
My Interface :
public interface OnSetLastSeenListener {
public void updateLastSeen();
}
So I have implemented interface OnSetLastSeenListener with my child fragment StudentsFragment . Now I'm calling method of tht interface updateLastSeen() from my container activity with thread. But it is not getting trigger to child fragment where I have implemented interface. So I don't know whether it is good way to communicate or not? Let me take your help to suggest on this solution or best way to communicate from child fragment to parent activity.
Thanks,
It is better to use interface when you want to communicate something from Fragment to Activity and not vice versa.
In your case, you can directly call the method in Fragment from Activity through fragment object. No need to use interface.
Something like this (For static fragments)
StudentsFragment fragment = (StudentsFragment) getFragmentManager()
.findFragmentById(R.id.fragmentid);
if (fragment != null && fragment.isInLayout()) {
fragment.updateLastSeen();
}
For dynamic fragment you can use the fragment object directly.
I have build a slide.
I have a ViewPage Activity that call a fragment every time that i swip to left or to right.
My question is:
I have a variable int that in the initial state have the value 6 (week_of_year). When i slide to right is call a new fragment and the variable is not increment as i intend. The variable is only increment in the the second slide.
For example: 6 -> 6 -> 7 -> 8 instead of 6 -> 7 -> 8 -> And i don't have ideia why this happens.
Here is my code:
ViewPage Activity
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide);
/**
* Instantiate a ViewPager and a PagerAdapter
*/
date = Calendar.getInstance();
mPager = (ViewPager)findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int arg0) {
if(itemOld < arg0){//right
auxFront = auxFront + 1;
oldStartWeek = oldStartWeek + auxFront;
auxFront=0;
}
else if(itemOld > arg0){//left
auxBack = auxBack - 1;
oldStartWeek = oldStartWeek + auxBack;
auxBack=0;
}
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public void onBackPressed(){
if(mPager.getCurrentItem()==0){
super.onBackPressed();
}else{
mPager.setCurrentItem(mPager.getCurrentItem()-1);
}
}
/**
* A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in sequence
*/
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter{
public ScreenSlidePagerAdapter(FragmentManager fm){
super(fm);
}
#Override
public ScreenSlidePageFragment getItem(int position) {
/**
* Pass values from ViewPage activity to Fragment
*/
ScreenSlidePageFragment f = new ScreenSlidePageFragment();
Bundle args = new Bundle();
if(position == 0){
oldStartWeek = date.get(Calendar.WEEK_OF_YEAR);
args.putInt("START_WEEK", oldStartWeek);
f.setArguments(args);
return f;
}
else if(position != 0){
args.putInt("START_WEEK", oldStartWeek);
f.setArguments(args);
itemOld = mPager.getCurrentItem();
return f;
}
return f;
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
}
Fragment that is call in each slide--------------------------------------------
public class ScreenSlidePageFragment extends Fragment implements
AdapterView.OnItemClickListener {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Toast.makeText(getActivity(), "week....." +getArguments().getInt("START_WEEK"), Toast.LENGTH_LONG).show(); //show the correct value
headerWeek.setText(" Week Number: "+getArguments().getInt("START_WEEK",0)); //But is not change corretly in the text view ?????
Thanks for your help and time.
To see why this happens in your ViewPager, you can Log the onCreate, onPause, onResume, etc methods for each fragment. What happens is that the first two fragments are actually created about the same time. So the second fragment is created before it actually displays in a ViewPager, so by the time the user scrolls to the second fragment, there is often old data there.
My solution to this is a little hacky. Note that instead of displayDialog() you would do whatever you needed to update the view when the user is present.
#Override
public void onResume() {
super.onResume();
fragmentActive = true;
if (userVisible()){
displayDialog();
}
else{
recursiveWait();
}
}
private void recursiveWait(){
new WaitAndDoXTask(1000, new DoXListener() {
#Override
public void doX() {
Log.d(TAG, "doX");
if (userVisible()){
displayDialog();
}
else if (fragmentActive){
recursiveWait();
}
}
}).execute();
}
private boolean userVisible(){
boolean vis = getUserVisibleHint();
Log.d(TAG, "user visible = " + vis);
return vis;
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause");
fragmentActive = false;
}
Here is the WaitAndDoXTask:
public class WaitAndDoXTask extends AsyncTask<Void, Void, Void>{
DoXListener mListener;
private int mTimeToWait;
/** This class will wait for the set time then do what is put into the listener.
*
*
* Run like this:
* new WaitAndDoXTask(1000, new DoXListener() {
*
* #Override
* public void doX() {
* // TODO Auto-generated method stub
*
* }
* }).execute();
**/
public WaitAndDoXTask(int timeToWait, DoXListener listener){
super();
mTimeToWait = timeToWait;
mListener = listener;
}
public interface DoXListener{
public void doX();
}
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(mTimeToWait);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (mListener!=null){
mListener.doX();
}
}
}
Alternatively, if you could set up your Fragment with some Adapter and get notified via onDataSetChanged that might work better.