in my Fragment.onCreateView(inflater), I keep a reference to a widge:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_shipping, container, false);
...
mMyBtn = (Button) view.findViewById(R.id.mybtn);
So I can use it later:
#Override
public void onResume() {
super.onResume();
...
mMyBtn.setEnabled(false);
Somehow, I get nullpointer in mMyBtn.setEnabled reported in Firebase Crashlytics occasionally (100% Android 8 devices).
Question: did I do it wrong in the wrong lifecycle callback? i.e., instead of keep the widget reference in onCreateView(...), should I do it in onViewCreated(...)? I have been doing this way forever wondering if I am out of dated ...
Any suggestion, to make my code more defensive?
Related
How are these methods different from each other when trying to get the view?
First:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a, container, false);
listView = view.findViewById(R.id.listview);
return view;
}
Second:
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView = getActivity().findViewById(R.id.listview); }
* some say this is used to get activity views but i used it for getting fragment views(which didn't existed in the activity) and it worked fine.
Third:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
listView = getView().findViewById(R.id.listview);
}
Three methods are good. In the onCreateView you create the view (!), it's the really first time you can use what you inflated. Then onViewCreated is called with the view you returned in the onCreateView, You can directly use the view given as parameter, it is the same the getView() provides. My advice is to initialise your UI variables here
For onActivityCreated, it is the best place to modify your UI elements. It is called when fragment creation is complete and when fragment is re-attached. There you can use the variables you initialised before, without having to get the activity just for that purpose.
I have only the mainActivity and I use 3 fragnments and navigate through them with a bottomnav. All good until now, Im able to run the app on the emulator but when I select this fragment with my RecyclerView I get this error message and the app crashes
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setAdapter(android.support.v7.widget.RecyclerView$Adapter)' on a null object reference
I've seen a lot of alike answers and try to make my way arround but no success, so Im thinking Im not putting the code in the correct way or in the correct places, can you give me some advice?
Here is the Fragment code
public class administrador_atletas extends Fragment {
//Lista de atletas
public List<lista_atletas> lista_atl;
public RecyclerView rcc_lista_atletas;
public lista_atletas_adaptador adaptador_lista_atletas;
public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_administrador_atletas, container, false);
rcc_lista_atletas = (RecyclerView)view.findViewById(R.id.recycler_administrador_atletas);
return view;
}
#Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LinearLayoutManager linear = new LinearLayoutManager(this.getActivity());
linear.setOrientation(LinearLayoutManager.VERTICAL);
rcc_lista_atletas.setLayoutManager(linear);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// do your variables initialisations here except Views!!!
data();
iniciar_adaptador_atletas();
}
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
}
public void data(){
lista_atl = new ArrayList<>();
lista_atl.add(new lista_atletas("Astrid Ruvalcaba Ramos", "Esgrima"));
lista_atl.add(new lista_atletas("Daniel Sanchez Cuevas", "G. Artistica"));
lista_atl.add(new lista_atletas("Alexa Luna Contreras", "TKD"));
lista_atl.add(new lista_atletas("Paul Carillo Mendez", "Natacion"));
lista_atl.add(new lista_atletas("Karen Mendoza Galindo", "Boxeo"));
lista_atl.add(new lista_atletas("Marco Torres Miranda", "Tiro con arco"));
}
public void iniciar_adaptador_atletas(){
adaptador_lista_atletas = new lista_atletas_adaptador(lista_atl);
rcc_lista_atletas.setAdapter(adaptador_lista_atletas);
}
Thanks in advance
EDIT: I just moved
data();
iniciar_adaptador_atletas();
Bellow
rcc_lista_atletas.setLayoutManager(linear);
In onCreateView so I have this
public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_administrador_atletas, container, false);
rcc_lista_atletas = (RecyclerView)view.findViewById(R.id.recycler_administrador_atletas);
LinearLayoutManager linear = new LinearLayoutManager(this.getActivity());
linear.setOrientation(LinearLayoutManager.VERTICAL);
rcc_lista_atletas.setLayoutManager(linear);
data();
iniciar_adaptador_atletas();
return view;
}
And it worked, now Im able to enter the fragment with my data
Many thanks to all, your info was very useful!
As the error message says, you are calling the method setAdapter on a null-valued variable (probably rcc_lista_atletas).
While the error is not exactly in the source code you published (you should update your post with the full code), I suppose one of the methods, data() or iniciar_adaptador_atletas(), is calling 'setAdapter'.
You must remember that onCreate is executed before onCreateView. So, you're probably calling setAdapter before the onCreateView is executed and, doing so, rcc_lista_atletas is still null. Move data() and iniciar_adaptador_atletas() to the line before "return view;" in onCreateView and test it again.
This is the best we can do without checking you full code.
It seems, you try to connect adapter to recyclerView before created recyclerView. So, try to move iniciar_adaptador_atletas(); to the bottom of
rcc_lista_atletas = (RecyclerView)view.findViewById(R.id.recycler_administrador_atletas);
by this answer
I can't understand where to put my onClickListener() - inside onCreateView() or inside onActivityCreated() , below codes describe it better:
CODE A: (Setting Button click listener inside onActivityCreated())
private FloatingActionButton bt;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// do something.
}
});
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.first_frag, container, false);
bt = (FloatingActionButton) v.findViewById(R.id.fab);
return v;
}
CODE B: (Setting Button click listener inside onCreateView())
private FloatingActionButton bt;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.first_frag, container, false);
bt = (FloatingActionButton) v.findViewById(R.id.fab);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// do something.
}
});
return v;
}
I may have not understood which code is better because of my poor English, anyway, thank you all :)
Both will have no effect as far as I know. Once the view is inflated you can put it anywhere either in onCreateView() or in onActivityCreated().
After all, for binding views and setting click listeners, onViewCreated() is a better candidate though, as it will be called immediately after onCreateView. It clearly suggests that your view has been inflated.
There is no specific reason or rule for it. Google itself doesn't care much about it. As a rule of thumb, you can put it anywhere you want once the view is inflated.
I would suggest putting the onClickListener it inside the onActivityCreated. And binding the button to the view inside onCreateView. Just like you have done the first time in your question.
To read more regarding the methods you can go through this post
Since onActivityCreated was deprecated in API level 28, it's probably wise to put it in onCreateView!
What happens if onCreateView returns null instead of View object?
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
....
return null;
}
I tested the application and it seemed to work fine even with null.
My question is: Why does only this Lifecycle function needs to return a View while the others don't need to and just use void and where it gets used?
Can anyone explain why my View element (ListView) is null with the following code:
public class NewsFragment extends Fragment {
#InjectView(R.id.news_listView) ListView lv;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.news_layout, container, false);
ButterKnife.inject(this, view);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (lv == null) {
UIHelper.showAlert("null?");
}
}
}
Am I doing something wrong or is there something wrong with the library, because I pasted the example code to my app to get it working, but it's not working here... Any help is much appreciated!
Have you setup your IDE?
IDE CONFIGURATION
Some IDEs require additional configuration in order to enable
annotation processing.
IntelliJ IDEA — If your project uses an external configuration (like a
Maven pom.xml) then annotation processing should just work. If not,
try manual configuration.
Eclipse — Set up manual configuration
Usually this means that the annotation processor didn't do its work. That might be due to misconfiguration or random problems with the IDE. In my experience, every now and then I had to clean the project and build everything again.
This work for me:
...
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
ButterKnife.bind(this, view);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
...