RecyclerView not working with fragment - android

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);
}

Related

RecyclerView is a null in fragment

I have MainActivity,which contain viewpager,which contain 2 fragments:
MainActivity
ViewPager viewPager = findViewById(R.id.viewPager);
MyPagerAdapter adapter = new MyPagerAdapter(this,
getSupportFragmentManager());
viewPager.setAdapter(adapter);
TabLayout tabLayout = findViewById(R.id.TabLayout);
tabLayout.setupWithViewPager(viewPager);
Fragment fragmentHour=adapter.getItem(1);
onChangeDayListener2= (OnChangeDayListener) fragmentHour;
I am also have interface for send data from main activity in fragment:
public interface OnChangeDayListener{
void OnChange(WeatherList list,int pos);
}
but when i try to work with this callback in interface my recycler adapter always is null:
HourWeatherFragment:
public class HourWeatherFragment extends Fragment implements MainScreen.OnChangeDayListener{
private RecyclerView recyclerView;
private AdapterHour adapter;
private ArrayList<Weather> days;
Context context;
static HttpClient httpClient;
public HourWeatherFragment() {
// Required empty public constructor
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
days=new ArrayList<>();
adapter = new AdapterHour(days,getActivity());
LinearLayoutManager LayoutManager = new LinearLayoutManager(getActivity().getBaseContext(),
LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(LayoutManager);
recyclerView.setAdapter(adapter);
days.add(new Weather());
recyclerView.getAdapter().notifyDataSetChanged();
Log.d("recycler","adapter seted!");
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_hour_weather, container, false);
recyclerView = rootView.findViewById(R.id.hour_list);
httpClient=new HttpClient();
MyAsyncTask task=new MyAsyncTask();
// task.execute("lviv");
return rootView;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context=context;
}
#Override
public void OnChange(WeatherList list,int pos) {
String date=list.getAverageWeather().get(pos).getDate();
ArrayList<Weather> weather=list.getByDate(date);
Log.d("ldata","size of weather for adding="+weather.size());
// days.add(new Weather());
if(adapter!=null){
adapter.notifyDataSetChanged();
Log.d("tag","first null!");}
else{
try{
recyclerView.getAdapter();}
catch (NullPointerException ex){
Log.d("tag","null!");//THERE ALWAYS NULL
}}
So,firstly creating activity,then i start load data and when data loaded i send data from MainActivity to HourWeatherFragment throught callback,
but when i receive data in fragment,my adapter is null,how i can fix it?
You can create a static singleton class to hold data and retrieve that data in the fragment.
public class DataHolder {
//create static variables here.
}
In your fragment simply retrieve the data and make it null after that.
Alternative solution
Another solution is to use Bundles. Follow the bundle solution here.
You must cast RecyclerView.
in your fragment and onCreateView method :
recyclerView = (RecyclerView) rootView.findViewById(R.id.hour_list);
I know this is an old question, but contrary to the accepted answer I think the issue is that the handle to the fragment's widget such as recyclerView is not available in the OnCreateView function.
The handles (or pointers if you wish) to the widgets are only guaranteed to exist in the OnViewCreated function.
This documentation has good description of the lifecycle of fragments:
https://guides.codepath.com/android/Creating-and-Using-Fragments
an extract is:
// This event is triggered soon after onCreateView().
// onViewCreated() is only called if the view returned from onCreateView() is non-null.
// Any view setup should occur here. E.g., view lookups and attaching view listeners.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ListView lv = (ListView) view.findViewById(R.id.lvSome);
lv.setAdapter(adapter);
}
Hope this helps.

application null object reference

Previous Question:
May I know why this error will occur when I try to start RecyclerView activity doing a search from fragment.
After added adapter:
error: OwnerDAO.getOwner()' on a null object reference
Fragment code:
RecyclerView recyclerView;
RecyclerView.LayoutManager layoutManager;
SearchAdapter adapter;
OwnerDAO mOwnerDao;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.activity_search, container, false);
recyclerView = (RecyclerView)v.findViewById(R.id.recycler_search);
layoutManager = new LinearLayoutManager(this.getActivity());
mOwnerDao = new OwnerDAO(getContext())
adapter = new SearchAdapter(getContext(),mOwnerDao.getOwner());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter( adapter );
return v;
}
Search Adapter:
public SearchAdapter(Context context, List<Owner> owners) {
this.context = context;
this.owners = owners;
}
Set the layoutManager after setAdapter like this :-
recyclerView.setAdapter( adapter );
recyclerView.setLayoutManager(layoutManager);
The error will be removed !!

avoid fragment list data duplicating on recyclerView

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.

Call a function defined in a fragment, from the main activity that required a view

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)

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

Categories

Resources