为什么会发生Android空指针异常错误?

huangapple go评论168阅读模式
英文:

why android null pointer exception error occur?

问题

It seems like you are encountering a java.lang.NullPointerException error in your Java code. The error message indicates that you are trying to invoke a method on a null object reference. Specifically, the error occurs in your HomeFragment.java file, in the onTextChanged method of the TextWatcher when you try to call adapterAd.getFilter().filter(query).

To resolve this issue, you need to make sure that adapterAd is properly initialized before you use it. Here's a modification to your code to ensure adapterAd is initialized in the onViewCreated method:

  1. @Override
  2. public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
  3. super.onViewCreated(view, savedInstanceState);
  4. // Initialize the adapter here
  5. adapterAd = new AdapterAd(mContext, adArrayList);
  6. binding.adsRv.setAdapter(adapterAd);
  7. // ... Your other code ...
  8. binding.searchEt.addTextChangedListener(new TextWatcher() {
  9. @Override
  10. public void beforeTextChanged(CharSequence s, int start, int count, int after) {
  11. }
  12. @Override
  13. public void onTextChanged(CharSequence s, int start, int before, int count) {
  14. Log.d(TAG, "onTextChanged: Query: " + s);
  15. try {
  16. String query = s.toString();
  17. adapterAd.getFilter().filter(query);
  18. } catch (Exception e) {
  19. Log.e(TAG, "onTextChanged: ", e);
  20. }
  21. }
  22. @Override
  23. public void afterTextChanged(Editable s) {
  24. }
  25. });
  26. }

Make sure to initialize adapterAd as shown above, and this should resolve the NullPointerException error you were encountering.

英文:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.widget.Filter com.example.olx_app.AdapterAd.getFilter()' on a null object reference
at com.example.olx_app.HomeFragment$1.onTextChanged(HomeFragment.java:113)

HomeFragment.java

public class HomeFragment extends Fragment {

  1. private FragmentHomeBinding binding;
  2. private static final String TAG="HOME_TAG";
  3. private static final int MAX_DISTANCE_TO_LOAD_ADS_KM =10;
  4. //Context for this fragment class
  5. private Context mContext;
  6. //adArrayList to hold ads list to show in RecycleView
  7. private ArrayList<ModelAd> adArrayList;
  8. //AdapterAd class instance to set to RecycleView to show Ads list
  9. private AdapterAd adapterAd;
  10. //show nearby location
  11. private SharedPreferences locationSp;
  12. private double currentLatitude =0.0;
  13. private double currentLongitude = 0.0;
  14. private String currentAddress ="";
  15. @Override
  16. public void onAttach(@NonNull Context context) {
  17. mContext = context;
  18. super.onAttach(context);
  19. }
  20. public HomeFragment() {
  21. // Required empty public constructor
  22. }
  23. @Override
  24. public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  25. // Inflate the layout for this fragment
  26. binding = FragmentHomeBinding.inflate(LayoutInflater.from(mContext),container,false);
  27. return binding.getRoot();
  28. }
  29. @Override
  30. public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
  31. super.onViewCreated(view, savedInstanceState);
  32. //init the shared Preferences p1. name of SharedPreferences file , p2. mode of SharedPreferences
  33. locationSp = mContext.getSharedPreferences("LOCATION_SP", Context.MODE_PRIVATE);
  34. //get saved current Latitude , Longitude ,address from SharedPreferences .
  35. //In next we will pick these info from map and save in it
  36. currentLatitude = locationSp.getFloat("CURRENT_LATITUDE",0.0f);
  37. currentLongitude = locationSp.getFloat("CURRENT_LONGITUDE",0.0f);
  38. currentAddress = locationSp.getString("CURRENT_ADDRESS","");
  39. //if current location is not 0
  40. if(currentLatitude !=0.0 && currentLongitude !=0.0)
  41. {
  42. binding.locationTv.setText(currentAddress);
  43. }
  44. //call , load categories
  45. loadCategories();
  46. //call , load all ads
  47. loadAds("All");
  48. binding.searchEt.addTextChangedListener(new TextWatcher() {
  49. @Override
  50. public void beforeTextChanged(CharSequence s, int start, int count, int after) {
  51. }
  52. @Override
  53. public void onTextChanged(CharSequence s, int start, int before, int count) {
  54. Log.d(TAG, "onTextChanged: Query: "+s);
  55. try {
  56. String query = s.toString();
  57. adapterAd.getFilter().filter(query);
  58. }
  59. catch (Exception e)
  60. {
  61. Log.e(TAG, "onTextChanged: ",e);
  62. }
  63. }
  64. @Override
  65. public void afterTextChanged(Editable s) {
  66. }
  67. });
  68. binding.locationCv.setOnClickListener(new View.OnClickListener() {
  69. @Override
  70. public void onClick(View v) {
  71. Intent intent = new Intent(mContext,LocationPickerActivity.class);
  72. locationPickerActivityResult.launch(intent);
  73. }
  74. });
  75. }
  76. private final ActivityResultLauncher<Intent> locationPickerActivityResult = registerForActivityResult(
  77. new ActivityResultContracts.StartActivityForResult(),
  78. new ActivityResultCallback<>() {
  79. @Override
  80. public void onActivityResult(ActivityResult result) {
  81. //check if from map , location is picked or not
  82. if (result.getResultCode() == Activity.RESULT_OK) {
  83. Log.d(TAG, "onActivityResult: RESULT_OK");
  84. Intent data = result.getData();
  85. if (data != null) {
  86. Log.d(TAG, "onActivityResult: Location picked");
  87. //get location info from intent
  88. currentLatitude = data.getDoubleExtra("latitude", 0.0);
  89. currentLongitude = data.getDoubleExtra("longitude", 0.0);
  90. currentAddress = data.getStringExtra("address");
  91. //save location info to shared preferences to when we launch app next time we don't need to pick again
  92. locationSp.edit()
  93. .putFloat("CURRENT_LATITUDE", Float.parseFloat("" + currentLatitude))
  94. .putFloat("CURRENT_LONGITUDE", Float.parseFloat("" + currentLongitude))
  95. .putString("CURRENT_ADDRESS", currentAddress)
  96. .apply();
  97. //set the picked address
  98. binding.locationTv.setText(currentAddress);
  99. //after picking address reload all ads again based on newly picked location
  100. loadAds("All");
  101. }
  102. } else {
  103. Log.d(TAG, "onActivityResult: Cancelled!");
  104. Utils.toast(mContext, "Cancelled!");
  105. }
  106. }
  107. }
  108. );
  109. private void loadCategories()
  110. {
  111. //init categoryArrayList
  112. ArrayList<ModelCategory> categoryArrayList = new ArrayList<>();
  113. //ModelCategory instance to show all products
  114. ModelCategory modelCategoryAll = new ModelCategory("All" , R.drawable.all);
  115. categoryArrayList.add(modelCategoryAll);
  116. //get categories from utils class and add in categoryArrayList
  117. for(int i=0; i <Utils.categories.length ;i++)
  118. {
  119. //hold category from current index
  120. ModelCategory modelCategory = new ModelCategory(Utils.categories[i], Utils.categoryIcons[i]);
  121. //add modelCategory to categoryArrayList
  122. categoryArrayList.add(modelCategory);
  123. }
  124. //setup AdapterCategory
  125. AdapterCategory adapterCategory = new AdapterCategory(mContext, categoryArrayList, new RvListenerCategory() {
  126. @Override
  127. public void onCategoryClick(ModelCategory modelCategory) {
  128. loadAds(modelCategory.getCategory());
  129. }
  130. });
  131. //set adapter to the RecycleView like categoriesRv
  132. binding.categoriesRv.setAdapter(adapterCategory);
  133. }

private void loadAds(String category) {
Log.d(TAG, "loadAds: Category: "+category);

  1. /*//init adArrayList before starting adding data into it
  2. adArrayList = new ArrayList<>();*/
  3. //Firebase DB listener to load ads based on category & distance
  4. DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Ads");
  5. ref.addValueEventListener(new ValueEventListener() {
  6. @Override
  7. public void onDataChange(@NonNull DataSnapshot snapshot) {
  8. //clear adArrayList each time starting adding data into it
  9. adArrayList.clear();
  10. //load ads list
  11. for(DataSnapshot ds: snapshot.getChildren()) {
  12. //prepare modelAd with all data from Firebase DB
  13. ModelAd modelAd = ds.getValue(ModelAd.class);
  14. //function call with returned value as distance in km
  15. assert modelAd != null;
  16. double distance = calculateDistanceKm(modelAd.getLatitude(), modelAd.getLongitude());
  17. Log.d(TAG, "onDataChange: distance: " + distance);
  18. //filter
  19. if (category.equals("All")) {
  20. //category All is selected , now check distance if is <= required e.x. 10km then show
  21. if (distance <= MAX_DISTANCE_TO_LOAD_ADS_KM) {
  22. //distance is <= required e.x. 10km Add to list
  23. adArrayList.add(modelAd);
  24. }
  25. } else {
  26. //some category is selected e.x. mobile
  27. if (modelAd.getCategory().equals(category)) {
  28. if (distance <= MAX_DISTANCE_TO_LOAD_ADS_KM) {
  29. //distance is <= required e.x. 10km Add to list
  30. adArrayList.add(modelAd);
  31. }
  32. }
  33. }
  34. }
  35. adapterAd = new AdapterAd(mContext,adArrayList);
  36. binding.adsRv.setAdapter(adapterAd);
  37. }
  38. @Override
  39. public void onCancelled(@NonNull DatabaseError error) {
  40. }
  41. });
  42. }
  43. private double calculateDistanceKm(double adLatitude, double adLongitude)
  44. {
  45. Log.d(TAG, "calculateDistanceKm: currentLatitude: "+ currentLatitude);
  46. Log.d(TAG, "calculateDistanceKm: currentLongitude: "+currentLongitude);
  47. Log.d(TAG, "calculateDistanceKm: adLatitude: "+adLatitude);
  48. Log.d(TAG, "calculateDistanceKm: adLongitude: "+adLongitude);
  49. //source Location i.e. user's current location
  50. Location startPoint = new Location(LocationManager.NETWORK_PROVIDER);
  51. startPoint.setLatitude(currentLatitude);
  52. startPoint.setLongitude(currentLongitude);
  53. //Destination Location i.e. Ad's Location
  54. Location endPoint = new Location(LocationManager.NETWORK_PROVIDER);
  55. endPoint.setLatitude(adLatitude);
  56. endPoint.setLongitude(adLongitude);
  57. //calculate distance
  58. double distanceInMeters = startPoint.distanceTo(endPoint);
  59. double distanceInKm = distanceInMeters / 1000 ;
  60. return distanceInKm;
  61. }

}

AdapterAd.java

public class AdapterAd extends RecyclerView.Adapter<AdapterAd.HolderAd> implements Filterable
{
private RowAdBinding binding;

  1. private static final String TAG = &quot;ADAPTER_AD_TAG&quot;;
  2. private FirebaseAuth firebaseAuth;
  3. private Context context;
  4. //adArrayList the list of the Ads
  5. public ArrayList&lt;ModelAd&gt; adArrayList;
  6. private ArrayList&lt;ModelAd&gt; filterList;
  7. private FilterAd filter;
  8. public AdapterAd(Context context, ArrayList&lt;ModelAd&gt; adArrayList) {
  9. this.context = context;
  10. this.adArrayList = adArrayList;
  11. this.filterList = adArrayList;
  12. firebaseAuth = FirebaseAuth.getInstance();
  13. }
  14. @NonNull
  15. @Override
  16. public HolderAd onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  17. //inflate the row_ad.xml
  18. binding = RowAdBinding.inflate(LayoutInflater.from(context),parent,false);
  19. return new HolderAd(binding.getRoot());
  20. }
  21. @Override
  22. public void onBindViewHolder(@NonNull HolderAd holder, int position) {
  23. //get data from particular position of list and set to UI
  24. ModelAd modelAd = adArrayList.get(position);
  25. String title = modelAd.getTitle();
  26. String description = modelAd.getDescription();
  27. String address = modelAd.getAddress();
  28. String price = modelAd.getPrice();
  29. String condition = modelAd.getCondition();
  30. //function call : load first image from available images of Ad
  31. loadAdFirstImage(modelAd,holder);
  32. //set data to UI views of row_ad.xml
  33. holder.titleTv.setText(title);
  34. holder.descriptionTv.setText(description);
  35. holder.addressTv.setText(address);
  36. holder.priceTv.setText(price);
  37. holder.conditionTv.setText(condition);
  38. }
  39. private void loadAdFirstImage(ModelAd modelAd, HolderAd holder) {
  40. Log.d(TAG, &quot;loadAdFirstImage: &quot;);
  41. //load first image from available images of Ad
  42. //adId to get image of it
  43. String adId = modelAd.getId();
  44. DatabaseReference reference = FirebaseDatabase.getInstance().getReference(&quot;Ads&quot;);
  45. reference.child(adId).child(&quot;Images&quot;).limitToFirst(1)
  46. .addValueEventListener(new ValueEventListener() {
  47. @Override
  48. public void onDataChange(@NonNull DataSnapshot snapshot)
  49. {
  50. //it return 1 image as we have used query .limitToFirst(1)
  51. for(DataSnapshot ds:snapshot.getChildren())
  52. {
  53. //get Url of image
  54. String imageUrl =&quot;&quot;+ds.child(&quot;imageUrl&quot;).getValue();
  55. Log.d(TAG, &quot;onDataChange: imageUrl: &quot;+imageUrl);
  56. //set image to Image view
  57. try
  58. {
  59. Glide.with(context)
  60. .load(imageUrl)
  61. .placeholder(R.drawable.ic_image_gray)
  62. .into(holder.imageIv);
  63. }catch (Exception e)
  64. {
  65. Log.e(TAG, &quot;onDataChange: &quot;,e );
  66. }
  67. }
  68. }
  69. @Override
  70. public void onCancelled(@NonNull DatabaseError error) {
  71. }
  72. });
  73. }
  74. @Override
  75. public int getItemCount() {
  76. return adArrayList.size();
  77. }
  78. @Override
  79. public Filter getFilter() {
  80. //init the filter obj only if it is null
  81. if(filter == null)
  82. {
  83. filter = new FilterAd(this,adArrayList);
  84. }
  85. return filter;
  86. }
  87. class HolderAd extends RecyclerView.ViewHolder
  88. {
  89. //UI views of the row_ad.xml
  90. ShapeableImageView imageIv;
  91. TextView titleTv, descriptionTv , addressTv , conditionTv , priceTv;
  92. ImageButton favBtn;
  93. public HolderAd(@NonNull View itemView) {
  94. super(itemView);
  95. //init UI views of the row_ad.xml
  96. imageIv = binding.imageIv;
  97. titleTv = binding.titleTv;
  98. descriptionTv = binding.descriptionTv;
  99. favBtn = binding.favBtn;
  100. addressTv = binding.addressTv;
  101. conditionTv = binding.conditionTv;
  102. priceTv = binding.priceTv;
  103. }
  104. }

}

FilterAd.java

public class FilterAd extends Filter
{
public AdapterAd adapter;

  1. public ArrayList&lt;ModelAd&gt; filterList;
  2. public FilterAd(AdapterAd adapter, ArrayList&lt;ModelAd&gt; filterList) {
  3. this.adapter = adapter;
  4. this.filterList = filterList;
  5. }
  6. @Override
  7. protected FilterResults performFiltering(CharSequence constraint) {
  8. //perform filter based on what user type
  9. FilterResults results = new FilterResults();
  10. if(constraint != null &amp;&amp; constraint.length() &gt; 0)
  11. {
  12. //search query is not null and not empty , we can perform filter
  13. //convert query to upper case to make search not case sensitive
  14. constraint = constraint.toString().toUpperCase();
  15. //hold the filtered list of ads based on user searched query
  16. ArrayList&lt;ModelAd&gt; filteredModels = new ArrayList&lt;&gt;();
  17. for(int i=0; i&lt;filterList.size(); i++)
  18. {
  19. //Ad filter based on Brand,Category,Condition,Title . if any of these matches add it to the filterModels list
  20. if(filterList.get(i).getBrand().toUpperCase().contains(constraint) ||
  21. filterList.get(i).getCategory().toUpperCase().contains(constraint) ||
  22. filterList.get(i).getCondition().toUpperCase().contains(constraint) ||
  23. filterList.get(i).getTitle().toUpperCase().contains(constraint)) {
  24. //Filter matched add to filterModels list
  25. filteredModels.add(filterList.get(i));
  26. }
  27. }
  28. results.count = filteredModels.size();
  29. results.values = filteredModels;
  30. }
  31. else
  32. {
  33. //the search query is either null or empty . we can&#39;t perform filter . return full list
  34. results.count = filterList.size();
  35. results.values = filterList;
  36. }
  37. return results;
  38. }
  39. @SuppressLint(&quot;NotifyDataSetChanged&quot;)
  40. @Override
  41. protected void publishResults(CharSequence constraint, FilterResults results) {
  42. //publish the filtered result
  43. adapter.adArrayList = (ArrayList&lt;ModelAd&gt;) results.values;
  44. adapter.notifyDataSetChanged();
  45. }

}

// Declare the AdapterAd reference globally in your HomeFragment class
private AdapterAd adapter;

// ...

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);

  1. // Initialize the adapter here
  2. adapter = new AdapterAd(mContext, adArrayList);
  3. binding.adsRv.setAdapter(adapter);
  4. // ... Your other code ...
  5. binding.searchEt.addTextChangedListener(new TextWatcher() {
  6. @Override
  7. public void beforeTextChanged(CharSequence s, int start, int count, int after) {
  8. }
  9. @Override
  10. public void onTextChanged(CharSequence s, int start, int before, int count) {
  11. Log.d(TAG, &quot;onTextChanged: Query: &quot; + s);
  12. try {
  13. query = s.toString();
  14. // Now you can safely call getFilter() on the initialized adapter
  15. adapter.getFilter().filter(query);
  16. } catch (Exception e) {
  17. Log.e(TAG, &quot;onTextChanged: &quot;, e);
  18. }
  19. }
  20. @Override
  21. public void afterTextChanged(Editable s) {
  22. }
  23. });

}

private void loadAds(String category) {

  1. ref.addValueEventListener(new ValueEventListener() {
  2. @Override
  3. public void onDataChange(@NonNull DataSnapshot snapshot) {
  4. // ...
  5. adArrayList.clear();
  6. // ...
  7. adapter.notifyDataSetChanged(); // Notify the adapter that the data has changed
  8. }
  9. @Override
  10. public void onCancelled(@NonNull DatabaseError error) {
  11. }
  12. });

}

I can try this but not solved problem

答案1

得分: 1

因为您正在访问 adapterAd,但它可能尚未初始化,因为您是在 Firebase 数据库的成功回调中初始化它。

方法1:在访问适配器之前进行null检查

  1. try {
  2. String query = s.toString();
  3. if(adapterAd != null){
  4. adapterAd.getFilter().filter(query);
  5. }
  6. }

方法2:在使用 Firebase 获取数据后,使用空列表初始化适配器,然后更新适配器。

  1. // 在 onCreateView() 中初始化适配器
  2. adArrayList = new ArrayList<>();
  3. adapterAd = new AdapterAd(mContext, adArrayList);
  4. binding.adsRv.setAdapter(adapterAd);
  5. // 在成功回调中通知适配器列表已更改
  6. ref.addValueEventListener(new ValueEventListener() {
  7. @Override
  8. public void onDataChange(@NonNull DataSnapshot snapshot) {
  9. // 每次开始向其中添加数据之前清除 adArrayList
  10. adArrayList.clear();
  11. // 加载广告列表
  12. for(DataSnapshot ds: snapshot.getChildren()) {
  13. // 您的代码
  14. }
  15. // 使用以下代码来更新适配器
  16. adapterAd.notifyDataSetChanged();
  17. }
  18. }
英文:

It is because you are accessing adapterAd, but it may not have been initialized, as you are initializing it in your success callback of Firebase database.

Approach 1 : Do a null check before accessing your adapter

  1. try {
  2. String query = s.toString();
  3. if(adapterAd != null){
  4. adapterAd.getFilter().filter(query);
  5. }
  6. }

Approach 2: Initialize your adapter with empty list and then update the adapter after you get data from Firebase.

  1. // initialize the adapter in your onCreateView()
  2. adArrayList = new ArrayList&lt;&gt;();
  3. adapterAd = new AdapterAd(mContext,adArrayList);
  4. binding.adsRv.setAdapter(adapterAd);
  5. // notify that adapter that list is changed in your success callback
  6. ref.addValueEventListener(new ValueEventListener() {
  7. @Override
  8. public void onDataChange(@NonNull DataSnapshot snapshot) {
  9. //clear adArrayList each time starting adding data into it
  10. adArrayList.clear();
  11. //load ads list
  12. for(DataSnapshot ds: snapshot.getChildren()) {
  13. // your code
  14. }
  15. // use this to update your adapter
  16. adapterAd.notifyDataSetChanged();
  17. }

huangapple
  • 本文由 发表于 2023年8月11日 00:00:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76877473.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定