将新数据添加到 arrayList 时出现奇怪的数组适配器问题

Weird Array-adapter issue when adding new data to arrayList

我似乎遇到了一个奇怪的问题。我有一个带有自定义适配器的 ArrayList,该适配器具有 5 个文本视图。我可以在第一次添加到这个列表中并保存它甚至重新加载它但是在重新加载它之后我的 Adapter class 在尝试添加另一个项目时在 getter 方法上抛出一个空指针到列表中。 NUll 指针我知道,但问题是来自尝试将另一个项目添加到列表中吗?我的适配器 class 只适用于 1 个视图吗?我不知道为什么它是空的或者为什么它一开始是空的然后它不是。这是堆栈跟踪

更新堆栈跟踪

08-04 14:23:17.855 10000-10000/com.apklegion.cltoollog E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.apklegion.cltoollog, PID: 10000
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.util.ArrayList.get(int)' on a null object reference
    at com.apklegion.cltoollog.ToolListAdapter.getView(ToolListAdapter.java:34)
    at android.widget.AbsListView.obtainView(AbsListView.java:2346)
    at android.widget.ListView.measureHeightOfChildren(ListView.java:1281)
    at android.widget.ListView.onMeasure(ListView.java:1188)
    at android.view.View.measure(View.java:18805)
    at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:716)
    at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:462)
    at android.view.View.measure(View.java:18805)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
    at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:139)
    at android.view.View.measure(View.java:18805)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
    at android.support.v7.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:400)
    at android.view.View.measure(View.java:18805)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
    at android.view.View.measure(View.java:18805)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
    at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
    at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
    at android.view.View.measure(View.java:18805)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
    at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
    at android.view.View.measure(View.java:18805)
    at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2100)
    at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1216)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1452)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
    at android.view.Choreographer.doCallbacks(Choreographer.java:670)
    at android.view.Choreographer.doFrame(Choreographer.java:606)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5417)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

这里是适配器 class,它指出了错误。 已更新以反映当前错误

public class ToolListAdapter extends ArrayAdapter<Toolinfo> {

 private Context mcontext;
int mResource;

public ToolListAdapter(Context context, int resource, ArrayList<Toolinfo> 
objects) {
    super(context, resource, objects);
    mcontext = context;
    mResource = resource;
}

@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull 
ViewGroup parent) {

  -error is here>    String part_number = 
 objects.get(position).getPart_number();
    String serial_number = objects.get(position).getSerial_number();
    int employee_number = objects.get(position)).getEmployee_nummber();
    String date_out = objects.get(position).getOut_time();
    String date_in = objects.get(position).getIn_time();

    Toolinfo toolinfo = new Toolinfo(part_number,serial_number,employee_number,date_out,date_in);
    LayoutInflater layoutInflater = LayoutInflater.from(mcontext);
    convertView = layoutInflater.inflate(mResource,parent,false);

    TextView parnum = (TextView)convertView.findViewById(R.id.patnum);
    TextView sernum = (TextView)convertView.findViewById(R.id.sernum);
    TextView empnum = (TextView)convertView.findViewById(R.id.empnum);
    TextView timeout = (TextView)convertView.findViewById(R.id.timeout);
    TextView timein = (TextView)convertView.findViewById(R.id.timein);

    parnum.setText(part_number);
    sernum.setText(serial_number);
    empnum.setText(String.valueOf(employee_number));
    timeout.setText((date_out));
    timein.setText((date_in));
    return convertView;

}
}

这里是 getters 和 setter

public class Toolinfo {

private String part_number;
private String serial_number;
private int employee_nummber;
private String out_time;
private String in_time;


public Toolinfo(String part_number, String serial_number, int employee_nummber, String out_time, String in_time){
    this.part_number = part_number;
    this.serial_number = serial_number;
    this.employee_nummber = employee_nummber;
    this.out_time = out_time;
    this.in_time = in_time;



}

public String getPart_number() {
    return part_number;
}

public void setPart_number(String part_number) {
    this.part_number = part_number;
}

public String getSerial_number() {
    return serial_number;
}

public void setSerial_number(String serial_number) {
    this.serial_number = serial_number;
}

public int getEmployee_nummber() {
    return employee_nummber;
}

public void setEmployee_nummber(int employee_nummber) {
    this.employee_nummber = employee_nummber;
}

public String getOut_time() {
    return out_time;
}

public void setOut_time(String out_time) {
    this.out_time = out_time;
}

public String getIn_time() {
    return in_time;
}

public void setIn_time(String in_time) {
    this.in_time = in_time;
}

} 最后但并非最不重要的是 ArrayList 所在的主要 activity class 的相关位

public class MainActivity extends AppCompatActivity {

List<String> list = new ArrayList<>();
ArrayAdapter<String> adapter;
ListView listView;
Button button;
static  final int ADD_TOOL = 1;
CustomAdapter customAdapter;
public static final String PREFS_NAME = "MyPreferencesFile";
final String[] tools = {"30-200 Torque Wrench","Calipers","Push Pull Gague"};
String date_out,date_in;
String part_number,serial_number;
int employee_number;
Context context;
ArrayList<Toolinfo> toolinfos;
String currentDateandTime;
DatabaseHelper db;
Toolinfo tool1;

public 静态字符串标记 = "Main";

ToolListAdapter myadapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    toolinfos = new ArrayList<>();
    myadapter = new ToolListAdapter(this,R.layout.logrowlayout,toolinfos );





    loadData();


    button = findViewById(R.id.button);
    listView =  findViewById(R.id.listview);
    listView.setAdapter(myadapter);

    Intent getData = getIntent();
    if(getData.hasExtra("part number")&& getData.hasExtra("serial number") && getData.hasExtra("employee number")) {
        final String part_number = getData.getStringExtra("part number");
        showToast("has extras");

        String serial_number = getData.getStringExtra("serial number");
         showToast(serial_number);
        int employee_number = getData.getIntExtra("employee number", 0);
        // showToast(String.valueOf(employee_number));
        //addItems(part_number, serial_number, employee_number);

        SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy_HHmmss");
        String currentDateandTime = sdf.format(new Date());
        populateData(part_number,serial_number,employee_number,date_out,"out");

     }else {
    showToast("info not present");


}



    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            addTool();
        }
    });



}



public void populateData(String part_number,String serial_number,int employee_number, String date_out, String date_in) {
    //loadData();
    SimpleDateFormat sdf = new SimpleDateFormat("MMdd");
    String currentDateandTime = sdf.format(new Date());
    Toolinfo tool = new Toolinfo(part_number, serial_number, employee_number, currentDateandTime, "out");
    myadapter.add(tool);
    myadapter.notifyDataSetChanged();
    saveData(tool);

        for (int i = 0;  i < toolinfos.size(); i++) {
            Log.d(TAG, "populateData: " + toolinfos.get(i));


           //toolinfos.add(tool1);

        }

}

private  void saveData(Toolinfo tool1) {
    SharedPreferences preferences = getSharedPreferences("Shared prefs", MODE_PRIVATE);
    SharedPreferences.Editor editor = preferences.edit();
    Gson gson = new Gson();
    String json = gson.toJson(tool1);
    editor.putString("toolobj",json);
    showToast(json);
    editor.commit();



    //Log.i("tag",json.toString());
    editor.apply();
    showToast("Data Saved");

}
private void loadData(){
    SharedPreferences preferences = getSharedPreferences("Shared prefs", MODE_PRIVATE);
    Gson gson = new Gson();
    String json = preferences.getString("toolobj","");

    if (json == null){
        showToast("no data");

    }else {
        Toolinfo tool1 = gson.fromJson(json, Toolinfo.class);
        toolinfos.add(tool1);


    }




}
private void addTool(){

    Intent i = new Intent(MainActivity.this,Toolsignout.class);
    startActivity(i);
    saveData(tool1);



}
public void showToast(String msg){
    Toast.makeText(this,msg,Toast.LENGTH_LONG).show();
}

@Override
protected void onResume() {
  //  loadData();
    super.onResume();
}

}

在你的 ToolsListAdapter 中为 ArrayList<Toolinfo> objects; 添加 class 变量并分配类似于上下文。

然后在您的 getView() 方法中将 getItem(position) 更改为 objects.get(position)

您只保存一个对象并从 SharedPreferences 加载一个对象。

private  void saveData(Toolinfo tool1) {
    SharedPreferences preferences = getSharedPreferences("Shared prefs", MODE_PRIVATE);
    SharedPreferences.Editor editor = preferences.edit();
    Gson gson = new Gson();
    String json = gson.toJson(tool1);
    editor.putString("toolobj",json);
    showToast(json);
    editor.commit();

    editor.apply();
    showToast("Data Saved");

}
private void loadData(){
    SharedPreferences preferences = getSharedPreferences("Shared prefs", MODE_PRIVATE);
    Gson gson = new Gson();
    String json = preferences.getString("toolobj","");

    if (json == null){
        showToast("no data");
    }else {
        Toolinfo tool1 = gson.fromJson(json, Toolinfo.class);
        toolinfos.add(tool1);
    }
}

在您的加载方法中,json 永远不会等于 null。如果首选项没有得到对象,它将 return 一个空字符串。因此,将始终转到 else 块。现在,如果 json 不是有效的 json 或者它不能反序列化为 Toolinfo 对象,gson.fromJson 不会抛出任何异常。相反,它只会 return null。因此,您正在将 null 添加到您的列表中。

此外,请记住:
共享首选项是键值对。如果您想保存项目列表或记录,您可能需要查看数据库。

TL;DR
您的代码结构为仅保存一个值,您可以尝试将列表保存到共享首选项。将 load 方法上的 if 语句从检查 json 字符串是否为 null 更改为 empy。并且,在将对象添加到列表之前检查对象是否为空。