java - 尝试在 ListView 上实现搜索时出现 NullpointerException

标签 java android nullpointerexception android-sqlite

我使用 AsyncTask 创建了一个 SQL 数据库,该数据库在一个 Activity 中接收输入并在另一个 Activity 中显示它们。现在我正在尝试学习如何使用搜索 View 在 ListView 中搜索数据库。

我有一个绑定(bind)到 ListView 的适配器类。其中有一个过滤功能,用于过滤搜索 View ,我认为这是错误的根源;因为错误发生在adapter.filter(s);处。

我的错误:

7167-7167/com.example.andrewg.sqltutorial E/AndroidRuntime: FATAL EXCEPTION: 
main
Process: com.example.andrewg.sqltutorial, PID: 7167
java.lang.NullPointerException: Attempt to invoke virtual method 'void 
com.example.andrewg.sqltutorial.ProductAdapter.filter(java.lang.String)' on a 
null object reference
    at
com.example.andrewg.sqltutorial.DisplayProduct$1.onQueryTextChange
(DisplayProduct.java:47)
    at android.widget.SearchView.onTextChanged(SearchView.java:1250)
    at android.widget.SearchView.access$2100(SearchView.java:98)
    at android.widget.SearchView$10.onTextChanged(SearchView.java:1776)
    at android.widget.TextView.sendOnTextChanged(TextView.java:9754)
    at android.widget.TextView.handleTextChanged(TextView.java:9851)
    at android.widget.TextView$ChangeWatcher.onTextChanged(TextView.java:12512)
    at android.text.SpannableStringBuilder.sendTextChanged(SpannableStringBuilder.java:1263)
    at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:575)
    at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:506)
    at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:36)
    at android.view.inputmethod.BaseInputConnection.replaceText(BaseInputConnection.java:843)
    at android.view.inputmethod.BaseInputConnection.setComposingText(BaseInputConnection.java:616)
    at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:396)
    at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:85)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6649)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:826)

显示数据库.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.SearchView;

public class DisplayProduct extends AppCompatActivity {

ListView listView;
ProductAdapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.display_product_layout);

    listView = findViewById(R.id.Display_listview);

    BackgroundTask backgroundTask = new BackgroundTask(this);
    backgroundTask.execute("get_info");

   //-----------------------------EDIT--------------------------------
   adapter = new ProductAdapter(this, R.layout.display_product_row);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu, menu);

    MenuItem myActionMenuItem = menu.findItem(R.id.action_search);
    SearchView searchView = (SearchView) myActionMenuItem.getActionView();
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String s) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String s) {

            if(TextUtils.isEmpty(s)){
                adapter.filter("");
                listView.clearTextFilter();
            }
            else{
                adapter.filter(s);
            }

            return true;
        }
    });

    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();

    if(id == R.id.action_settings){
        //do your functionality here
        return true;
    }

    return super.onOptionsItemSelected(item);
}
}

产品适配器.java

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class ProductAdapter extends ArrayAdapter {

List list = new ArrayList();

//Menu Search
Context context;
ArrayList<Product> productArrayList = new ArrayList<>();


public ProductAdapter(@NonNull Context context, int resource) {
    super(context, resource);
    this.context = context;
    this.productArrayList.addAll(list);
}

public void addList(ArrayList<Product> Oldarraylist){
    this.productArrayList = Oldarraylist;
}

public void add(Product object) {
    list.add(object);
    super.add(object);
}

@Override
public int getCount() {
    return list.size();
}

@Nullable
@Override
public Object getItem(int position) {
    return list.get(position);
}

@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    //Referencing each row as a View, which is an object
    View row = convertView;
    ProductHolder productHolder;

    if(row == null){
        //There is no view at this position, so we are creating a new one
        //In this case we are inflating an XML layout

        LayoutInflater layoutInflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = layoutInflater.inflate(R.layout.display_product_row, parent, false);

        //Locate the views in row.xml
        productHolder = new ProductHolder();
        productHolder.id = row.findViewById(R.id.ID);
        productHolder.name = row.findViewById(R.id.NAME);
        productHolder.price = row.findViewById(R.id.PRICE);
        productHolder.quantity = row.findViewById(R.id.QUANTITY);

        /*setTag is very useful for custom ArrayAdapter using. It is some kind of optimization.
         There setTag used as reference to object that references on some parts of layout
         (that displaying in ListView) instead of findViewById.
         */

        row.setTag(productHolder);
    }

    else{
        //We are recycling a view that already exists
        productHolder = (ProductHolder) row.getTag();
    }

    //Once we have a reference to the View we are returning, we set its values
    //Setting results into textviews

    Product product = (Product) getItem(position);
    productHolder.id.setText(product.getID().toString());
    productHolder.name.setText(product.getName().toString());
    productHolder.price.setText(Integer.toString(product.getPrice()));
    productHolder.quantity.setText(Integer.toString(product.getQuantity()));

    //Menu
    //Listview item clicks

    row.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

        }
    });

    return row;
}

//Menu
public void filter(String charText){
    charText = charText.toLowerCase(Locale.getDefault());
    list.clear();

    if(charText.length() == 0){
        list.addAll(productArrayList);
    }
    else{
        for (Product product : productArrayList){
            if(product.getName().toLowerCase(Locale.getDefault()).contains(charText)){
                list.add(product);
            }
        }
    }
    notifyDataSetChanged();
}

static class ProductHolder{

    TextView id, name, price, quantity;

}
}

我的 AsyncTask 线程中的相关代码

public class BackgroundTask extends AsyncTask<String,Product,String> {

Context context;
ProductAdapter productAdapter;
Activity activity;
ListView listView;

ArrayList<Product> arrayList = new ArrayList<>();

@Override
protected String doInBackground(String... params) {
    listView = activity.findViewById(R.id.Display_listview);
        SQLiteDatabase db = dbOperations.getReadableDatabase();
        Cursor cursor = dbOperations.getInformation(db);

        productAdapter = new ProductAdapter(context, 
  R.layout.display_product_row);

        String id, name;
        int price, quantity;

        while(cursor.moveToNext()){
            id = 
  cursor.getString(cursor.getColumnIndex(ProductContract.ProductEntry.ID));
            name = 
 cursor.getString(cursor.getColumnIndex(ProductContract.ProductEntry.NAME));
            price = 
 cursor.getInt(cursor.getColumnIndex(ProductContract.ProductEntry.PRICE));
            quantity = 
 cursor.getInt(cursor.getColumnIndex(ProductContract.ProductEntry.QUANTITY));

            Product product = new Product(id, name, price, quantity);

            publishProgress(product);
        }

        return "get_info";
}

@Override
protected void onPostExecute(String s) {
   //Bind the array adapter to the listview
   listView.setAdapter(productAdapter);
   productAdapter.addList(arrayList);

    @Override
protected void onProgressUpdate(Product... values) {
    productAdapter.add(values[0]);
    arrayList.add(values[0]);
}

最佳答案

正如 @Psypher 指出的,您必须初始化 ProductAdapter。但是,仅在 AsyncTask 中添加 ProductAdapter adapter = new ProductAdapter() 是行不通的,因为它引用的不是您之前创建的同一对象。

您需要首先创建适配器,然后将其传递到 AsyncTask(或使其静态)。

关于java - 尝试在 ListView 上实现搜索时出现 NullpointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50827409/

相关文章:

android.view.InflateException : Binary XML file line #2: Error inflating class fragment at android. app.ActivityThread.performLaunchActivity

android - 如何在listview android中设置所有值

java - 多重测试 TestNG.xml 文件导致 java.lang.NullPointerException

android - SQLiteDatabase close() 函数在多个线程时导致 NullPointerException

nullpointerexception - JavaFx : Error Cannot be ideantified

java - 如何动态获取文件夹路径?

java - Sonar : "Module is already part of project" or How to upload projects with same dependencies?

android - Mediaplayer没有声音

java - 根据每个元素值的总和拆分数组

java - 使用观察者模式是否合适?