I am stuck in something
List is null as you see but I want to assign it to the response from API before the pass it to the Adapter. But the List passed as null and throw null exception. I call the API method in onCreate() method before the Adapter initialization but it does not work somehow.
I could not understand what I miss here. How can the List is not assigned. I tried to initialize new ArrayList and it did not throw any error but this time the RecyclerView is empty.
Any help?
Code:
public class InventoryInfoActivity extends AppCompatActivity {
InventoryInfoRecyclerViewAdapter inventoryInfoRecyclerViewAdapter;
RecyclerView recyclerView;
ProductService productService;
List<Product> productList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inventory_info);
productService = new ProductService(this);
// CALL METHOD
this.getProductList();
recyclerView = findViewById(R.id.recycler_inventory);
recyclerView.setLayoutManager(new LinearLayoutManager(InventoryInfoActivity.this));
inventoryInfoRecyclerViewAdapter = new InventoryInfoRecyclerViewAdapter(productList,this);
recyclerView.setAdapter(inventoryInfoRecyclerViewAdapter);
}
// API REQUEST
private void getProductList() {
productService.getProducts().enqueue(new Callback<List<Product>>() {
@Override
public void onResponse(Call<List<Product>> call, Response<List<Product>> response) {
if (response.isSuccessful()) {
Log.i("REQUEST","OK");
// ASSIGN
productList = response.body();
}else {
Log.i("REQUEST","BAD");
productList = new ArrayList<>();
}
}
@Override
public void onFailure(Call<List<Product>> call, Throwable t) {
Log.i("REQUEST","FAILED");
productList = new ArrayList<>();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search_action,menu);
MenuItem menuItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setQueryHint("Ara");
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
filter(newText);
return false;
}
});
return super.onCreateOptionsMenu(menu);
}
private void filter(String text) {
ArrayList<Product> filteredlist = new ArrayList<>();
for (Product item : productList) {
if (item.getProductName().toLowerCase().contains(text.toLowerCase())) {
filteredlist.add(item);
}
}
if (filteredlist.isEmpty()) {
Toast.makeText(this, "Böyle bir ürün yok", Toast.LENGTH_SHORT).show();
} else {
inventoryInfoRecyclerViewAdapter.filterList(filteredlist);
}
}
}
LogCat:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.tempter.stoktakip, PID: 32165
java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
CodePudding user response:
The problem is here that after you get your response you should inform your adapter that you have a new List. There are many cool methods in RecyclerView called notifiyDataSetChanged
.
What you did is not all wrong. Let me explain what you can do in your code:
- The variable that you define is a list which doesn’t have any value so its null.
private List<Product> items = new ArrayList<Product>();
or you should fix the getItems method in your adapter like below:
public int getItems() {
return items == null || items.isEmpty() ? 0 : items.size();
}
- After you get your response, please pass the new list to adapter. First you need to create in adapter a method that pass those data like below
// in your adapter
public void setData(List<String> newItems) {
adapterItems.clear();
adapterItems.addAll(newItems);
notifyDataSetChange();
}
and then after your successfull api call you should do it like below:
private void getProductList() {
productService.getProducts().enqueue(new Callback<List<Product>>() {
@Override
public void onResponse(Call<List<Product>> call, Response<List<Product>> response) {
if (response.isSuccessful()) {
Log.i("REQUEST", "OK");
// ASSIGN
productList = response.body();
//!! This is here important
inventoryInfoRecyclerViewAdapter.setData(productList);
//!! This is here important
} else {
Log.i("REQUEST", "BAD");
productList = new ArrayList<>();
}
}
@Override
public void onFailure(Call<List<Product>> call, Throwable t) {
Log.i("REQUEST", "FAILED");
productList = new ArrayList<>();
}
});
}
Now that’s it. You should now have you recyclerView updated with the new list.
CodePudding user response:
First, call the getProductList
at the end of onCreate.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List<Product> productlist = new ArrayList<Product>();
setContentView(R.layout.activity_inventory_info);
productService = new ProductService(this);
recyclerView = findViewById(R.id.recycler_inventory);
recyclerView.setLayoutManager(new LinearLayoutManager(InventoryInfoActivity.this));
inventoryInfoRecyclerViewAdapter = new InventoryInfoRecyclerViewAdapter(productList,this);
recyclerView.setAdapter(inventoryInfoRecyclerViewAdapter);
this.getProductList();
}
Then I presume that getProductList
should be return a List of Product or a List of your another class.
private ArrayList<Product> getProductList() {
productService.getProducts().enqueue(new Callback<List<Product>>() {
@Override
public void onResponse(Call<List<Product>> call, Response<List<Product>> response) {
if (response.isSuccessful()) {
Log.i("REQUEST","OK");
// ASSIGN
productList = response.body();
}else {
Log.i("REQUEST","BAD");
productList = new ArrayList<>();
}
}
@Override
public void onFailure(Call<List<Product>> call, Throwable t) {
Log.i("REQUEST","FAILED");
productList = new ArrayList<>();
}
});
}
return productList;