Null Pointer Debugging [duplicate] - android

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
quick summary of what I'm trying to do.
Using shared preferences so that when a user watches a video a green tick will appear beside it to mark it as complete. Currently getting a null pointer error.
Basically there are two pages - main page and video page. When user lands on the main page the if statement should check the sharepreferences to see if they have already visited the video page. If they have it should display the completedTick imageView.
Please see the code and context below.
MAIN PAGE CODE SNIPPET:
/**
* Shared preferences variable which is used to store the userId which is captured at the login screen.
*/
private SharedPreferences loginPref, activityPref;
private ImageView completedTick;
private Boolean activityCompleted;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
loginPref = getContext().getSharedPreferences("loginPref", Context.MODE_PRIVATE);
activityPref = getContext().getSharedPreferences("activityPref", Context.MODE_PRIVATE);
activityCompleted = activityPref.getBoolean("activityCompleted", true);
View view = inflater.inflate(R.layout.fragment_activities, container, false);
initialiseRecyclerView(view);
retrieveActivities();
if(activityCompleted == false || activityCompleted == null ) {
completedTick.setVisibility(view.INVISIBLE);
}else{
completedTick.setVisibility(View.VISIBLE);
}
return view;
}
#Override
public void onViewCreated(#NonNull final View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
/**
* Method which is used to initialise the recycler view
*
* #param view
*/
private void initialiseRecyclerView(View view) {
mRecyclerView = view.findViewById(R.id.recyclerViewActivities);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
EmptyAdapter emptyAdapter = new EmptyAdapter();
mRecyclerView.setAdapter(emptyAdapter);
completedTick = view.findViewById(R.id.completedTick);
}
VIDEO PAGE CODE SNIPPET:
private SharedPreferences activityPref;
private Boolean activityCompleted;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.youtube_layout);
Log.d(TAG, "onCreateView: Starting");
activityPref = getSharedPreferences("activityPref", MODE_PRIVATE);
activityCompleted = activityPref.getBoolean("activityCompleted", true);
getExtrasMethod();
initialiseViews();
setTextInViews();
checkCompleteD();
private void checkCompleteD() {
if (activityCompleted) {
SharedPreferences.Editor editor = activityPref.edit();
activityCompleted = false;
editor.putBoolean("activityCompleted", activityCompleted);
editor.apply();
}
}
The error is :
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setVisibility(int)' on a null object reference
at com.example.fit.ActivitiesFragment.onCreateView(ActivitiesFragment.java:78)
UPDATE:
Made the suggedted changes
#Override
public void onViewCreated(#NonNull final View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
loginPref = getContext().getSharedPreferences("loginPref", Context.MODE_PRIVATE);
activityPref = getContext().getSharedPreferences("activityPref", Context.MODE_PRIVATE);
activityCompleted = activityPref.getBoolean("activityCompleted", true);
completedTick = view.findViewById(R.id.completedTickImage);
initialiseRecyclerView(view);
retrieveActivities();
if (activityCompleted == false || activityCompleted == null) {
completedTick.setVisibility(View.INVISIBLE);
} else {
completedTick.setVisibility(View.VISIBLE);
}
}
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setVisibility(int)' on a null object reference
at com.example.feelingfit.ActivitiesFragment.onViewCreated(ActivitiesFragment.java:85)
Which is this line : completedTick.setVisibility(View.INVISIBLE);

First of all, your completedTick is null. Try putting the completedTick = view.findViewById(R.id.completedTick); in your OnViewCreated above this code:
if(activityCompleted == false || activityCompleted == null ) {
completedTick.setVisibility(View.INVISIBLE);
}else{
completedTick.setVisibility(View.VISIBLE);
}
And also, replace the view.INVISIBLE with View.INVISIBLE
Edit + Aditional Information:
If you occur again the NullPointerException please refer to this link.
Edit 2:
Rewrite your code inside the onViewCreated method like this:
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_activities, container, false);
}
#Override
public void onViewCreated(#NonNull final View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
loginPref = getContext().getSharedPreferences("loginPref", Context.MODE_PRIVATE);
activityPref = getContext().getSharedPreferences("activityPref", Context.MODE_PRIVATE);
activityCompleted = activityPref.getBoolean("activityCompleted", true);
initialiseRecyclerView(view);
retrieveActivities();
if(activityCompleted == false || activityCompleted == null ) {
completedTick.setVisibility(View.INVISIBLE);
}else{
completedTick.setVisibility(View.VISIBLE);
}
}
Edit number 3: Since it is crashing again on the same use case I assume your R.id.completedTickImage is not inside your fragment_activities

Do the operation of CompleteTick.setVisibility inside onActivityCreated() method and also replace the view.INVISIBLE to View.INVISIBLE

Related

Infinite loop on settheme()

I am trying to change the app theme from the fragment using setTheme() method of an activity. But somehow its looping forever while trying to change. Here is my setTheme() method calls.
//XYZ Fragment class
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
if (mThemeName.equalsIgnoreCase("Mode 1")) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
getActivity().setTheme(R.style.Theme_One);
} else {
getActivity().setTheme(R.style.Theme_Two);
}
super.onViewCreated(view, savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//binding object of this fragment
binding = FragmentXYZBinding.inflate(inflater);
binding.switch.setOnCheckedChangeListener((buttonView, isChecked) -> {
if(isChecked){
setTheme("Mode 2");
}else {
setTheme("Mode 1");
}
});
return inflater.inflate(R.layout.fragment_setting, container, false);
}
public void setTheme(String name) {
SharedPreferences preferences = getActivity().getSharedPreferences("app", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("ThemeName", name);
editor.apply();
// If i call this recreate() then it goes into infinite loop
// but without calling this I can't change theme on runtime
//getActivity().recreate();
}
Any idea about what could be wrong in here ?

Saving state of Fragment on View with LiveData

Im saving the state of fragment on a View, it works in the way I expected, the problem is with the LiveData. When I navigate to other fragment and then come back to this fragment, I cant no longer observer for changes. This is the code of my OnCreateView():
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(view == null){
view = inflater.inflate(R.layout.fragment, container, false);
initializeViews(view);
receivedProductViewModel.getProductMutableLiveData().observe(getViewLifecycleOwner(), new Observer<DispatchedProduct>() {
#Override
public void onChanged(DispatchedProduct dispatchedProduct) {
if(dispatchedProduct != null){
int index = dispatchedProducts.indexOf(dispatchedProduct);
dispatchedProductsAdapter.notifyItemChanged(index);
}
}
});
btnSearch.setOnClickListener(btnSearchListener());
btnRegister.setOnClickListener(btnRegisterListener());
initializeRV();
}
return view;
}
I'm initializing the VM in OnCreate():
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
receivedProductViewModel = new ViewModelProvider(getActivity()).get(ReceivedProductViewModel.class);
}
Move your observe outside of your if (view == null) block. You always need to create a new Observer for your View every time onCreateView is called - the previous getViewLifecycleOwner() was destroyed when the previous onDestroyView was called, which correctly stops your previous observe callback.
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(view == null){
view = inflater.inflate(R.layout.fragment, container, false);
initializeViews(view);
btnSearch.setOnClickListener(btnSearchListener());
btnRegister.setOnClickListener(btnRegisterListener());
initializeRV();
}
receivedProductViewModel.getProductMutableLiveData().observe(
getViewLifecycleOwner(), new Observer<DispatchedProduct>() {
#Override
public void onChanged(DispatchedProduct dispatchedProduct) {
if(dispatchedProduct != null){
int index = dispatchedProducts.indexOf(dispatchedProduct);
dispatchedProductsAdapter.notifyItemChanged(index);
}
}
});
return view;
}

Why the view is null outside onCreateView

I declare a view variable in the class and assign its value in OnCreateView using findviewbyid as usual, and I use an interface to interact between this fragment and another one, when the other fragment interacts with this fragment using a method called "ask" in which the local variable is invoked, I find that the variable is null Here is the variable
private TextInputLayout questionLayout;
Here I assign its value
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_article_, container, false);
Button ask = v.findViewById(R.id.ask);
questionLayout = v.findViewById(R.id.QuestionInputLayoutArticle);
if(questionLayout == null){
Log.d("ORDERARTICLE","QUESTION");
}
Log.d("ORDERORDER","CreateView");
return v;
}
Here is the method
#Override
public boolean ask() {
Log.d("ORDERORDER","ASK");
if(questionLayout == null){
Log.d("ORDERARTICLE","QUESTION");
}
if(questionLayout.getEditText().getText().toString().isEmpty()){
return false;
}else {
FirebaseFirestore Fs = FirebaseFirestore.getInstance();
Map<String, String> QuestionMap = new HashMap<>();
QuestionMap.put("Head", questionLayout.getEditText().getText().toString());
QuestionMap.put("Type", "Article");
Fs.collection("Questions").document().set(QuestionMap);
return true;
}
}
You can note that I am logging to make sure that the value is assigned before invoking the variable and it's assigned before invoking indeed

ClickListener in cardview return null exception

I have some problem when I try to click a cardview, I want it to make toast with its ID. But whenever I click the cardview, it always crashed and get null exception on its listener. already declare the listener but still crashed. Thank You
Listener class
public interface ResetPasswordListener {
void onClickCardview(String userid);
}
Adapter Class
public class ResetPasswordAdapter extends RecyclerView.Adapter<ResetPasswordAdapter.ViewHolder> implements ResetPasswordListener {
private List<ResetPasswordRespModel> resetList = new ArrayList<>();
private ResetPasswordListener resetPasswordListener;
public void setOnClick(ResetPasswordListener listener) {
this.resetPasswordListener = listener;
}
#Override
public void onClickCardview(String userid) {
Log.d("ID VALUE", userid);
resetPasswordListener.onClickCardview(userid);
}
}
This is how I set the listener in fragment class
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
listResetPasswordBinding = DataBindingUtil.inflate(inflater, R.layout.list_reset_password, container, false);
return inflater.inflate(R.layout.fragment_reset_password, container, false);
}
#Override
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
listResetPasswordBinding.setOnClick(new ResetPasswordListener() {
#Override
public void onClickCardview(String userid) {
Toast.makeText(getActivity(), userid, Toast.LENGTH_SHORT).show();
}
});
}
Error Logs
java.lang.NullPointerException: Attempt to invoke interface method 'void example.com.absensiapp.view.listener.ResetPasswordListener.onClickCardview(java.lang.String)' on a null object reference
at example.com.absensiapp.view.adapter.ResetPasswordAdapter.onClickCardview(ResetPasswordAdapter.java:35)
at example.com.absensiapp.databinding.ListResetPasswordBindingImpl._internalCallbackOnClick(ListResetPasswordBindingImpl.java:227)
at example.com.absensiapp.generated.callback.OnClickListener.onClick(OnClickListener.java:11)
The problem seems to be onCreateView you are inflating the layout twice one with DataBindingUtil.inflate adn once with inflater.inflate. Modify it
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
listResetPasswordBinding = DataBindingUtil.inflate(inflater, R.layout.list_reset_password, container, false);
return listResetPasswordBinding.getroot();
}
Also call setOnClick of ResetPasswordAdapter to set listener. Until you set the listener you will keep getting a null pointer.

Initialization Method for 'RecyclerView' crashes app when used with fragments

I used a recyclerView on my app to display all files from an external storage. Until I changed it, it worked fine when it was implemented in the "MainActivity.java".
Now, I want my app to have a "BottomNavigationBar"; in order to do that, I use fragments. The problem is the app crashes when I touch the specific item from the menu (the one containing the RecyclerView).
I changed all the "this" method to ".getActivity()" but it crashed anyways. I changed it to ".getActivity().getApplicationContext()" but it still crashed.
I'm sorry, my computer does not support hardware acceleration so I can't properly show what the error is. Instead, I have attached a debugger to my connected phone and set up breakpoints. The debugger highlighted the line "RecyclerView recyclerView = getView().findViewById(R.id.recyclerview);" when the app crashed.
Here's the fragment code:
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_records, container, false);
}
private static final int PERMISSION_REQUEST = 1000;
private ArrayList<String> mNames = new ArrayList<>();
public static ArrayList<String> NbFiles = new ArrayList<>();
public ArrayList<String> PathFiles = new ArrayList<>();
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Check if we have the permission to read storage
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//We don't have the permission, so request it.
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST);
}
//We already have permission
else {
permissionExists();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PERMISSION_REQUEST) {
if (resultCode == RESULT_OK) {
permissionExists();
} else {
//handle error
}
}
}
private void initRecyclerView() {
RecyclerView recyclerView = getView().findViewById(R.id.recyclerview);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(mNames, getActivity().getApplicationContext(), (RecyclerViewAdapter.OnNoteListener) this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
}
private void permissionExists() {
String path = Environment.getExternalStorageDirectory().toString() + "/Rapture";
File directory = new File(path);
boolean success = true;
if (!directory.exists()) {
success = directory.mkdirs();
}
if (success) {
File[] arrayFiles = directory.listFiles();
for (File file : arrayFiles) {
mNames.add(file.getName());
PathFiles.add(file.getPath());
NbFiles.add(file.getName());
}
}
initRecyclerView();
}
}
[Let me know if you need more code]
How can I fix this ?
RecyclerView recyclerView = getView().findViewById(R.id.recyclerview);
Instead of getView(), you need to use the view inflated in onCreateView
So,
RecyclerView recyclerView;
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_records, container, false);
recyclerView = v.findViewById(R.id.recyclerview);
return v;
}
If you want, you can then populate the RecyclerView (or make it visible, or whatever) in initRecyclerView()
Change your code to this-
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_records, container, false);
initRecyclerView(view);
return view;
}
private void initRecyclerView(View view) {
RecyclerView recyclerView = view.findViewById(R.id.recyclerview);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(mNames, getActivity().getApplicationContext(), (RecyclerViewAdapter.OnNoteListener) this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
}
try this
getActivity() instance of getView()
RecyclerView recyclerView = getView().findViewById(R.id.recyclerview);
instance of
RecyclerView recyclerView = getActivity().findViewById(R.id.recyclerview);
Move below code for handling permission onActivityCreated
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//We don't have the permission, so request it.
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST);
}
//We already have permission
else {
permissionExists();
}
}
In Fragment, you can initialize your view in onViewCreated
// This event is triggered soon after onCreateView().
// Any view setup should occur here. E.g., view lookups and attaching view listeners.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// Setup any handles to view objects here
initRecyclerView(view);
}
Change your initRecyclerView() like below,
private void initRecyclerView(View v) {
RecyclerView recyclerView = v.findViewById(R.id.recyclerview);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(mNames, getActivity().getApplicationContext(), (RecyclerViewAdapter.OnNoteListener) this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
}
It will shows fragment page without blank,
For more clarification about life cycle of Fragment, refer this
Remove the onCreate mewthod and move the logic into onCreateView
Here the issue is your recyclerView initializes by calling getActivity() but the problem is that the activity does not exist until onActivityCreated() is called.
So it's crashing. Move all of that code inside onCreate() to onActivityCreated() and it should work fine.

Categories

Resources