issues when I use tablayout and viewpager inside fragment - android

Hi I have a TabLayout and ViewPager inside a fragment
public class Explore : Android.Support.V4.App.Fragment, AppCompatActivity
{
private TabLayout tablayout;
private ViewPager viewPager;
private TimeBuget timeBuget;
private SpecialActivity specialActivity;
public override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
// Create your fragment here
}
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
// return inflater.Inflate(Resource.Layout.YourFragment, container, false);
//return base.OnCreateView (inflater, container, savedInstanceState);
return inflater.Inflate(Resource.Layout.ExploreLayout,container,false);
viewPager = View.FindViewById<ViewPager> (Resource.Id.viewpagerExplore);
setupViewPager (viewPager);
tablayout = View.FindViewById<TabLayout> (Resource.Id.sliding_tabsExplore);
tablayout.SetupWithViewPager (viewPager);
}
private void InditialFragment()
{
timeBuget = new TimeBuget ();
specialActivity = new SpecialActivity ();
}
public void setupViewPager(ViewPager viewPager)
{
InditialFragment ();
ViewPagerAdapter adapter = new ViewPagerAdapter (SupportFragmentManager);
adapter.addFragment (timeBuget, "Explore");
adapter.addFragment (specialActivity, "Featured");
viewPager.Adapter=adapter;
}
}
Classes cannot have multiple base classes.
If I don't use AppCompatActivity so I can't use SupportFragmentManager
How to solve it?

You have to host the fragment inside the activity, not use both at the same time. After you do that you could access the SupportFragmentManager like this:
ViewPagerAdapter adapter = new ViewPagerAdapter ((SpecialActivity as AppCompatActivity).SupportFragmentManager);

Related

Failed to pass a string from Activity to Fragment

I want to pass a Serializable object from activity to fragment. But at fragment, getArguments() always retuns null. Then I try to pass a simple string value from activity to fragment, it still shows NullPointerExection.
Here is my Activity Class
public class FullProfile extends AppCompatActivity {
private Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;
private Customer customer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_full_profile);
tabLayout = findViewById(R.id.tabLayout);
viewPager = findViewById(R.id.myViewPager);
setupViewPager(viewPager);
ProfileBasicFragment basic = new ProfileBasicFragment();
Bundle bundle = new Bundle();
bundle.putString("profile", "Hello Hello");
basic.setArguments(bundle);
getSupportFragmentManager().beginTransaction().add(R.id.myViewPager, basic).commit();
tabLayout.setupWithViewPager(viewPager);
}
private void setupViewPager(ViewPager viewPager) {
FragmentAdapter fragmentAdapter = new FragmentAdapter(getSupportFragmentManager(), 4);
fragmentAdapter.addFragment(new ProfileBasicFragment(), "Profile");
fragmentAdapter.addFragment(new ProductFragment(), "Product");
fragmentAdapter.addFragment(new WatchListFragment(), "Choices");
viewPager.setAdapter(fragmentAdapter);
}
}
Here is my Fragment..
public class ProfileBasicFragment extends Fragment {
TextView t;
String s;
public ProfileBasicFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_profile_basic, container, false);
t = view.findViewById(R.id.nameTV);
String s = getArguments().getString("profile");
t.setText(s);
return view;
}
}
And Here is the error
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
I can't understand what's is my fault. Can you help me? Thank you
the actual problem is when you initializing the viewPager.
private void setupViewPager(ViewPager viewPager) {
...
fragmentAdapter.addFragment(new ProfileBasicFragment(), "Profile");
//Problem is here
...
}
So send the data from here also or in your fragment do this
if(getArguments()!=null){
String s = getArguments().getString("profile");
t.setText(s);
}
You are using the same fragment twice, and sending the argument once in basic only(setupviewpager and basic). Either pass the argument in both case or add a null check before getting the string.

Save RecyclerView State inside Fragment in ViewPager created inside another Fragment

I have a ViewPager inside a Fragment
public class FragmentPager extends BaseFragment {
#Bind(R.id.viewpager)
ViewPager viewPager;
#Bind(R.id.detail_tabs)
TabLayout detailTabs;
private Activity mActivity;
private PagerAdapter mPagerAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mPagerAdapter = new PagerAdapter(getChildFragmentManager());
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_pager, container, false);
ButterKnife.bind(this, v);
viewPager.setAdapter(mPagerAdapter);
final int pageMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources()
.getDisplayMetrics());
viewPager.setPageMargin(pageMargin);
detailTabs.setupWithViewPager(viewPager);
return v;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = activity;
}
#Override
public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
}
}
I am already using FragmentStatePagerAdapter to manage my fragments in ViewPager. Each Fragment has a RecyclerView. On clicking each item of the RecyclerView I am replacing the FragmentPager with FragmentDetail. When I navigate back to the FragmentPager, the RecyclerView starts from the beginning instead of position scrolled.
I think you change your fragment with fragmentTransaction replace method. You need to do it with fragmentTransaction add method. See the below
Basic difference between add() and replace() method of Fragment

ViewPager inside fragment, how to retain state?

In my application the fragment activity holds two fragments, Fragment A and Fragment B. Fragment B is a view pager that contains 3 fragments.
In my activity, to prevent that the fragment is recreated on config changes:
if(getSupportFragmentManager().findFragmentByTag(MAIN_TAB_FRAGMENT) == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.container, new MainTabFragment(), MAIN_TAB_FRAGMENT).commit();
}
Code for Fragment B:
public class MainTabFragment extends Fragment {
private PagerSlidingTabStrip mSlidingTabLayout;
private LfPagerAdapter adapter;
private ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_tab, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
this.adapter = new LfPagerAdapter(getChildFragmentManager());
this.mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
this.mViewPager.setAdapter(adapter);
this.mSlidingTabLayout = (PagerSlidingTabStrip) view.findViewById(R.id.sliding_tabs);
this.mSlidingTabLayout.setViewPager(this.mViewPager);
}
}
Code for the adapter:
public class LfPagerAdapter extends FragmentPagerAdapter {
private static final int NUM_ITEMS = 3;
private FragmentManager fragmentManager;
public LfPagerAdapter(FragmentManager fm) {
super(fm);
this.fragmentManager = fm;
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
Log.d("TEST","TEST");
switch (position) {
case 1:
return FragmentC.newInstance();
case 2:
return FragmentD.newInstance();
default:
return FragmentE.newInstance();
}
}
}
My problem is that I am not able to retain the state of the view pager an its child fragments on orientation changes.
Obviously this is called on every rotation:
this.adapter = new LfPagerAdapter(getChildFragmentManager());
which will cause the whole pager to be recreated, right? As a result
getItem(int position)
will be called on every rotation and the fragment will be created from scratch and losing his state:
return FragmentC.newInstance();
I tried solving this with:
if(this.adapter == null)
this.adapter = new LfPagerAdapter(getChildFragmentManager());
in onViewCreated but the result was that on rotation the fragments inside the pager where removed.
Any ideas how to correctly retain the state inside the pager?
You will need to do 2 things to resolve the issue:
1) You should use onCreate method instead of onViewCreated to instantiate LfPagerAdapter;
i.e.:
public class MainTabFragment extends Fragment {
private PagerSlidingTabStrip mSlidingTabLayout;
private LfPagerAdapter adapter;
private ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
this.adapter = new LfPagerAdapter(getChildFragmentManager());
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_tab, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
this.mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
this.mViewPager.setAdapter(adapter);
this.mSlidingTabLayout = (PagerSlidingTabStrip) view.findViewById(R.id.sliding_tabs);
this.mSlidingTabLayout.setViewPager(this.mViewPager);
}
}
2) You will need to extend FragmentStatePagerAdapter instead of FragmentPagerAdapter
Android will automatically recreate your activity on configuration without this line android:configChanges="keyboardHidden|orientation|screenSize" in you manifest so that you can handle onConfiguration change yourself.
The only way then is to use onSaveInstanceState() in both your activityFragement to save viewPager state(current position for example) and in fragments where you need to save stuff
Example on how you can save current position of viewpager and restore it onConfiguration change
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
int position = mViewPager.getCurrentItem();
outState.Int("Key", position );
}
#Override //then restore in on onCreate();
public void onCreated(Bundle savedInstanceState) {
super.onCreated(savedInstanceState);
// do stuff
if (savedInstanceState != null) {
int position= savedInstanceState.getInt("Key");
mViewPager.setCurrentItem(position)
}
}
Of course, this is a very basic example.
Ps: to restore in fragment use onActivityCreated() instead of onCreate() method.
Here is another example on how to retain state : Click me!

Notify from child fragment inside ViewPager to his parent an event

i have a fragment inside a activity, this fragment contains a viewpager, this is the code:
public class RepliesContainerFragment extends Fragment {
#InjectView(R.id.viewPager)
ViewPager pager;
private PagerAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ReplyActivity replyActivity = (ReplyActivity) getActivity();
List<Replie> replies = getArguments().getParcelableArrayList("replies");
adapter = new PagerAdapter(replyActivity.getSupportFragmentManager(), replies);
setActionBar();
}
private void setActionBar() {
getActivity().getActionBar().setDisplayHomeAsUpEnabled(false);
getActivity().getActionBar().setIcon(getResources().getDrawable(R.drawable.ic_back));
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
getActivity().getActionBar().setTitle("Respuestas");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.work_containter_replies, container, false);
ButterKnife.inject(this, view);
pager.setAdapter(adapter);
return view;
}
}
Inside the adapter i had instantiate some fragments like this:
public class ReplyFragment extends Fragment {
#InjectView(R.id.tvQuestion)
TextView tvQuestion;
#InjectView(R.id.frameContainter)
FrameLayout replyContainer;
private ReplyView replyView;
private String question;
private String currentReplie;
private int replieType;
private int questionId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
replieType = getArguments().getInt("replyType");
question = getArguments().getString("question");
questionId = getArguments().getInt("questionId");
currentReplie = getArguments().getString("currentReplie");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.work_reply_fragment, container, false);
ButterKnife.inject(this, view);
initQuestionText();
return view;
}
private void persistReply() {
ReplyActivity replyActivity = (ReplyActivity) getActivity();
if (replyActivity != null) {
//DO SOMETHING
//Notify to adapter from here
}
}
}
}
As you can see, i want to notify to my RepliesContainerFragment and his inside adapter that some event happens and do an action..
How can i do it this?
With broadcastreceivers, with callbacks(Interfaces)..?I am not sure.
The very simple solution for this is to pass a listener instance from your parent fragment to a child fragment. You have to create a listener interface, create an instance of it in your parent fragment, and pass that instance to all your children fragments.
By the way there is a topic regarding this problem in the official tutorial.
Hope this helps.
I think it is easier:
private void persistReply() {
ReplyActivity replyActivity = (ReplyActivity) getActivity();
if (replyActivity != null) {
//DO SOMETHING
RepliesContainerFragment frag = ((RepliesContainerFragment)this.getParentFragment());
frag.getAdapter().notifyDataSetChanged();
}
}
}
and make getter setter for adapter

Where start code in fragment?

i dont know where can i put the code to start a fragment. I have a viewpager with fragments but they dont do nothing. For example:
I have the class fragmentosactivity thats inicialize de fragments:
public class FragmentosActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
super.setContentView(R.layout.fragmentos_layout);
// Paginador
this.inicializaPaginas();
//ActionBar
ActionBar actionBar = getSupportActionBar();
actionBar.setTitle("Contoles");
//CirculoProgreso
setProgressBarIndeterminateVisibility(Boolean.FALSE);
}
//Este metodo inicia todos los fragments
private void inicializaPaginas() {
FragmentAdapter adapter =
new FragmentAdapter(getSupportFragmentManager());
adapter.addFragment(new Mapa());
adapter.addFragment(new Cercanos());
ViewPagerAdapter vadapter = new ViewPagerAdapter( this );
ViewPager pager =
(ViewPager)findViewById( R.id.viewpager );
TitlePageIndicator indicator =
(TitlePageIndicator)findViewById( R.id.indicator );
pager.setAdapter( adapter );
pager.setAdapter( vadapter );
indicator.setViewPager( pager );
}
}
Here i call cercanos.class
And in cercanos i have
public class Cercanos extends ListFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
return (LinearLayout) inflater.inflate(R.layout.cercanos, container, false);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] objetos = {"hola","adios"};
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, objetos));
Parseador.anadedatos();
}
}
But never enter in onCreate method of cercanos, why? I think i dont understand for all the use of fragments.
this is called only in main activity, not in views
public class XXX extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
....
}
}
onCreate is a fragment of the application life-cycle, not class or view life-cycle
You can try to overriding this method:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
And put the onCreate code here.
Anyway, you can take a look at the documentation, because fragments don't have a setContentView, is in the xml layout where you tell what fragment controlls the layout. http://developer.android.com/guide/topics/fundamentals/fragments.html
Hope this helps

Categories

Resources