如何解决Androidstudio“尝试在空对象引用上调用虚拟方法”/

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (1616)

有以下错误:

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)

DisplayDatabase.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);
}
}

ProductAdapter.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]);
}
提问于
用户回答回答于

在调用Product.filter()方法之前未初始化ProductAdapter adapter;,当在onQueryTextChange中调用filter()时,适配器为NULL,因此出现了错误。如果ProductAdapter类声明为静态的,那么现在拥有的代码可能会正常工作,因为它不是必须在调用类中的方法之前创建类的新实例。

热门问答

主库的binlog被删掉了,从库是否可以用对应的Relay_Log_File同步?

朱明豪从事Oracle、MySQL等数据库工作10年,擅长性能诊断优化、故障处理、SQL优化、业务架构设计、技术培训等。
推荐
1.Waiting for Slave Workers to free pending events, 可能是出现大事务,可能参数slave_pending_jobs_size_max过小 2.“主库设置了expire_logs_days,所以从库的Relay_Mas...... 展开详请

CDN加速时,当带宽超出所设置阈值后关闭CDN服务,是否可以自动重启CDN服务?

开元

腾讯云 · 高级工程师 (已认证)

专注给云上客户提供优质的服务
推荐

触发封顶带宽导致域名关闭后,若您希望继续使用 CDN 服务,可以在重新启动域名加速。

详见https://cloud.tencent.com/document/product/228/7541

是否提供海外CDN加速服务(微信小程序云)?

开元

腾讯云 · 高级工程师 (已认证)

专注给云上客户提供优质的服务
推荐

目前腾讯云是支持海外加速的,CDN加速只和域名有关系,只需要把需要海外加速域名配置海外CDN就就可以。详细见:https://cloud.tencent.com/document/product/673

Dr.Elephant支持hadoop3吗?还有编译一直有包找不到怎么解决?

目前TBDS的hadoop版本是2.7.2,建议配置文件中使用该版本号进行匹配

iOS实时音视频的SDK和Demo有没有Objective-C版本?

腾讯视频云-ZacharyTXLiteAVSDK技术支持
推荐
下载专业版和企业版的压缩包里面带的官方demo是Objective-C的,下载地址:https://cloud.tencent.com/document/product/647/32689 image.png ... 展开详请

安卓APP使用免费版加固后,在Android11系统上运行闪退,是什么原因?

hello,目前已经适配了Android R Beta1,预计这周内上线移动应用安全在线版,请留意日志更新

所属标签

扫码关注云+社区

领取腾讯云代金券