我一直在我的recyclerview中使用我的搜索过滤器面对NPE。我的搜索过滤器在我的自定义工具栏中,每当我尝试在searchview中输入内容时,应用程序崩溃。我已经提供了以下代码..
空指针异常
java.lang.NullPointerException: Attempt to invoke virtual method 'android.widget.Filter com.cvsuimus.theflare.NewsArticleAdapter.getFilter()' on a null object reference
at com.cvsuimus.theflare.MainPageActivity$1.onQueryTextChange(MainPageActivity.java:101)
MainPageActivity.Java
public class MainPageActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
public SearchView searchView;
public NewsArticleAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_page);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
RecentNewsFragment recentNewsFragment = new RecentNewsFragment();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.mainLayout, recentNewsFragment, recentNewsFragment.getTag()).commit();
}
long lastPress;
@Override
public void onBackPressed() {
long currentTime = System.currentTimeMillis();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
// close search view on back button pressed
if (!searchView.isIconified()) {
searchView.setIconified(true);
return;
}
else if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else if (currentTime - lastPress > 5000) {
Toast.makeText(getBaseContext(), "Press back once more to exit", Toast.LENGTH_LONG).show();
lastPress = currentTime;
}
else {
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory( Intent.CATEGORY_HOME );
homeIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(homeIntent);
}
super.onBackPressed();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_page, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
MenuItem searchMenuItem = menu.findItem(R.id.action_search);
searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem);
if (searchManager != null) {
searchView.setSearchableInfo(searchManager.getSearchableInfo(new ComponentName(getApplicationContext(), MainPageActivity.class)));
}
searchView.setMaxWidth(Integer.MAX_VALUE);
// listening to search query text change
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
// filter recycler view when query submitted
adapter.getFilter().filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String query) {
// filter recycler view when text is changed
adapter.getFilter().filter(query);
return false;
}
});
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_search) {
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_recent) {
setTitle("Recent News");
RecentNewsFragment recentNewsFragment = new RecentNewsFragment();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.mainLayout, recentNewsFragment, recentNewsFragment.getTag()).commit();
} else if (id == R.id.nav_favorites) {
setTitle("Favorite News");
FavoriteNewsFragment favoriteNewsFragment = new FavoriteNewsFragment();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.mainLayout, favoriteNewsFragment, favoriteNewsFragment.getTag()).commit();
} else if (id == R.id.nav_forum) {
setTitle("Recent Topics");
ForumFragment forumFragment = new ForumFragment();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.mainLayout, forumFragment, forumFragment.getTag()).commit();
} else if (id == R.id.nav_games) {
setTitle("Games");
GamesFragment gamesFragment = new GamesFragment();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.mainLayout, gamesFragment, gamesFragment.getTag()).commit();
}
else if (id == R.id.nav_account) {
AccountSettingsFragment accountSettingsFragment = new AccountSettingsFragment();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.mainLayout, accountSettingsFragment, accountSettingsFragment.getTag()).commit();
} else if (id == R.id.nav_settings) {
} else if (id == R.id.nav_logout) {
SharedPreferences pref = getSharedPreferences(StartupActivity.PREFS_NAME, MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.remove("studentNumber");
editor.remove("password");
editor.apply();
Intent in = new Intent(getApplicationContext(), StartupActivity.class);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(in);
} else if (id == R.id.nav_about_us) {
Intent in = new Intent(getApplicationContext(), AboutUsActivity.class);
startActivity(in);
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
RecentNewsFragment.Java
public class RecentNewsFragment extends Fragment implements ConnectivityReceiver.ConnectivityReceiverListener, NewsArticleAdapter.NewsArticleAdapterListener {
public RecentNewsFragment() {
}
final String TAG = "MainPageActivity";
public RecyclerView rvNewsArticle;
public ArrayList<News> newsArrayList;
public NewsArticleAdapter.NewsArticleAdapterListener listener;
public SwipeRefreshLayout swipeRefreshLayout;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_recent_news, container, false);
checkConnection();
rvNewsArticle = (RecyclerView) view.findViewById(R.id.rvNewsArticle);
rvNewsArticle.setHasFixedSize(true);
final LinearLayoutManager manager = new LinearLayoutManager(getActivity());
rvNewsArticle.setLayoutManager(manager);
swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefresh);
swipeRefreshLayout.setColorSchemeResources(R.color.primaryColor, R.color.primaryTextColor, R.color.secondaryColor);
swipeRefreshLayout.setSize(SwipeRefreshLayout.LARGE);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
loadNews();
}
}, 1000);
}
});
return view;
}
private void loadNews() {
String ip = IPAddress.ipaddress;
String url = "http://" + ip + "/theflare/app/news.php";
StringRequest stringRequest = new StringRequest(Request.Method.GET,
url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d(TAG, response);
ArrayList<News> newsList = new JsonConverter<News>()
.toArrayList(response, News.class);
final NewsArticleAdapter adapter = new NewsArticleAdapter(getActivity(), newsList, listener);
newsArrayList = new ArrayList<>();
// adding news to news list
newsArrayList.clear();
newsArrayList.addAll(newsList);
// refreshing recycler view
adapter.notifyDataSetChanged();
rvNewsArticle.setAdapter(adapter);
swipeRefreshLayout.setRefreshing(false);
FileCacher<ArrayList<News>> newsCacher = new FileCacher<>(getActivity(), "theflarenewscache.txt");
try {
newsCacher.appendOrWriteCache(newsList);
} catch (IOException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
if (error != null) {
Snackbar snackbar = Snackbar
.make(getActivity().findViewById(android.R.id.content), "Something went wrong.", Snackbar.LENGTH_INDEFINITE)
.setAction("Retry", new View.OnClickListener() {
@Override
public void onClick(View view) {
loadNews();
}
});
View sbView = snackbar.getView();
sbView.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.maroon));
snackbar.show();
}
}
}
);
MySingleton.getInstance(getActivity()).addToRequestQueue(stringRequest);
}
@Override
public void onContactSelected(News news) {
Toast.makeText(getContext(), "Selected: " + news.getTitle() + ", " + news.getAuthor(), Toast.LENGTH_LONG).show();
}
private void loadCachedNews() {
FileCacher<ArrayList<News>> newsCacher = new FileCacher<>(getActivity(), "theflarenewscache.txt");
if(newsCacher.hasCache()){
try {
ArrayList<News> cachedNewsList = newsCacher.readCache();
final NewsArticleAdapter adapter = new NewsArticleAdapter(getActivity(), cachedNewsList, listener);
//rvNewsArticle.setAdapter(adapter);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassCastException e){
e.printStackTrace();
}
}
}
// Method to manually check connection status
private void checkConnection() {
boolean isConnected = isConnected();
snackInternet(isConnected);
}
private void snackInternet(boolean isConnected) {
if (isConnected) {
Snackbar snackbar = Snackbar.make(getActivity().findViewById(android.R.id.content), "Connected to the Internet!", Snackbar.LENGTH_SHORT);
View sbView = snackbar.getView();
sbView.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.primaryDarkColor));
snackbar.show();
loadNews();
}
else {
Snackbar snackbar = Snackbar
.make(getActivity().findViewById(android.R.id.content), "You seem to be offline.", Snackbar.LENGTH_INDEFINITE)
.setAction("Retry", new View.OnClickListener() {
@Override
public void onClick(View view) {
loadNews();
}
});
View sbView = snackbar.getView();
sbView.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.maroon));
snackbar.show();
loadCachedNews();
}
}
@Override
public void onResume() {
super.onResume();
// register connection status listener
TheFlare.getInstance().setConnectivityListener(this);
}
/**
* Callback will be triggered when there is change in
* network connection
*/
@Override
public void onNetworkConnectionChanged(boolean isConnected) {
snackInternet(isConnected);
}
}
NewsArticleAdapter.Java
public class NewsArticleAdapter extends RecyclerView.Adapter<NewsArticleAdapter.NewsViewHolder> implements Filterable {
private Context context;
public ArrayList<News> news, filteredNews;
private NewsArticleAdapterListener listener;
//ViewHolder class
public class NewsViewHolder extends RecyclerView.ViewHolder{
public CardView cvNews;
public TextView tvId;
public ImageView ivImage;
public TextView tvTitle;
public TextView tvPubDate;
public NewsViewHolder(View itemView) {
super(itemView);
cvNews = (CardView)itemView.findViewById(R.id.cvNews);
tvId = (TextView) itemView.findViewById(R.id.tvId);
ivImage = (ImageView)itemView.findViewById(R.id.ivImageUrl);
tvTitle = (TextView)itemView.findViewById(R.id.tvTitle);
tvPubDate = (TextView)itemView.findViewById(R.id.tvPubDate);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// send selected news article in callback
listener.onContactSelected(filteredNews.get(getAdapterPosition()));
}
});
}
}
public NewsArticleAdapter(Context context, ArrayList<News> news, NewsArticleAdapterListener listener){
this.context = context;
this.news = news;
this.filteredNews = news;
this.listener = listener;
}
@Override
public NewsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.from(parent.getContext())
.inflate(R.layout.news_cardview_layout, parent, false);
NewsViewHolder newsViewHolder = new NewsViewHolder(view);
return newsViewHolder;
}
@Override
public void onBindViewHolder(NewsViewHolder holder, int position) {
final News selectedNews = news.get(position);
holder.tvId.setText(String.valueOf(selectedNews.id));
holder.tvTitle.setText(selectedNews.title);
holder.tvPubDate.setText(selectedNews.publicationDate);
String ip = IPAddress.ipaddress;
String fullUrl = "http://" + ip + "/theflare/admin/img/newsbanner/" + selectedNews.imgBanner;
Picasso.with(context)
.load(fullUrl)
.placeholder(R.drawable.bannerplaceholder)
.error(android.R.drawable.stat_notify_error)
.into(holder.ivImage);
holder.ivImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick (View view) {
Intent intent = new Intent(context, NewsDetailActivity.class);
intent.putExtra("news", selectedNews);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
if(news != null){
return news.size();
}
return 0;
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
filteredNews = news;
} else {
ArrayList<News> filteredList = new ArrayList<>();
for (News row : news) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if ( (row.getTitle().toLowerCase().contains(charString.toLowerCase())) ||
(row.getCategory().toLowerCase().contains(charString.toLowerCase())) ||
(row.getContent().toLowerCase().contains(charString.toLowerCase())) ||
(row.getAuthor().toLowerCase().contains(charString.toLowerCase())) ) {
filteredList.add(row);
}
}
filteredNews = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = filteredNews;
return filterResults;
}
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
filteredNews = (ArrayList<News>) filterResults.values;
notifyDataSetChanged();
}
};
}
public interface NewsArticleAdapterListener {
void onContactSelected(News news);
}
}
main_page.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.cvsuimus.theflare.MainPageActivity">
<item
android:id="@+id/action_search"
android:icon="@android:drawable/ic_menu_search"
android:orderInCategory="100"
android:title="@android:string/search_go"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always" />
</menu>
fragment_recent_news.xml
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.cvsuimus.theflare.RecentNewsFragment">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefresh"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="@+id/rvNewsArticle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>
的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.cvsuimus.theflare">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".TheFlare"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".LoginActivity"
android:label="@string/app_name" />
<activity
android:name=".RegisterActivity"
android:label="Sign Up"
android:parentActivityName=".LoginActivity" />
<activity
android:name=".MainPageActivity"
android:label="@string/title_activity_main_page"
android:theme="@style/AppTheme.NoActionBar">
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable"
android:value=".activities.MainPageActivity" />
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
</activity>
<activity
android:name=".StartupActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".AboutUsActivity"
android:label="@string/title_activity_about_us"
android:parentActivityName=".MainPageActivity" />
<activity
android:name=".ResetPasswordActivity"
android:label="@string/reset_pw"
android:parentActivityName=".MainPageActivity" />
<activity
android:name=".NewsDetailActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:parentActivityName=".MainPageActivity"
android:theme="@style/AppTheme.NoActionBar" />
<receiver
android:name=".ConnectivityReceiver"
android:enabled="true">
<intent-filter>
<action
android:name="android.net.conn.CONNECTIVITY_CHANGE"
tools:ignore="BatteryLife" />
</intent-filter>
</receiver>
<activity
android:name=".TopicCommentsActivity"></activity>
</application>
</manifest>
我还在proguard-rules.pro
文件中添加了这一行:
-keep class android.support.v7.widget.SearchView { *; }
我也遵循了这个答案,不幸的是,我没有成功: https://stackoverflow.com/a/18942838/8586704
我错过了什么或者我的代码有问题吗?感谢。
答案 0 :(得分:2)
只需更改您的getItemCount()
代码,它就会对您有用。您正在使用filteredNews
进行操作,因此您必须在所有地方使用filteredNews
而不是news
:
@Override
public int getItemCount() {
if(filteredList != null){
return filteredList.size();
}
return 0;
}
并在你的onBindViewHolder中:(使用filteredList
代替news
)
@Override
public void onBindViewHolder(NewsViewHolder holder, int position) {
final News selectedNews = filteredList.get(position);
holder.tvId.setText(String.valueOf(selectedNews.id));
holder.tvTitle.setText(selectedNews.title);
holder.tvPubDate.setText(selectedNews.publicationDate);
String ip = IPAddress.ipaddress;
String fullUrl = "http://" + ip + "/theflare/admin/img/newsbanner/" + selectedNews.imgBanner;
Picasso.with(context)
.load(fullUrl)
.placeholder(R.drawable.bannerplaceholder)
.error(android.R.drawable.stat_notify_error)
.into(holder.ivImage);
holder.ivImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick (View view) {
Intent intent = new Intent(context, NewsDetailActivity.class);
intent.putExtra("news", selectedNews);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
}