英文:
CS50 Android Track Filter will not run in device despite building without errors
问题
这是我的PokedexAdapter.java文件,其中在底部添加了筛选函数:
package edu.harvard.cs50.pokedex;
import android.content.Context;
// ...(省略其他导入语句)
public class PokedexAdapter extends RecyclerView.Adapter<PokedexAdapter.PokedexViewHolder> implements Filterable {
// ...(省略其他代码)
@Override
public Filter getFilter() {
return new PokemonFilter();
}
private class PokemonFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
// implement your search here!
FilterResults results = new FilterResults();
if (constraint == null || constraint.length() == 0) {
// returns whole list if nothing is entered
results.values = pokemon;
results.count = pokemon.size();
} else {
List<Pokemon> filteredPokemon = new ArrayList<>();
for (Pokemon name : pokemon) {
if (name.getName().toUpperCase().startsWith(constraint.toString().toUpperCase())) {
filteredPokemon.add(name);
}
}
results.values = filteredPokemon;
results.count = filteredPokemon.size();
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
List<Pokemon> filtered = (List<Pokemon>) results.values;
notifyDataSetChanged();
}
}
}
这是如何在MainActivity.java中实现的:
package edu.harvard.cs50.pokedex;
import androidx.appcompat.app.AppCompatActivity;
// ...(省略其他导入语句)
public class MainActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {
// ...(省略其他代码)
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
@Override
public boolean onQueryTextSubmit(String newText) {
adapter.getFilter().filter(newText);
return false;
}
}
英文:
I am trying to implement the filter function in the Pokedex app, and although the app "Builds" without any errors, when I go to run it within the virtual Android phone, I get the error "Pokedex Keeps Stopping," on the virtual device. Since my code builds correctly, I cannot really figure out why it would continue to crash on the virtual device. Any help will be appreciated!
Here is my PokedexAdapter.java file, with the filter function added at the bottom:
package edu.harvard.cs50.pokedex;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
public class PokedexAdapter extends RecyclerView.Adapter<PokedexAdapter.PokedexViewHolder> implements Filterable {
public static class PokedexViewHolder extends RecyclerView.ViewHolder {
public LinearLayout containerView;
public TextView textView;
PokedexViewHolder(View view) {
super(view);
containerView = view.findViewById(R.id.pokedex_row);
textView = view.findViewById(R.id.pokedex_row_text_view);
containerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Pokemon current = (Pokemon) containerView.getTag();
Intent intent = new Intent(v.getContext(), PokemonActivity.class);
intent.putExtra("url", current.getUrl());
v.getContext().startActivity(intent);
}
});
}
}
private List<Pokemon> pokemon = new ArrayList<>();
private RequestQueue requestQueue;
PokedexAdapter(Context context) {
requestQueue = Volley.newRequestQueue(context);
loadPokemon();
}
public void loadPokemon() {
String url = "https://pokeapi.co/api/v2/pokemon?limit=151";
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
JSONArray results = response.getJSONArray("results");
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
String name = result.getString("name");
pokemon.add(new Pokemon(
name.substring(0, 1).toUpperCase() + name.substring(1),
result.getString("url")
));
}
notifyDataSetChanged();
} catch (JSONException e) {
Log.e("cs50", "Json error", e);
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("cs50", "Pokemon list error", error);
}
});
requestQueue.add(request);
}
@NonNull
@Override
public PokedexViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.pokedex_row, parent, false);
return new PokedexViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull PokedexViewHolder holder, int position) {
Pokemon current = pokemon.get(position);
holder.textView.setText(current.getName());
holder.containerView.setTag(current);
}
@Override
public int getItemCount() {
return pokemon.size();
}
@Override
public Filter getFilter() {
return new PokemonFilter();
}
private class PokemonFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
// implement your search here!
FilterResults results = new FilterResults();
if (constraint == null || constraint.length() == 0) {
//returns whole list if nothing is entered
results.values = pokemon;
results.count = pokemon.size();
}
else {
List<Pokemon> filteredPokemon = new ArrayList<>();
for (Pokemon name : pokemon) {
if (name.getName().toUpperCase().startsWith(constraint.toString().toUpperCase())) {
filteredPokemon.add(name);
results.values = filteredPokemon; // you need to create this variable!
results.count = filteredPokemon.size();
}
}
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
List<Pokemon> filtered = (List<Pokemon>) results.values;
notifyDataSetChanged();
}
}
}
And here is how it is implemented in MainActivity.java:
package edu.harvard.cs50.pokedex;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.SearchView;
public class MainActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {
private RecyclerView recyclerView;
private PokedexAdapter adapter; //private RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recycler_view);
adapter = new PokedexAdapter(getApplicationContext());
layoutManager = new LinearLayoutManager(this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(layoutManager);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
@Override
public boolean onQueryTextSubmit(String newText) {
adapter.getFilter().filter(newText);
return false;
}
}
答案1
得分: 1
@Override
public void onBindViewHolder(@NonNull PokedexViewHolder holder, int position) {
if (filtered.isEmpty()) {
Pokemon current = pokemon.get(position);
holder.textView.setText(current.getName());
holder.containerView.setTag(current);
}else{
Pokemon current = filtered.get(position);
holder.textView.setText(current.getName());
holder.containerView.setTag(current);
}
}
@Override
public int getItemCount() {
if (filtered.isEmpty()) {
return pokemon.size();
}else {
return filtered.size();
}
}
在你的宝可梦图鉴适配器中使用这段代码代替
英文:
@Override
public void onBindViewHolder(@NonNull PokedexViewHolder holder, int position) {
if (filtered.isEmpty()) {
Pokemon current = pokemon.get(position);
holder.textView.setText(current.getName());
holder.containerView.setTag(current);
}else{
Pokemon current = filtered.get(position);
holder.textView.setText(current.getName());
holder.containerView.setTag(current);
}
}
@Override
public int getItemCount() {
if (filtered.isEmpty()) {
return pokemon.size();
}else {
return filtered.size();
}
}
use this instead in your pokedex adapter
答案2
得分: 0
我曾遇到类似的问题,是由以下代码引起的:
@Override
public int getItemCount() {
return pokemon.size();
}
我认为可能会出现 pokemon 未初始化的情况,因此没有返回值(或等于 "null")。
我添加了一个条件语句,如果 pokemon 为 null,就返回 0:
@Override
public int getItemCount() {
if (pokemon != null) {
return pokemon.size();
} else {
return 0;
}
}
我还将变量名 pokemon 更改为保存筛选项目的数组列表的变量名。
英文:
I had a similar issue which was caused by the following :
@Override
public int getItemCount() {
return pokemon.size();
}
I believe it can happen that pokemon is not initiated and therefore doesn't have a return value (or equals "null")
I added an if statement that would just return 0 if pokemon is null
@Override
public int getItemCount() {
if (pokemon != null) {
return pokemon.size();
} else {
return 0;
}
}
I also have changed the variable name pokemon to the variable name of my Array List that holds the filtered items.
答案3
得分: 0
问题可能出现在您的导入部分。您有:
import android.widget.SearchView;
在您的MainActivity中。当我将该导入更改为以下内容时:
import androidx.appcompat.widget.SearchView;
一切似乎都正常工作。如果这行不通,那我就不知道了。
英文:
The issue (may) be in your imports. You have:
import android.widget.SearchView;
In your MainActivity. When I changed that import over to the following:
import androidx.appcompat.widget.SearchView;
Everything seemed to work. If that doesn't work, then I have no idea.
答案4
得分: 0
另外要做的一件事是,在onBindViewHolder和getItemCount中将变量"pokemon"更改为您存储的名为"filtered"的筛选数据变量。
同时,务必按照其他人所说,将导入android.widget.SearchView; 进行更改。
英文:
Other thing you have to do is change the variable "pokemon" in onBindViewHolder and in getItemCount to the variable you stored the filtered data called "filtered".
And it's mandatory to change import android.widget.SearchView; as the other person said.
答案5
得分: 0
cs50建议使用
@Override
protected void publishResults(CharSequence charSequence, FilterResults results) {
filtered = (List<Pokemon>) results.values;
notifyDataSetChanged();
}
但是如果你注意到,Android Studio会用灰色的高亮显示"filtered",提示你"filtered"从未被使用。
我一直在研究代码,试图找出问题出在哪里。代码能够编译和运行而没有任何错误只是意味着筛选已经成功执行(说实话,我不是100%确定,只是猜测),但由于某种原因搜索结果没有显示出来。
在注意到"filtered"被标记为灰色后,我碰碰运气,将"filtered"替换为"pokemon",因为最初发布的列表是"pokemon"。
我最终得到了以下代码
@Override
protected void publishResults(CharSequence charSequence, FilterResults results) {
pokemon = (List<Pokemon>) results.values;
notifyDataSetChanged();
}
现在一切都正常工作了。
另外,我确实按照第二个回答建议的方式更新了我的导入。
英文:
cs50 advised to use
@Override
protected void publishResults(CharSequence charSequence, FilterResults results) {
filtered = (List<Pokemon>) results.values;
notifyDataSetChanged();
}
but if you notice, android studio prompts you that filtered
was never used by highlighting filtered in grey.
I have been studying the code trying to figure out where the problem was. The fact that the code compiles and runs without any errors just means that the filtering was executed successfully (honestly I'm not 100% sure, I am just guessing) but for some reason the search result was not displayed.
After noticing that filtered
was greyed out, I tried my luck and replaced filtered
with pokemon
because the original list that was posted is pokemon
.
What I ended up with was
@Override
protected void publishResults(CharSequence charSequence, FilterResults results) {
pokemon = (List<Pokemon>) results.values;
notifyDataSetChanged();
}
and now everything works fine.
Also I did update my imports like what the second answer suggested
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论