I am new to android firebase. The question I have is. The first is to distribute the date from an Activity to several fragments. So far I have solved that problem. But I have a requirement to display the data in Firebase database in each Fragment. But the problem is that the application stops after entering the data in firebase.
stdAttn Activity
public class stdAttnDisplay extends AppCompatActivity {
private ViewPager pager;
private TabLayout tabs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_std_attn_display);
pager=(ViewPager) findViewById(R.id.vpager);
tabs=(TabLayout) findViewById(R.id.tablayout1);
tabs.setupWithViewPager(pager);
tabs.setTabGravity(TabLayout.GRAVITY_FILL);
tabs.setTabMode(TabLayout.MODE_SCROLLABLE);
setupViewPager(pager);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
//bundle
Bundle bundle =new Bundle();
bundle.putString("DATE","01-05-2023");
IABF_Attnfrag frag_iabf = new IABF_Attnfrag();
DABF_Attnfrag frag_dabf = new DABF_Attnfrag();
CMA_Attnfrag frag_cma = new CMA_Attnfrag();
CHARTERED_Attnfrag frag_chartered = new CHARTERED_Attnfrag();
ENGLISH_Attnfrag frag_english = new ENGLISH_Attnfrag();
AAT1_Attnfrag frag_aat1 = new AAT1_Attnfrag();
AAT2_Attnfrag frag_aat2 = new AAT2_Attnfrag();
AAT3_Attnfrag frag_aat3 = new AAT3_Attnfrag();
frag_iabf.setArguments(bundle);
frag_dabf.setArguments(bundle);
frag_cma.setArguments(bundle);
frag_chartered.setArguments(bundle);
frag_english.setArguments(bundle);
frag_aat1.setArguments(bundle);
frag_aat2.setArguments(bundle);
frag_aat3.setArguments(bundle);
adapter.addFrag(frag_iabf,"IABF");
adapter.addFrag(frag_dabf,"DABF");
adapter.addFrag(frag_cma,"CMA");
adapter.addFrag(frag_chartered,"CHARTERED");
adapter.addFrag(frag_english,"ENGLISH");
adapter.addFrag(frag_aat1,"AAT-i");
adapter.addFrag(frag_aat2,"AAT-ii");
adapter.addFrag(frag_aat3,"AAT-iii");
viewPager.setAdapter(adapter);
}
}
Fragment
public class IABF_Attnfrag extends Fragment {
String dateTxt;
private Bundle bundle;
myadapter adapter;
RecyclerView recViewiabf;
private DatabaseReference propertyRef;
public IABF_Attnfrag() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_i_a_b_f__attnfrag, container, false);
recViewiabf = (RecyclerView) view.findViewById(R.id.recViewiabf);
bundle = this.getArguments();
dateTxt = bundle.getString("DATE");
Log.e("DATE_FRAG_INBOUND",""+dateTxt);
propertyRef = FirebaseDatabase.getInstance()
.getReference()
.child("attendance")
.child("IABF")
.child(dateTxt);
propertyRef.keepSynced(true);
recViewiabf.setLayoutManager(new LinearLayoutManager(getContext()));
FirebaseRecyclerOptions<modelAttn> options =
new FirebaseRecyclerOptions.Builder<modelAttn>()
.setQuery(propertyRef, modelAttn.class)
.build();
adapter = new myadapter(options);
recViewiabf.setAdapter(adapter);
return view;
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
}
Adapter
public class myadapter extends FirebaseRecyclerAdapter<modelAttn,myadapter.myviewholder>
{
public myadapter(#NonNull FirebaseRecyclerOptions<modelAttn> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull myviewholder holder, int position, #NonNull modelAttn model) {
holder.stdFulName.setText(model.getName());
holder.stdidtv.setText(model.getSt_id());
}
#NonNull
#Override
public myviewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.attn_item,parent,false);
return new myviewholder(view);
}
public class myviewholder extends RecyclerView.ViewHolder {
TextView stdFulName, stdidtv;
public myviewholder(#NonNull View itemView) {
super(itemView);
stdidtv = itemView.findViewById(R.id.indextext);
stdFulName = itemView.findViewById(R.id.nametext);
}
}
}
Model Attn
public class modelAttn {
String Name, st_id;
public modelAttn() {
}
public modelAttn(String name, String st_id) {
this.Name = name;
this.st_id = st_id;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getSt_id() {
return st_id;
}
public void setSt_id(String st_id) {
this.st_id = st_id;
}
}
FireBase Database Screenshot
Database Screenshot
What I need is to distribute the data from the Activity to the Fragment and then display the relevant data in the RecyclerView using the data in the Firebase database.
If you create a regular adapter then pass it a list of custom objects which you retrieve from firebase. You can make a static list on your MainActivity that can be referenced anywhere including in the fragment.
Related
ViewPager2 is scrolling to the wrong page when I am selecting a tab from a far position. Swiping and selecting tab of loaded pages working fine. The error is only happening when the page is not loaded and scrolling animation is active. I have created a large viewpager2 with 100 pages containing Recyclerview.
My Activity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TabLayout tabLayout = findViewById(R.id.tabLayout);
ViewPager2 viewPager = findViewById(R.id.viewPager2);
viewPager.setAdapter(new viewPagerAdapter(this));
new TabLayoutMediator(tabLayout, viewPager, true, true,
((tab, position) -> tab.setText("Page: " + position))).attach();
}
private class viewPagerAdapter extends FragmentStateAdapter {
public viewPagerAdapter(FragmentActivity fa) {
super(fa);
}
#Override
public Fragment createFragment(int position) {
Fragment fragment = new itemFragment();
Bundle args = new Bundle();
args.putInt(itemFragment.ARG_PARAM1, position);
fragment.setArguments(args);
return fragment;
}
#Override
public int getItemCount() {
return 100;
}
}
}
My Fragment
public class itemFragment extends Fragment {
public static final String ARG_PARAM1 = "parram1";
int pagePosition;
public itemFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pagePosition = getArguments().getInt(ARG_PARAM1);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frgment_item, container, false);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView textView = view.findViewById(R.id.textView);
textView.setText("Page - " + pagePosition);
RecyclerView recyclerView = view.findViewById(R.id.recyclerView);
recyclerView.setAdapter(new myAdapter());
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 16));
}
private class myAdapter extends RecyclerView.Adapter<Myvh> {
#Override
public Myvh onCreateViewHolder(ViewGroup parent, int viewType) {
return new Myvh(new TextView(getContext()));
}
#Override
public void onBindViewHolder(Myvh holder, int position) {
int codepoint=pagePosition*700 + position;
char[] ch=Character.toChars(codepoint);
holder.textView.setText(String.valueOf(ch));
}
#Override
public int getItemCount() { return 700; }
}
private class Myvh extends RecyclerView.ViewHolder {
TextView textView;
public Myvh(View itemView) {
super(itemView);
textView = (TextView) itemView;
}
}
}
I have also tried Recyclerview adapter instead of FragmentStateAdapter and getting same problem.
I have found some solution but not sufficient.
Those are:
Using old ViewPager(deprecated)
Using viewPager.setOffscreenPageLimit(100); (taking huge time to load activity)
Disabling smoothscroll ( looks awful when swiping)
The Error
'FirebaseRecyclerAdapter(com.firebase.ui.database.FirebaseRecyclerOptions<com.munopa.revise.Files>)'
in 'com.firebase.ui.database.FirebaseRecyclerAdapter' cannot be
applied to '(java.lang.Class<com.munopa.revise.Files>, int,
java.lang.Class<com.munopa.revise.MainActivity.FilesViewHolder>,
com.google.firebase.database.DatabaseReference)'
My Main Activity
public class MainActivity extends AppCompatActivity {
private EditText mSearchField;
private RecyclerView mFileList;
private FloatingActionButton mSearchButton;
private DatabaseReference mFilesDatabase;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFilesDatabase = FirebaseDatabase.getInstance().getReference().child("Files");
mSearchField = findViewById(R.id.search_bar_input);
mFileList = findViewById(R.id.file_list);
mSearchButton = findViewById(R.id.btn_search);
mSearchButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
firebaseFileSearch();
}
});
}
private void firebaseFileSearch() {
FirebaseRecyclerAdapter<Files, FilesViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Files, FilesViewHolder>(
Files.class,
R.layout.paper_card,
FilesViewHolder.class,
mFilesDatabase
) {
#Override
protected void onBindViewHolder(#NonNull FilesViewHolder holder, int position, #NonNull Files model) {
}
#NonNull
#Override
public FilesViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return null;
}
};
}
public class FilesViewHolder extends RecyclerView.ViewHolder{
View mView;
public FilesViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
}
}
This is your problem (and where you are getting the error):
FirebaseRecyclerAdapter<Files, FilesViewHolder> firebaseRecyclerAdapter =
new FirebaseRecyclerAdapter<Files, FilesViewHolder>(
Files.class,
R.layout.paper_card,
FilesViewHolder.class,
mFilesDatabase
)
You are calling the constructor of FirebaseRecyclerAdapter with 4 parameters, but it only expects 1 parameter of type FirebaseRecyclerOptions<Files>.
Refer to https://github.com/firebase/FirebaseUI-Android/blob/master/database/README.md for more details about how to set this up.
I am a beginner at android development. I tried to display data on Recycle View using MVVM. When I opened the fragment the first time it is empty, the second time it showed data. Adapter not called the first time. How to fix this.
Fragment class
public class fragmentEmployee extends Fragment {
private FragmentEmployeeBinding binding;
private ViewGroup viewGroup;
private View view;
private RecyclerView mRecycleView;
private UserAdapter mAdapter;
private EmployeeRegisterViewModel viewModel;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_employee, viewGroup, false);
view = binding.getRoot();
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Toast.makeText(getContext(), "onViewCreated", Toast.LENGTH_SHORT).show();
mRecycleView = binding.recyleViewEmployee;
viewModel = new ViewModelProvider(this).get(EmployeeRegisterViewModel.class);
viewModel.init();
initRecycleView();
viewModel.getEmployee().observe(getViewLifecycleOwner(), new Observer<List<employeeModel>>() {
#Override
public void onChanged(List<employeeModel> employeeModels) {
mAdapter.notifyDataSetChanged();
}
});
}
private void initRecycleView() {
mAdapter = new UserAdapter(getContext(), viewModel.getEmployee().getValue());
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
mRecycleView.setLayoutManager(layoutManager);
mRecycleView.setAdapter(mAdapter);
}
}
UserAdapter class
public class UserAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
public List<employeeModel> employeeModelList= new ArrayList<>();
public Context context1;
public UserAdapter(Context context,List<employeeModel> employeeModels){
employeeModelList = employeeModels;
context1 = context;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem,parent,false);
ViewHolder viewHolder=new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
(ViewHolder)holder).username.setText(employeeModelList.get(position).getName());
}
#Override
public int getItemCount() {
return employeeModelList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView username;
public ViewHolder(#NonNull View itemView) {
super(itemView);
username=itemView.findViewById(R.id.userText);
}
}
}
Try reordering like this.
Remove
mAdapter = new UserAdapter(getContext(), viewModel.getEmployee().getValue());
from initRecycleView
mAdapter = new UserAdapter(getContext(), viewModel.getEmployee().getValue());
viewModel.getEmployee().observe(getViewLifecycleOwner(), new Observer<List<employeeModel>>() {
#Override
public void onChanged(List<employeeModel> employeeModels) {
mAdapter.notifyDataSetChanged();
}
});
initRecycleView();
mAdapter.notifyDataSetChanged();
Above method will work if the list declared inside adapter has any change. So, calling above method without changing adapter's list is useless.
Add a method to UserAdapter class to update list data. Like:
public void updateData(List<employeeModel> updatedList){
employeeModelList.clear();
employeeModelList.addAll(updatedList);
notifyDataSetChanged();
}
And call this method inside observer. Like:
viewModel.getEmployee().observe(getViewLifecycleOwner(), new
Observer<List<employeeModel>>() {
#Override
public void onChanged(List<employeeModel> employeeModels) {
mAdapter.updateData(employeeModels);
}
});
where are you get your network data?
If your get in here -> viewModel.init();
I think it just timing problem.
Just change code sequence
initRecycleView();
viewModel.getEmployee().observe(getViewLifecycleOwner(), new Observer<List<employeeModel>>() {
#Override
public void onChanged(List<employeeModel> employeeModels) {
mAdapter.notifyDataSetChanged();
}
});
viewModel.init();
I've been trying to delete data from firebase with an OnClick RecyclerView method, but nothing works. I can't even make my OnClick method works. I have watched videos and tutorials, I've tried so much stuff and nothing helps...
Here is my adapter class:
public class myadapter extends RecyclerView.Adapter<myadapter.myviewholder>{
ArrayList<datamodel> dataholder;
public myadapter(ArrayList<datamodel> dataholder) {
this.dataholder = dataholder;
}
#NonNull
#Override
public myviewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false);
return new myviewholder(view);
}
#Override
public void onBindViewHolder(#NonNull myviewholder holder, int position) {
Glide.with(holder.itemView.getContext()).load(dataholder.get(position).getImageurl()).into(holder.CircleImg);
holder.header.setText(dataholder.get(position).getHeader());
holder.descr.setText(dataholder.get(position).getDescr());
holder.price.setText(dataholder.get(position).getPrec());
}
#Override
public int getItemCount() {
return dataholder.size();
}
class myviewholder extends RecyclerView.ViewHolder{
CircleImageView CircleImg;
TextView header, descr, price;
public myviewholder(#NonNull View itemView) {
super(itemView);
CircleImg = itemView.findViewById(R.id.circle1);
header = itemView.findViewById(R.id.txtheader1);
descr = itemView.findViewById(R.id.txtdescr1);
price = itemView.findViewById(R.id.txtprecio1);
}
}
And my fragment (the one that have the recyclerView):
public class articulos extends Fragment {
private FirebaseUser firebaseUser;
private String uid;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private DatabaseReference myRef;
private Context mContext;
private myadapter myadapter;
RecyclerView recyclerView;
ArrayList<datamodel> dataholder;
public articulos() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment articulos.
*/
// TODO: Rename and change types and number of parameters
public static articulos newInstance(String param1, String param2) {
articulos fragment = new articulos();
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) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_articulos, container, false);
recyclerView = view.findViewById(R.id.rv);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
myRef = FirebaseDatabase.getInstance().getReference();
dataholder= new ArrayList<>();
getDataFromFirebase();
//datamodel ob1 = new datamodel("Esta nueva", "5000MXN", "wwsad.adasd", "asdasdsa");
// dataholder.add(ob1);
//recyclerView.setAdapter(new myadapter(dataholder));
return view;
}
private void getDataFromFirebase() {
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
uid = firebaseUser.getUid();
Query query = myRef.child("Usuarios").child(uid).child("articulos");
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
ClearAll();
for(DataSnapshot snapshot1 : snapshot.getChildren()){
datamodel datamodel = new datamodel();
datamodel.setImageurl(snapshot1.child("imageurl").getValue(String.class));
datamodel.setDescr(snapshot1.child("descripcion").getValue(String.class));
datamodel.setHeader(snapshot1.child("nombre").getValue(String.class));
datamodel.setPrec(snapshot1.child("precio").getValue(String.class));
dataholder.add(datamodel);
}
myadapter = new myadapter(dataholder);
recyclerView.setAdapter(new myadapter(dataholder));
myadapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
private void ClearAll(){
if(dataholder != null){
dataholder.clear();
if(myadapter != null){
myadapter.notifyDataSetChanged();
}
}
dataholder = new ArrayList<>();
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button mbtnNuevoArticulo = view.findViewById(R.id.btnNuevoArticulo);
mbtnNuevoArticulo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Navigation.findNavController(v).navigate(R.id.agregarart);
}
});
}
If anyone can tell me what to do and how to do it, please.. I need it so bad
Try set onclicklistener on viewholder class
class myviewholder extends RecyclerView.ViewHolder implements View.OnClickListener {
CircleImageView CircleImg;
TextView header, descr, price;
public myviewholder(#NonNull View itemView) {
super(itemView);
CircleImg = itemView.findViewById(R.id.circle1);
header = itemView.findViewById(R.id.txtheader1);
descr = itemView.findViewById(R.id.txtdescr1);
price = itemView.findViewById(R.id.txtprecio1);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
//do something when clicked
}
}
You can apply onclick listener by using following code :
holder.header.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do something.
}
});
add this code in your onBindViewHolder of Adapter. Just make sure to change the id of holder.
full code :
#Override
public void onBindViewHolder(#NonNull myviewholder holder, int position) {
Glide.with(holder.itemView.getContext()).load(dataholder.get(position).getImageurl()).into(holder.CircleImg);
holder.header.setText(dataholder.get(position).getHeader());
holder.descr.setText(dataholder.get(position).getDescr());
holder.price.setText(dataholder.get(position).getPrec());
holder.header.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do something.
}
});
}
Create object of view inside your view holder and also initialize button.setOnClickListener(this) inside viewHolder itself and setting on click inside onBinfViewHolder(...)(only in JAVA). In kotlin you just need to set on click method inside onBindViewHolder(...).
Example:
class YourAdapter():RecyclerView.Adapter<YourAdapter.YourViewHolder>() {
class YourViewHolder(view: View):RecyclerView.ViewHolder(view){
val yourButton:Button = view.findViewById(R.id.landingViewBtn)
}
override fun onBindViewHolder(holder: YourViewHolder, position: Int) {
holder.yourButton.setOnClickListener {
//do Something
val intent = Intent(context,nextActivity::class.java)
context.startActivity(intent)
}
}
}
i'm facing an issue i can't seem to resolve and i'd like some help.
My app is composed by an activity containing a fragment. After the user taps on a suggestion, activity's method onSuggestionClicked(String cardId) is called and activity's content is replaced with a new PagerFragment_new.
#Override
public void onSuggestionClicked(String cardId) {
Log.d("activity","ID:\t" + cardId);
PagerFragment_new pagerFragment = PagerFragment_new.getInstance(
Injection.provideMtgDatabase(getApplicationContext()),
activityPresenter.getAllCardExpansionIds(cardId),
this);
ActivityUtils.replaceFragment(getSupportFragmentManager(), pagerFragment, R.id.MTGRecallActivity_container);
}
PagerFragment_new contains a ViewPager to display CardInfoFragment_new
public class PagerFragment_new extends MtgRecallFragment_new implements PagerFragmentContract.View {
private View fragmentView;
private ViewPager viewPager;
private PagerFragmentContract.Presenter presenter;
private ScreenSlidePageAdapter_new adapter;
private MtgDatabase database;
private String[] printingsIds;
private ScreenSlidePageAdapter_new.ActivePresenterListener listener;
public PagerFragment_new() {
//Required empty constructor
}
public static PagerFragment_new getInstance(MtgDatabase database, String[] printingsIds, ScreenSlidePageAdapter_new.ActivePresenterListener listener) {
PagerFragment_new instance = new PagerFragment_new();
instance.setDatabase(database);
instance.setPrintingsIds(printingsIds);
instance.listener = listener;
return instance;
}
//other stuff
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
setRetainInstance(true);
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
setHasOptionsMenu(true);
fragmentView = inflater.inflate(R.layout.fragment_pager, container, false);
viewPager = (ViewPager) fragmentView.findViewById(R.id.PAGERFRAG_VIEWPAGER);
adapter = new ScreenSlidePageAdapter_new(getChildFragmentManager(), printingsIds, database, viewPager);
adapter.setListener(listener);
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(1);
return fragmentView;
}
#Override
public void setPresenter(PagerFragmentContract.Presenter presenter) {
this.presenter = presenter;
}
}
The adapter to manage ViewPager's element's is ScreenSlidePageAdapter_new, it is responsible of instantiating CardInfoFragments.
public class ScreenSlidePageAdapter_new extends FragmentStatePagerAdapter {
private String[] printingsIds;
private String firstItemId;
private MtgDatabase database;
public ActivePresenterListener activity;
private ViewPager viewPager;
public ScreenSlidePageAdapter_new(FragmentManager fm, String[] printingsIds, MtgDatabase database, ViewPager viewPager) {
super(fm);
this.printingsIds =printingsIds;
this.database = database;
this.firstItemId = printingsIds[0];
this.viewPager = viewPager;
}
#Override
public Fragment getItem(int position) {
//todo create a bundle with cardId
Bundle bundle = new Bundle();
bundle.putString("CardID", printingsIds[position]);
bundle.putString("FirstItemId", firstItemId);
CardInfoFragment_new cardInfoFragment_new = CardInfoFragment_new.getInstance(viewPager);
cardInfoFragment_new.setArguments(bundle);
CardInfoPresenter cardInfoPresenter = new CardInfoPresenter(cardInfoFragment_new, database);
activity.setActivePresenter(cardInfoPresenter);
return cardInfoFragment_new;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
public void setListener(ActivePresenterListener listener) {
this.activity = listener;
}
#Override
public int getCount() {
return printingsIds.length;
}
public interface ActivePresenterListener {
void setActivePresenter(BasePresenter presenter);
}}
Finally, here's the code of CardInfoFragment:
public class CardInfoFragment_new extends MtgRecallFragment_new
implements CardInfoContract.View,
CardPrintingsAdapter.OnItemClickListener {
private ViewPager viewPager;
public CardInfoContract.Presenter presenter;
private View fragmentView;
private MTGCard mtgCard;
RecyclerView printingsRecyclerView;
CardPrintingsAdapter cardPrintingsAdapter;
private String firstItemId; //the first id
public CardInfoFragment_new() {
//required empty constructor
}
private void setViewPager(ViewPager viewPager) {
this.viewPager = viewPager;
}
public static CardInfoFragment_new getInstance(ViewPager viewPager) {
CardInfoFragment_new cardInfoFragment_new = new CardInfoFragment_new();
cardInfoFragment_new.setViewPager(viewPager);
return cardInfoFragment_new;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
setRetainInstance(true);
presenter.start();
String cardId = getArguments().getString("CardID");
firstItemId = getArguments().getString("FirstItemId");
mtgCard = presenter.getCardData(cardId);
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
fragmentView = inflater.inflate(R.layout.fragment_card_info_new, container, false);
setUpCardInfoView(fragmentView);
return fragmentView;
}
public void setUpCardInfoView(final View view){
//others view set-up action omitted
cardprintingsContainer = (LinearLayout) view.findViewById(R.id.CARDINFO_printingsContainer);
printingsRecyclerView = (RecyclerView)fragmentView.findViewById(R.id.CARDINFO_printings_recyclerView);
final List<String> printings = presenter.getCardPrintings(firstItemId, mtgCard.getName());
if (printings.size() < 40) {
setupPrintings(printings,printingsRecyclerView);
}
else {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout printingsRow = new LinearLayout(getContext());
printingsRow = (LinearLayout)inflater.inflate(R.layout.card_info_printings_row,printingsRow,true);
printingsRow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setupPrintings(printings, printingsRecyclerView);
}
});
ImageView printingssetImage = (ImageView)printingsRow.findViewById(R.id.CARDINFO_printingsRow_setImage);
printingssetImage.setVisibility(View.INVISIBLE);
TextView printingssetName = (TextView)printingsRow.findViewById(R.id.CARDINFO_printingsRow_setName);
printingssetName.setText("Click to see all the "+printings.size()+ " versions");
cardprintingsContainer.addView(printingsRow);
}
}
public void setupPrintings(List<String> printings, RecyclerView recyclerView) {
cardPrintingsAdapter =
new CardPrintingsAdapter(getContext(), printings);
cardPrintingsAdapter.setOnItemClickListener(this);
UnscrollableLayoutManager layoutManager = new UnscrollableLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
recyclerView.setAdapter(cardPrintingsAdapter);
recyclerView.setLayoutManager(layoutManager);
}
#Override
public void onItemClick(View itemView, int position) {
int i = viewPager.getAdapter().getCount();
viewPager.setCurrentItem(position);
}
#Override
public void onDestroy() {
presenter = null;
mtgCard = null;
super.onDestroy();
}}
When user click on a RecyclerView item, CardInfoFragment's method onItemClick(View itemView, int position) is called and the viewpager is set to current position. Everything as expected.
THE PROBLEM
When the orientation changes, fragments are able to retain their states, but viewPager.setCurrentItem(position) does nothing, and i'm not able to change displayed fragment.
I already checked:
ViewPager instance and adapters instances corresponds to those passed to Fragments
onItemClick is fired
this questions question1 question2
If i use
android:configChanges="orientation|screenSize"
in manifest it works even after config changes, but i don't want to use this option since is discouraged.
Thanks in advance!
By default, when certain key configuration changes happen on Android (a common example is an orientation change), Android fully restarts the running Activity to help it adjust to such changes.
When you define android:configChanges="keyboardHidden|orientation" in your AndroidManifest, you are telling Android: "Please don't do the default reset when the keyboard is pulled out, or the phone is rotated; I want to handle this myself. Yes, I know what I'm doing".
So use configChanges.
The use of this is discouraged, IF you don't know how to use it. But for a case like this, I would suggest you use it. IF not, still the activity will be recreated. which just takes time, resources, and I don't see why you would want that to happen.