I have to create a list inside one of my Fragments but I cannot make recyclerview work, I was searching the internet whole day followed tutorials but could not figure out why its not working
row_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/list"
android:name="com.streak.roadpoliceviolations.ViolationFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context="com.streak.roadpoliceviolations.ViolationFragment"
tools:listitem="#layout/fragment_violation" />
Adapter:
public class ViolationAdapter extends RecyclerView.Adapter<ViolationAdapter.MyViewHolder>{
private LayoutInflater inflater;
List<ViolationItem> data= Collections.emptyList();
public ViolationAdapter(List<ViolationItem> data) {
//inflater = LayoutInflater.from(context);
this.data = data;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.fragment_violation, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
ViolationItem current = data.get(position);
holder.txt1.setText(current.txt1);
holder.txt2.setText(current.txt2);
}
#Override
public int getItemCount() {
return 0;
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView txt1;
TextView txt2;
public MyViewHolder(View itemView) {
super(itemView);
txt1= (TextView) itemView.findViewById(R.id.txt1);
txt2= (TextView) itemView.findViewById(R.id.txt2);
}
}
}
Fragment class
public class ViolationFragment extends Fragment {
private ViolationAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_violation_list, container, false);
RecyclerView rv = (RecyclerView) view.findViewById(R.id.list);
adapter = new ViolationAdapter(getActivity(),getData());
rv.setAdapter(adapter);
rv.setLayoutManager(new LinearLayoutManager(getActivity()));
return view;
}
public static List<ViolationItem> getData() {
List<ViolationItem> data = new ArrayList<>();
String[] txts1 = {"AAA","BBB","CCC"};
String[] txts2 = {"111","222","333"};
for(int i=0; i<=txts1.length; i++) {
ViolationItem c = new ViolationItem();
c.txt1=txts1[i];
c.txt2=txts2[i];
data.add(c);
}
return data;
}
private List<ViolationItem> createList() {
List<ViolationItem> data = new ArrayList<>();
return data;
}
}
Everything passes without a single warning BUT I cannot place this into the fragment container
In mine activity I'm calling the fragment with the following code
//Initial fragment
ViolationFragment frag = new ViolationFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction() .replace(R.id.frame_container, frag).commit();
Getting this error during the build
Error:(77, 75) error: incompatible types: ViolationFragment cannot be converted to Fragment
And if i change frag initialization Fragment frag = new ViolationFragment();
I get the same error.
How to finally fix this and make the fragment work?!
As I remember you must use support library fragment to make it work. Please check and confirm.
Related
I have added an adapter to my recycler view, the adapter contains the data plist which is an ArrayList populated with firebase data.
I have done this in the onCreateView method in my Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_buy, container, false);
recyler = rootView.findViewById(R.id.recycler);
recyler.setHasFixedSize(true);
reference = FirebaseDatabase.getInstance().getReference("Produce");
plist = new ArrayList<>();
adapter = new Produce_RecyclerViewAdapter(rootView.getContext(), plist);
recyler.setAdapter(adapter);
final int count = 0;
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot ds : snapshot.getChildren()) {
Produce produce = ds.getValue(Produce.class);
plist.add(produce);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Display();
}
});
return inflater.inflate(R.layout.fragment_buy, container, false);
As far as I can tell there are no errors with my Recycler adapter:
public class Produce_RecyclerViewAdapter extends RecyclerView.Adapter<Produce_RecyclerViewAdapter.ViewHolder>{
private final List<Produce> produce_item;
private final Context context;
public Produce_RecyclerViewAdapter(Context context, ArrayList<Produce> produce_item) {
this.produce_item = produce_item;
this.context = context;
}
#NonNull
#NotNull
#Override
public ViewHolder onCreateViewHolder(#NonNull #NotNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.produce_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull #NotNull ViewHolder holder, int position) {
Produce produce = produce_item.get(position);
holder.ptitle.setText(produce.getPname());
holder.pprice.setText(produce.getPprice());
Picasso.with(context)
.load(produce.getPimg())
.placeholder(R.mipmap.ic_launcher)
.fit()
.centerCrop()
.into(holder.pimage);
}
#Override
public int getItemCount() {
return produce_item.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView pimage;
TextView ptitle, pprice;
CardView view, addtocart;
public ViewHolder(#NonNull #NotNull View itemView) {
super(itemView);
pimage = itemView.findViewById(R.id.pimage);
ptitle = itemView.findViewById(R.id.ptitle);
pprice = itemView.findViewById(R.id.pprice);
view = itemView.findViewById(R.id.view);
addtocart = itemView.findViewById(R.id.addtocart);
}
}
}
I added the linear layout manager directly to the recycler view:
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
and here is the firebase data:
firebase data
Edit: I checked out recyclerview No adapter attached; skipping layout
and quite a few other answers relating to the problem but either I have already done what they suggested or they are referring to recycler view in an activity and not in a fragment.
The No adapter attached; skipping layout is harmless and overall can be ignored.
Your problem is that you are inflating the view two times. You inflate first and setup everything, throw that way. Inflate it second time and return it without any setup.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_buy, container, false);
/*
* All of the setup
*/
//return inflater.inflate(R.layout.fragment_buy, container, false);
return rootView;
}
I have a fragment running that has part of its layout view load a RecyclerView Card. From within this card I want to launch a new fragment that opens a full screen layout.
public class MemoriesFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MemListFragment fragment = new MemListFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.placeholder, fragment);
fragmentTransaction.commit();
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_authoring_memory_menu_1, container, false);
return view;
}}
That's the main fragment. The next one is the fragment that creates and populates the RecyclerView
public class MemListFragment extends Fragment {
ImageButton button1;
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_authoring_memory_list, container,false);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.listRecyclerView);
ListAdapter listAdapter = new ListAdapter();
recyclerView.setAdapter(listAdapter);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
button1 = view.findViewById(R.id.memory_image);
return view;
}}
This is the RecyclerView
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
private LayoutInflater layoutInflater;
private List<String> data;
public ImageButton memory_image;
public Adapter(MemoriesFragment Context, List<String> data){
// this.layoutInflater = LayoutInflater.from();
this.data = data;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = layoutInflater.inflate(R.layout.memory_view,viewGroup,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
// bind the textview with data received
String title = data.get(i);
viewHolder.textTitle.setText(title);
// similarly you can set new image for each card and descriptions
viewHolder.memoryButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
AppCompatActivity activity = (AppCompatActivity) view.getContext();
Fragment MemoryDetails = new MemoryDetails();
activity.getSupportFragmentManager().beginTransaction().replace(R.id.placeholder, MemoryDetails).addToBackStack(null).commit();
}
});
}
#Override
public int getItemCount() {
return data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
// Define UI components here
TextView textTitle;
ImageButton memoryButton;
public ViewHolder(#NonNull View itemView) {
super(itemView);
textTitle = itemView.findViewById(R.id.textTitle);
memoryButton = itemView.findViewById(R.id.memory_image);
}
}
}
The recylerview is created with memory_view.xml which just has text and an imagebutton named memory_image. When I run this code it crashes when I click the Image Button.
Edit: added error log below
2020-02-21 16:50:29.334 19558-19558/com.app.emotivo E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app.emotivo, PID: 19558
java.lang.IllegalStateException: Could not find method onClick(View) in a parent or ancestor Context for android:onClick attribute defined on view class androidx.appcompat.widget.AppCompatImageButton with id 'memory_image'
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.resolveMethod(AppCompatViewInflater.java:434)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:391)
at android.view.View.performClick(View.java:6256)
at android.view.View$PerformClick.run(View.java:24701)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
i am not sure if it works but can you try using supportfragmentmanager in the memories fragment too , and cast your the the result of itemView.findViewById(R.id.memory_image)to an ImageButton like that (ImageButton)itemView.findViewById(R.id.memory_image)
the display of the fragment inside the adapter is not a good thing.
I think first of all use the navigation on Android Jetpack
Or use RxJava and transfer the formatting representation from adapter to fragment.
I have created a viewpager with tabslayout.Each view of viewpager consists of recyclerview inside fragment.The issue i am having is that when i swipe through the views it stucks while swiping in such a manner that there is no change in view and i have to swipe multiple times in order to change view.It looks that swipe event is not detected by viewpager.However if i comment out below two lines which includes setting adapter then i don't experience such issue and swipe is smooth and fast.
PlanListAdapter mAdapter = new PlanListAdapter(browsePlanModelList, getActivity());
rvBrowsePlanList.setAdapter(mAdapter);
Where am i going wrong and how can i resolve this?
Below is code of fragment and adapter-
public class FullTimeFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_browse_plan_list, container, false);
ArrayList<BrowsePlanModel> browsePlanModelList = (ArrayList<BrowsePlanModel>) getArguments().getSerializable(AppConstant.BROWSEPLANlIST);
RecyclerView rvBrowsePlanList = (RecyclerView) view.findViewById(R.id.rvBrowsePlanList);
//rvBrowsePlanList.addItemDecoration(new SimpleDividerIncludingLastItemDecoration(getResources()));
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
rvBrowsePlanList.setLayoutManager(mLayoutManager);
rvBrowsePlanList.setItemAnimator(new DefaultItemAnimator());
if(browsePlanModelList!=null)
{
BrowsePlanListAdapter mAdapter = new BrowsePlanListAdapter(browsePlanModelList, getActivity());
rvBrowsePlanList.setAdapter(mAdapter);
}
return view;
}
}
Adapter
public class PlanListAdapter extends RecyclerView.Adapter<PlanListAdapter.MyViewHolder> {
private List<BrowsePlanModel> planList;
Context mContext;
public PlanListAdapter(List<BrowsePlanModel> planList, Context mContext) {
this.mContext = mContext;
this.planList = planList;
}
#Override
public PlanListAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.sffs_item, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(PlanListAdapter.MyViewHolder holder, int position) {
holder.xyz.setText(planList.get(position).getxyx());
holder.abc.setText(planList.get(position).getabc());
}
#Override
public int getItemCount() {
return planList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView xyz, abc;
public MyViewHolder(View itemView) {
super(itemView);
xyz = (TextView) itemView.findViewById(R.id.xyz);
abc = (TextView) itemView.findViewById(R.id.abc);
}
}
}
Use
myViewPager.setOffscreenPageLimit(number of pages in your viewpager minus 1);
If you do not do this, the pages which are not currently visible will be destroyed and will be recreated every time you swipe. This will lead to huge lag if each of those pages is populating a RecyclerView from a database, etc.
It may be happening because of high resolution image. If you use high resolution images then the viewPager will stuck while swiping . Try using low resolution images.
I am trying to use recyclerView which is inside a fragment.This is fragment is nested inside the viewPager.
public class UniversityDetail extends Fragment {
RecyclerView universityDetailView;
//need to set Adapter
public static UniversityDetail newInstance(){
return new UniversityDetail();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment_university_lsit,container,false);
universityDetailView = (RecyclerView)view;
setupViews();
return view;
}
private void setupViews(){
//set the adapter
UniversityDetailAdapter detailAdapter = new UniversityDetailAdapter(new ArrayList<UniversityDetails>());
universityDetailView.addItemDecoration(new RecyclerListDecorater(getActivity()));
universityDetailView.setAdapter(detailAdapter);
universityDetailView.setLayoutManager(new LinearLayoutManager(getActivity()));
universityDetailView.setHasFixedSize(false);
}
public RecyclerView getRecyclerView(){
return this.universityDetailView;
}
}
This is the fragment which i want to be inside the viewPager.It returns a recyclerView from onCreateView.
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/scroll"
android:paddingBottom="8dp"
android:paddingTop="?attr/actionBarSize"
android:scrollbars="vertical">
fragment_university_lsit.xml
recyclerView uses below adapter.
public class UniversityDetailAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<UniversityDetails> universityDetails;
private static Map<String,String> admissionRecommendation;
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((DetailHolder)holder).bind(universityDetails.get(position));
}
#Override
public int getItemCount() {
return universityDetails.size();
}
public UniversityDetailAdapter(List<UniversityDetails> details){
this.universityDetails = details;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
Log.d("CreateUniveristyDetail", "onCreateViewHolder: detail called");
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.detail_fragment,parent,false);
return new DetailHolder(itemView);
}
}
DetailHolder is the class extends ReyclerView.ViewHolder and its implementation is irrelevant here.
The adapter list is upated from handler and notifyDataSetChanged()
private void setup(){
mHandler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message message){
if(message.what == ConnectionHandler.DETAILMSG){
Log.d("detail handle message", "handleMessage: Called");
List<UniversityDetails> details = (List<UniversityDetails>)message.obj;
UniversityDetailAdapter adapter = (UniversityDetailAdapter)universityDetail.getRecyclerView().getAdapter();
adapter.addAll(details);
adapter.notifyDataSetChanged();
Log.d("size", "handleMessage: " + adapter.getItemCount());
}
}
};
}
Fragment is created in activity..
private void setupNavigation(){
ViewPagerAdapter pagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
universityDetail = UniversityDetail.newInstance();
pagerAdapter.addFragment(universityDetail);
mViewPager.setAdapter(pagerAdapter);
//setup the fragment transaction.
headerTab.setViewPager(mViewPager,0);
//no need to add to back stack
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.view_pager,universityDetail);
transaction.commit();
}
Implementation of DetailHolder
public class DetailHolder extends RecyclerView.ViewHolder{
CardView admissionGeneral;
public View root;
public DetailHolder (View itemView){
super(itemView);
root = itemView;
admissionGeneral = (CardView)root.findViewById(R.id.admission_general);
}
public void bind(UniversityDetails detail){
Log.d("detail bind", "bind: binding to recyclerView");
}
}
here the log of adapter.getItemCount(); return 3; thats means something is being added and onCreateViewHolder is supposed to be called but it never is.
The weird thing is i have implemented another recyclerAdapter is the sameProject and its working perfectly fine.
This problem would be easier to answer if you could show how the universityDetail was assigned from whatever class contains the Handler usage.
It's also not clear how message.obj is able to be cast to a List.
I believe you are using a different instance of the Fragment there than the one that you want to update.
So, you know this line is good
List<UniversityDetails> details = (List<UniversityDetails>)message.obj;
because you see 3 in the output when you do this
Log.d("size", "handleMessage: " + adapter.getItemCount());
Now, these lines could likely be the problem.
UniversityDetailAdapter adapter = (UniversityDetailAdapter)universityDetail.getRecyclerView().getAdapter();
adapter.addAll(details);
adapter.notifyDataSetChanged();
Firstly, there is no addAll method to RecyclerView.Adapter. So I'm not sure how that compiled. Anyways...
Try to keep cross-class references to a minimum. Here, we expose only the method to add the details rather than the entire RecyclerView.
Then, for RecyclerViews, you should notify only the data that was inserted rather than all of it using notifyItemRangeInserted
public class UniversityDetailFragment extends Fragment {
private RecyclerView universityDetailView;
private UniversityDetailAdapter detailAdapter;
private List<UniversityDetails> details = new ArrayList<UniversityDetails>();
...
public void setupViews() {
detailAdapter = new UniversityDetailAdapter(details);
// etc...
}
public void addDetails(List<UniversityDetails> details) {
int curSize = detailAdapter.getItemCount();
this.details.addAll(details);
detailAdapter.notifyItemRangeInserted(curSize, details.size());
}
}
And then just use the instance of your Fragment
if(message.what == ConnectionHandler.DETAILMSG){
Log.d("detail handle message", "handleMessage: Called");
List<UniversityDetails> details = (List<UniversityDetails>) message.obj;
universityDetail.addDetails(details);
Another recommendation would be to use the correct generic type for the holder class to avoid unnecessary casts.
public class UniversityDetailAdapter extends RecyclerView.Adapter<DetailHolder>
I have three tabs.For testing purposes,I am setting the same fragment to all the three tabs.Fragment has a recycler view. I am able to view the recycler view only in first fragment.
Activity Code:
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new TrialsFragment(), getString(R.string.camps));
adapter.addFragment(new TrialsFragment(), getString(R.string.trials));
adapter.addFragment(new TrialsFragment(), getString(R.string.events));
viewPager.setAdapter(adapter);
Fragment Code:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
recyclerView = (RecyclerView) getActivity().findViewById(R.id.recycler);
adapter = new TrialsRecyclerViewAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(adapter);
}
Adapter code:
public class TrialsRecyclerViewAdapter extends RecyclerView.Adapter<TrialsRecyclerViewAdapter.ViewHolder> {
String[] names = {"Sample Name","Sample Name","Sample Name","Sample Name","Sample Name"};
String[] regNos ={"12345678","12345678","12345678","12345678","12345678"};
#Override
public TrialsRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
CardView cv = (CardView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.trial_card, parent, false);
return new ViewHolder(cv);
}
#Override
public void onBindViewHolder(TrialsRecyclerViewAdapter.ViewHolder holder, int position) {
final CardView cardView = holder.cardView;
TextView name = (TextView)cardView.findViewById(R.id.trial_name);
TextView regNumber = (TextView)cardView.findViewById(R.id.trial_start_end);
name.setText(names[position]);
regNumber.setText(regNos[position]);
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
#Override
public int getItemCount() {
return names.length;
}
public static class ViewHolder extends RecyclerView.ViewHolder
{
private CardView cardView;
public ViewHolder(CardView v)
{
super(v);
cardView = v;
}
}
}
When the activity is started, RecyclerView is visible in first tab only. If I swipe the tabs, then it becomes visible in second tab only.
I observed the following error while debugging it:
No adapter attached; skipping layout
recyclerView = (RecyclerView) getActivity().findViewById(R.id.recycler);
This is very wrong. Move your logic from onActivityCreated() into onViewCreated(), and get the fragment's own RecyclerView. Each fragment should be creating its own RecyclerView in onCreateView(), which will be the contents of that page of the ViewPager.