I m have a problem with my RecyclerView. I m trying to populate it with a list of friends names, however when i launch my fragment friends are not loaded. On the other side friends are loaded if i m entering debug mode.
My code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mKinveyClient = KinveyUtils.getClient(getContext());
mFriends = getUserFriends();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_friend_list, container, false);
// Set the adapter
if (view instanceof RecyclerView) {
Context context = view.getContext();
mRecyclerView = (RecyclerView) view;
mRecyclerView.setLayoutManager(new LinearLayoutManager(context));
mRecyclerView.setAdapter(new FriendRecyclerViewAdapter(mFriends));
}
return view;
}
private ArrayList<ArrayMap> getUserFriends() {
return (ArrayList<ArrayMap>) mKinveyClient.user().get(KinveyConstants.FRIENDS);
}
I feel like the friends are loading too slow, but all the needed data should be already in app by this time. Any idea how to fix it?
Related
I try to create a HORIZONTAL recyclerView but recyclerView can't find the context here is my Fragmnet code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.context =context;
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
ArrayList<CategoryModel> categoryModels = null;
RecyclerView recyclerView = container.findViewById(R.id.category_recycler);
// recyclerView.setHasFixedSize(true);
CategoryAdapter adapter = new CategoryAdapter(context,CategoryData.getCategory());
recyclerView.setAdapter(adapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
return inflater.inflate(R.layout.main_fragment, container, false);
}
and here is Recycler view adapter code:
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.ViewHolder> {
Context context;
ArrayList<CategoryModel> categorys;
public CategoryAdapter(Context context, ArrayList<CategoryModel> categoryModels) {
this.categorys = categoryModels;
this.context = context;
}
#NonNull
#Override
public CategoryAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.product_category,parent,false);
return new ViewHolder(view);
}
i'm also attached the Debug result please check the image
Try like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
// Defines the xml file for the fragment
return inflater.inflate(R.layout.main_fragment, parent, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// Inflate the layout for this fragment
ArrayList<CategoryModel> categoryModels = null;
RecyclerView recyclerView = view.findViewById(R.id.category_recycler);
// recyclerView.setHasFixedSize(true);
CategoryAdapter adapter = new CategoryAdapter(getContext(), CategoryData.getCategory());
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
To use Context inside Fragment use getContext() method .
CategoryAdapter adapter = new CategoryAdapter(getContext(),CategoryData.getCategory());
From official doc
Return the Context this fragment is currently associated with.
If you are using Context only for inflating view inside onCreateViewHolder method in CategoryAdapter class then you don't need to pass Context in Constructor. You can get Context from ViewGroup which is first parameter of the onCreateViewHolder method.
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_category,parent,false);
In your onCreate() fragment callback I see this line:
public void onCreate(Bundle savedInstanceState) {
...
this.context =context;
...
}
This line doesn't do anything; there's no context argument to the onCreate() method or anything like that, so you're just assigning a variable back to itself. Since your Context context field doesn't have an explicit intialization, the default is null. So this is the same as writing
public void onCreate(Bundle savedInstanceState) {
...
this.context = null;
...
}
Later on, in onCreateView(), you're instantiating your adapter with this line:
CategoryAdapter adapter = new CategoryAdapter(context,CategoryData.getCategory());
Because of what I said above, this is functionally the same as
CategoryAdapter adapter = new CategoryAdapter(null, CategoryData.getCategory());
To solve this, you need some place to get a Context instance from. Fragments are often "attached" to a context, and, when they're attached, you can get that context by calling getContext(). A fragment is guaranteed to be attached to a context in the onActivityCreated() callback, so you will want to move your adapter creation to that callback instead of onViewCreated().
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.main_fragment, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
CategoryAdapter adapter = new CategoryAdapter(getContext(), CategoryData.getCategory());
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
RecyclerView recyclerView = getView().findViewById(R.id.category_recycler);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(layoutManager);
}
I want to display my data inside a fragment but it seems like some methods are not applicable in fragments only in Activity. The text with * are causing me errors. How i can execute it on a fragment?
String urlAddress = "http://capstonproject.xyz/project/tourist/retrieve/adventure";
RecyclerView recyclerView;
public Fadventure() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
//RecyclerView recyclerView = (RecyclerView) inflater.inflate(R.layout.fragment_fadventure, container, false);
return inflater.inflate(R.layout.fragment_fadventure, container, false);
recyclerView = view.findViewById(R.id.adventure_list);
recyclerView.setLayoutManager(new LinearLayoutManager(***this***));
recyclerView.setItemAnimator(new DefaultItemAnimator());
new DBFetch(***Fadventure.this***,recyclerView).execute();
//return recyclerView;
}
instead of this try with getActivity().getApplication().
hope it helps.
I had some fragments switch on one activity.
I found a issue is that when i turn back the fragment , it will show duplicate data.
I try to clear the arrayList data to solve it.
But i want to know more smart way.
Is any possible to avoid this issue for duplicate data ?
My fragment code:
public class Vaccine extends Fragment {
private List<VaccineItem> vaccineList = new ArrayList<>();
private VaccineAdapter vaccineAdapter;
private RecyclerView recyclerVaccine;
public Vaccine() {
}
public static Vaccine newInstance() {
return new Vaccine();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.vaccine_fragment_, container, false);
recyclerVaccine = (RecyclerView) view.findViewById(R.id.recyclerVaccine);
recyclerVaccine.setLayoutManager(new LinearLayoutManager(getActivity()));
vaccineList.clear();// i use it to slove the problem.--------------
testData();
vaccineAdapter = new VaccineAdapter(getActivity(), vaccineList);
recyclerVaccine.setAdapter(vaccineAdapter);
vaccineAdapter.notifyDataSetChanged();
return view;
}
private void testData(){
VaccineItem vaccineItem=new VaccineItem("Data1");
vaccineList.add(vaccineItem);
vaccineItem=new VaccineItem("Data2");
vaccineList.add(vaccineItem);
}
}
Try with this
View view; // declare this globally
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(view == null){ // initialize if view is null
view = inflater.inflate(R.layout.vaccine_fragment_, container, false);
recyclerVaccine = (RecyclerView) view.findViewById(R.id.recyclerVaccine);
recyclerVaccine.setLayoutManager(new LinearLayoutManager(getActivity()));
vaccineList.clear();// i use it to slove the problem.--------------
testData();
vaccineAdapter = new VaccineAdapter(getActivity(), vaccineList);
recyclerVaccine.setAdapter(vaccineAdapter);
vaccineAdapter.notifyDataSetChanged();
}
return view;
}
Call testData() in your constructor, not in onCreateView.
The reason you are getting duplicate data is because you are calling testData() when fragment view is created. This adds same items everytime your fragment is recreated. There is nothing wrong with clearing the list though.
I have a function in a fragment (Frag_Lista) that changes its cardView dynamically using the output of a query.
The first time i call it from that fragment and it works. The second time i would call it from the main activity, but i can't set correctly the second parameter, the view.
Frag_Lista
public void function_in_fragment() {
//some code
Context context = getActivity();
DBhelper database = ((MainActivity)getActivity()).getDatabase();
Cursor cursor=database.ottieni_tutto();
genera_lista(cursor,getView());
}
public void genera_lista(Cursor cursor, View v) {
list.clear();
if(cursor!=null) {
if(cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
//Log.d(TAG,cursor.getString(cursor.getColumnIndex(DBhelper.COL_NOME)));
String nome = cursor.getString(cursor.getColumnIndex(DBhelper.COL_NOME));
String tipo = cursor.getString(cursor.getColumnIndex(DBhelper.COL_TIPO));
String difficolta = cursor.getString(cursor.getColumnIndex(DBhelper.COL_DIFFICOLTA));
String immagine = cursor.getString(cursor.getColumnIndex(DBhelper.COL_IMMAGINE));
Food_Card food_card = new Food_Card(immagine, nome, tipo, difficolta);
list.add(food_card);
cursor.moveToNext();
}
cursor.close();
}
else Log.d(TAG,"Cursor vuoto");
}
else Log.d(TAG,"Cursor nullo");
recyclerView = (RecyclerView) v.findViewById(R.id.recyclerView);
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
adapter=new food_adapter(getActivity(),list);
recyclerView.setAdapter(adapter);
}
MainActivity
public void function_in_mainActivity(String[] parametri) {
Cursor cursor=database.query_filtri(parametri);
Frag_Lista nothing=new Frag_Lista();
View v= ?
nothing.genera_lista(cursor,v);
}
How can i pass correctly the current view?
Frag_Lista
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag_lista, container, false);
setHasOptionsMenu(true);
return(v);
}
Change your onCreateView like this
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag_lista, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.recyclerView);
setHasOptionsMenu(true);
return(v);
}
Crate a field inside your Fragment for recyclerView.
Now you always have a reference to the RecyclerView and don't need to pass it as a argument to the method.
public void genera_lista(Cursor cursor)
public class WorkFragment extends Fragment {
List<CardViewItem> items = new ArrayList<>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("FRAGMENT", "Work Fragment started");
TypedArray icons = getResources().obtainTypedArray(R.array.project_icons);
TypedArray names = getResources().obtainTypedArray(R.array.project_names);
TypedArray descs = getResources().obtainTypedArray(R.array.project_descs);
for (int i=0;i<icons.length();i++){
items.add(new CardViewItem(icons.getDrawable(i),
names.getString(i),
descs.getString(i)));
}
icons.recycle();
names.recycle();
descs.recycle();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("FRAGMENT", "Work Fragment onCreateView");
View rootView = inflater.inflate(R.layout.fragment_work, container, false);
RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
LinearLayoutManager llm = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(llm);
recyclerView.setAdapter(new ItemAdapter(items));
return inflater.inflate(R.layout.fragment_work, container, false);
}
}
Gives me
E/RecyclerView: No adapter attached; skipping layout
I have tried out all the solutions I had found (setting an empty adapter, moving the code elswhere, using a seperate thread) but to no avail. This should work on a normal activity so I guess maybe I'm doing something wrong.
the problem is mostly this line
return inflater.inflate(R.layout.fragment_work, container, false);
you should have
return rootView
With the first return you are inflating a new totally different view hierarchy, starting from fragment_work.xml, from the one which has an the RecyclerView correctly set up.