Issue
basically my code is about displaying user data on a recyclerView, & when clicked, would intent to an activity that displays more of that particular user's data.
onClickListener works fine if I do not use the searchView. It intents the correct data.
However, when using searchView, when first result is clicked, it always takes the data of the first item of the recyclerView that was displayed before i entered any searchView query, and so on for positions 2,3,4...
Adapter Class
public class OwnerAdapter extends RecyclerView.Adapter<OwnerAdapter.ViewHolder> {
private final RecyclerInterface recyclerInterface;
private ArrayList<Owners> ownerList;
public OwnerAdapter(ArrayList<Owners> ownerList, RecyclerInterface recyclerInterface){
this.recyclerInterface = recyclerInterface;
this.ownerList = ownerList;
}
public void setFilteredList(ArrayList<Owners> filteredList) {
this.ownerList = filteredList;
notifyDataSetChanged();
}
@NonNull
@Override
public OwnerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.owner_recycler_row, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull OwnerAdapter.ViewHolder holder, int position) {
int resource = R.drawable.ic_baseline_person_24;
String name=ownerList.get(position).getOwner_name();
int owner_num = ownerList.get(position).getOwner_number();
String category = ownerList.get(position).getCategory();
holder.setData(resource,name,owner_num,category);
}
@Override
public int getItemCount() {
return ownerList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private ImageView imageView;
private TextView tvName, tvOwner_num, tvCategory;
public ViewHolder(@NonNull View itemView) {
super(itemView);
imageView=itemView.findViewById(R.id.imageview1);
tvName=itemView.findViewById(R.id.tvName);
tvOwner_num=itemView.findViewById(R.id.tvOwner_num);
tvCategory=itemView.findViewById(R.id.tvCategory);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (recyclerInterface != null) {
int pos = getAdapterPosition();
if (pos != RecyclerView.NO_POSITION){
recyclerInterface.onRecyclerClick(pos);
}
}
}
});
}
public void setData(int resource, String name, int owner_num, String category) {
imageView.setImageResource(resource);
tvName.setText(name);
tvOwner_num.setText(Integer.toString(owner_num));
tvCategory.setText(category);
}
}
}
ViewOwners Class (displays the recycler view)
public class ViewOwnerDetails extends AppCompatActivity implements RecyclerInterface {
RecyclerView recyclerView;
LinearLayoutManager layoutManager;
OwnerAdapter ownerAdapter;
ArrayList<Owners> ownerList = new ArrayList<>();
ArrayList<Owners> filteredList = new ArrayList<>();
private SearchView searchView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.owner_recylcer_view);
new ViewOwnerDetails.Async().execute();
searchView = findViewById(R.id.searchView);
searchView.clearFocus();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
filteredList.clear();
filterList(newText);
return true;
}
});
}
class Async extends AsyncTask<Void, Void, Void> {
ProgressDialog pd;
@Override
protected void onPreExecute() { //before completing task
//loading message
super.onPreExecute();
pd = new ProgressDialog(ViewOwnerDetails.this);
pd.setMessage("Loading");
pd.show();
}
@Override
protected Void doInBackground(Void... voids) { //
load(); //load data to userList
return null;
}
@Override
protected void onPostExecute(Void aVoid) { //after completing task
initRecyclerView();
pd.dismiss();
}
}
public void load() {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://0104-acrs.mysql.database.azure.com:3306/azuredb", "VSVP", "VVSP0104!");
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("SELECT * FROM owner_data O INNER JOIN category C on O.catId = C.cat_id;");
while (rs.next()) {
String category = rs.getString("cat_name"), owner_name = rs.getString("owner_name");
int owner_num = rs.getInt("owner_num");
Boolean enabled = rs.getBoolean("isEnabled");
Owners owner = new Owners(owner_name, category, enabled, owner_num);
ownerList.add(owner);
Log.i("hi", "load: " + ownerList);
}
} catch (Exception e) {
Log.i("hi", "ERROR: " + e.getMessage());
}
}
private void initRecyclerView() {
recyclerView = findViewById(R.id.recyclerView);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
ownerAdapter = new OwnerAdapter(ownerList, this);
recyclerView.setAdapter(ownerAdapter);
ownerAdapter.notifyDataSetChanged();
}
public void onRecyclerClick(int position) {
Intent intent = new Intent(ViewOwnerDetails.this, ViewFullOwnerDetails.class);
if(searchView.toString().isEmpty()) {
intent.putExtra("NAME", ownerList.get(position).getOwner_name());
intent.putExtra("OWNER_NUM", ownerList.get(position).getOwner_number());
intent.putExtra("CATEGORY", ownerList.get(position).getCategory());
intent.putExtra("ENABLED", ownerList.get(position).isEnabled());
} else if(!searchView.toString().isEmpty()){
intent.putExtra("NAME", filteredList.get(position).getOwner_name());
intent.putExtra("OWNER_NUM", filteredList.get(position).getOwner_number());
intent.putExtra("CATEGORY", filteredList.get(position).getCategory());
intent.putExtra("ENABLED", filteredList.get(position).isEnabled());
}
startActivity(intent);
}
private void filterList(String text) {
for(Owners o : ownerList){
if(o.getOwner_name().toLowerCase().contains(text.toLowerCase())){
filteredList.add(o);
}
}
if(filteredList.isEmpty()) {
Toast.makeText(this, "No results found", Toast.LENGTH_SHORT).show();
} else {
ownerAdapter.setFilteredList(filteredList);
}
}
}
ViewFullOwnerInfo Class (to be intented to after clicking recyclerView item)
public class ViewFullOwnerDetails extends AppCompatActivity {
TextView tvTitle, tvName, tvOwner_num, tvCategory, tvMember;
Button btBack, btEdit, btDeleteOwner, btView;
ArrayList<String> associatedList = new ArrayList<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.full_owner_details);
initComponents();
intentData();
new asyncsetUpAssociatedList().execute();
btBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(ViewFullOwnerDetails.this, ViewOwnerDetails.class);
startActivity(intent);
}
});
btDeleteOwner.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
deleteConfirmationOwner();
}
});
btEdit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(ViewFullOwnerDetails.this, ViewOwnerDetails.class);
startActivity(intent);
}
});
btView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewDialog(associatedList);
}
});
}
public void intentData() {
String name = getIntent().getStringExtra("NAME");
int owner_num = getIntent().getIntExtra("OWNER_NUM", 0);
String category = getIntent().getStringExtra("CATEGORY");
Boolean enabled = getIntent().getBooleanExtra("ENABLED", false);
tvTitle.setText("FULL INFORMATION");
tvName.setText(name);
tvOwner_num.setText(String.valueOf(owner_num));
tvCategory.setText(category);
if (enabled.toString() == "false") {
tvMember.setText("Membership Disabled");
} else if (enabled.toString() == "true") {
tvMember.setText("Membership Enabled");
}
}
private void initComponents() {
tvTitle = (TextView) findViewById(R.id.tvTitle);
tvName = (TextView) findViewById(R.id.tvName);
tvOwner_num = (TextView) findViewById(R.id.tvCategory);
tvCategory = (TextView) findViewById(R.id.tvOwner_num);
tvMember = (TextView) findViewById(R.id.tvMember);
btBack = (Button) findViewById(R.id.btBack);
btDeleteOwner = (Button) findViewById(R.id.buttonDeleteOwner);
btEdit = (Button) findViewById(R.id.btResolve);
btView = (Button) findViewById(R.id.btViewVehicles);
}
private void viewDialog(List<String> associatedList) {
String output = "";
if (associatedList.isEmpty()) {
output = "List empty";
} else {
for (int i = 0; i < associatedList.size(); i++) {
String vehicle = associatedList.get(i);
output += vehicle + "\n";
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("ASSOCIATED VEHICLES: \n" + output)
.setPositiveButton("Close", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog alertDialog = builder.create();
alertDialog.show();
}
private void deleteConfirmationOwner() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Are you sure you want to delete this Owner? It will delete all related vehicles also")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new ViewFullOwnerDetails.asyncDeleteOwner().execute();
Intent intent = new Intent(ViewFullOwnerDetails.this, ViewOwnerDetails.class);
startActivity(intent);
Toast.makeText(ViewFullOwnerDetails.this, "Delete Succesful!", Toast.LENGTH_LONG).show();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog alertDialog = builder.create();
alertDialog.show();
}
class asyncDeleteOwner extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... voids) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("url", "user", "pass");
String query = String.format("DELETE FROM owner_data WHERE owner_num = '%d'", Integer.parseInt(tvOwner_num.getText().toString()));
PreparedStatement statement = conn.prepareStatement(query);
statement.executeUpdate();
} catch (Exception e) {
}
return null;
}
}
class asyncsetUpAssociatedList extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("url", "pass", "user");
Statement statement = conn.createStatement();
//String query = String.format("SELECT * FROM vehicle_data V INNER JOIN owner_data O on O.owner_num = V.owner_num WHERE V.owner_num = '%d'", Integer.parseInt(tvOwner_num.getText().toString()));
ResultSet rs = statement.executeQuery("SELECT * FROM owner_data O INNER JOIN category C on O.catId = C.cat_id;");
while (rs.next()) {
String reg_num = rs.getString("reg_num");
associatedList.add(reg_num);
}
} catch (Exception e) {
Log.i("v", "Error: " + e.getMessage());
}
return null;
}
}
}
error when i click on recyclerView item without search query:
2022-08-01 18:13:39.119 26727-26727/? E/.example.acrs3: Unknown bits set in runtime_flags: 0x8000
2022-08-01 18:13:39.828 26727-26727/com.example.acrs30 E/RecyclerView: No adapter attached; skipping layout
2022-08-01 18:13:41.039 26727-26727/com.example.acrs30 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.acrs30, PID: 26727
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.get(ArrayList.java:437)
at com.example.acrs30.ViewOwnerDetails.onRecyclerClick(ViewOwnerDetails.java:131)
at com.example.acrs30.OwnerAdapter$ViewHolder$1.onClick(OwnerAdapter.java:73)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Solution
when using searchView, when first result is clicked, it always takes the data of the first item of the recyclerView that was displayed before i entered any searchView query, and so on for positions 2,3,4...
This means that your recyclerView list is not getting updated properly when you search for an item. The list you are showing in the search view is different than the list that you are making changes to upon clicking.
public void onRecyclerClick(int position) {
Intent intent = new Intent(ViewOwnerDetails.this, ViewFullOwnerDetails.class);
intent.putExtra("NAME", ownerList.get(position).getOwner_name());
intent.putExtra("OWNER_NUM", ownerList.get(position).getOwner_number());
intent.putExtra("CATEGORY", ownerList.get(position).getCategory());
intent.putExtra("ENABLED", ownerList.get(position).isEnabled());
startActivity(intent);
}
So, the problem here is you are accessing the first item of your ownerList which is not the same as the filtered list. So, in order to get the correct item, you should access the filtered list rather than ownerList. You can initialise the filteredList for the whole activity and then you can use recyclerView on click accordingly. If the search view is empty, you can access items from ownerList and if it is not, you can access items from filtered list.
Answered By - Arsh
Answer Checked By - Senaida (JavaFixing Volunteer)