活动介绍

package com.example.kucun2.ui.jinhuo; import static android.content.ContentValues.TAG; import android.app.AlertDialog; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.RadioGroup; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import com.example.kucun2.R; import com.example.kucun2.entity.*; import com.example.kucun2.entity.data.Data; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Random; public class AddInventoryFragment extends Fragment { private Spinner spinnerDingdan, spinnerChanpin, spinnerZujian, spinnerBancai; private EditText etShuliang; private RadioGroup rgType; private Dingdan selectedDingdan; private Chanpin selectedChanpin; private Zujian selectedZujian; private Bancai selectedBancai; // 创建新订单产品组件按钮 private Button btnNewDingdan, btnAddChanpin, btnAddZujian; /** * 初始化 * @param inflater The LayoutInflater object that can be used to inflate * any views in the fragment, * @param container If non-null, this is the parent view that the fragment's * UI should be attached to. The fragment should not add the view itself, * but this can be used to generate the LayoutParams of the view. * @param savedInstanceState If non-null, this fragment is being re-constructed * from a previous saved state as given here. * * @return */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_add_inventory, container, false); // 初始化UI组件 spinnerDingdan = view.findViewById(R.id.spinner_dingdan); spinnerChanpin = view.findViewById(R.id.spinner_chanpin); spinnerZujian = view.findViewById(R.id.spinner_zujian); spinnerBancai = view.findViewById(R.id.spinner_bancai); etShuliang = view.findViewById(R.id.et_shuliang); rgType = view.findViewById(R.id.rg_type); Button btnSubmit = view.findViewById(R.id.btn_submit); // 初始化新按钮 btnNewDingdan = view.findViewById(R.id.btn_new_dingdan); btnAddChanpin = view.findViewById(R.id.btn_add_chanpin); btnAddZujian = view.findViewById(R.id.btn_add_zujian); // 设置按钮点击事件 btnNewDingdan.setOnClickListener(v -> createNewDingdan()); btnAddChanpin.setOnClickListener(v -> addChanpinToDingdan()); btnAddZujian.setOnClickListener(v -> addZujianToChanpin()); // 设置订单选择器 setupDingdanSpinner(); // 提交按钮点击事件 btnSubmit.setOnClickListener(v -> addInventoryRecord()); return view; } private void setupDingdanSpinner() { // 定制订单适配器显示订单号(number) ArrayAdapter<Dingdan> dingdanAdapter = new ArrayAdapter<Dingdan>( requireContext(), android.R.layout.simple_spinner_item, Data.dingdans) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getView(position, convertView, parent); Dingdan dingdan = getItem(position); if (dingdan != null) { textView.setText(dingdan.getNumber()); } return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getDropDownView(position, convertView, parent); Dingdan dingdan = getItem(position); if (dingdan != null) { textView.setText(dingdan.getNumber()); } return textView; } }; dingdanAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerDingdan.setAdapter(dingdanAdapter); spinnerDingdan.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedDingdan = (Dingdan) parent.getItemAtPosition(position); setupChanpinSpinner(selectedDingdan); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupChanpinSpinner(Dingdan dingdan) { // 获取该订单的产品列表 List<Chanpin> chanpins = new ArrayList<>(); for (Dingdan_Chanpin dc : dingdan.getChanpins()) { chanpins.add(dc.getChanpin()); } // 定制产品适配器显示产品名(name) ArrayAdapter<Chanpin> chanpinAdapter = new ArrayAdapter<Chanpin>( requireContext(), android.R.layout.simple_spinner_item, chanpins) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { Log.d(TAG, "getView:position="+position+",convertView="+convertView+",parent="+parent); TextView textView = (TextView) super.getView(position, convertView, parent);//也是 convertView=null 就不报错 Chanpin chanpin = getItem(position); if (chanpin != null) { textView.setText(chanpin.getName()); } return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getDropDownView(position, convertView, parent); Chanpin chanpin = getItem(position); if (chanpin != null) { textView.setText(chanpin.getName()); } return textView; } }; chanpinAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerChanpin.setAdapter(chanpinAdapter); spinnerChanpin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedChanpin = (Chanpin) parent.getItemAtPosition(position); setupZujianSpinner(selectedChanpin); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupZujianSpinner(Chanpin chanpin) { // 获取该产品的组件列表 List<Zujian> zujians = new ArrayList<>(); for (Chanpin_Zujian cz : chanpin.getZujians()) { zujians.add(cz.getZujian()); } // 定制组件适配器显示组件名(name) ArrayAdapter<Zujian> zujianAdapter = new ArrayAdapter<Zujian>( requireContext(), android.R.layout.simple_spinner_item, zujians) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { Log.d(TAG, "getView:position="+position+",convertView="+convertView+",parent="+parent); TextView textView = (TextView) super.getView(position, convertView, parent);//也是 convertView=null 就不报错 Zujian zujian = getItem(position); if (zujian != null) { textView.setText(zujian.getName()); } return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getDropDownView(position, convertView, parent); Zujian zujian = getItem(position); if (zujian != null) { textView.setText(zujian.getName()); } return textView; } }; zujianAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerZujian.setAdapter(zujianAdapter); spinnerZujian.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedZujian = (Zujian) parent.getItemAtPosition(position); setupBancaiSpinner(selectedChanpin, selectedZujian); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupBancaiSpinner(Chanpin chanpin, Zujian zujian) { // 获取该组件关联的板材 List<Bancai> bancais = new ArrayList<>(); for (Chanpin_Zujian cz : chanpin.getZujians()) { if (cz.getZujian().getId().equals(zujian.getId())) { bancais.add(cz.getBancai()); } } // 定制板材适配器显示TableText(保持不变) ArrayAdapter<Bancai> bancaiAdapter = new ArrayAdapter<Bancai>( requireContext(), android.R.layout.simple_spinner_item, bancais) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { Log.d(TAG, "getView:position="+position+",convertView="+convertView+",parent="+parent); TextView textView = (TextView) super.getView(position, convertView, parent);// 点击添加组件才会一直报 convertView=null java.lang.NullPointerException Bancai bancai = getItem(position); if (bancai != null) { textView.setText(bancai.TableText()); } return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getDropDownView(position, convertView, parent); Bancai bancai = getItem(position); if (bancai != null) { textView.setText(bancai.TableText()); } return textView; } }; bancaiAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerBancai.setAdapter(bancaiAdapter); spinnerBancai.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedBancai = (Bancai) parent.getItemAtPosition(position); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } // ... addInventoryRecord和createRecord方法保持不变 ... private void addInventoryRecord() { // 验证必填项 if (selectedDingdan == null || selectedChanpin == null || selectedZujian == null || selectedBancai == null) { Toast.makeText(getContext(), "请选择订单、产品、组件和板材", Toast.LENGTH_SHORT).show(); return; } String shuliangStr = etShuliang.getText().toString().trim(); if (shuliangStr.isEmpty()) { Toast.makeText(getContext(), "请输入数量", Toast.LENGTH_SHORT).show(); return; } // 解析数量 int shuliang; try { shuliang = Integer.parseInt(shuliangStr); } catch (NumberFormatException e) { Toast.makeText(getContext(), "请输入有效的数量", Toast.LENGTH_SHORT).show(); return; } // 确定操作类型(进货或消耗) boolean isJinhuo = rgType.getCheckedRadioButtonId() == R.id.rb_jinhuo; // 实际开发中应从登录信息获取当前用户 User currentUser = new User(1, "当前用户", "user", "password",1); // 创建记录 createRecord(selectedDingdan, selectedChanpin, selectedZujian, selectedBancai, shuliang, isJinhuo, currentUser); Toast.makeText(getContext(), "记录添加成功", Toast.LENGTH_SHORT).show(); etShuliang.setText(""); // 清空输入框 } private void createRecord(Dingdan dingdan, Chanpin chanpin, Zujian zujian, Bancai bancai, int shuliang, boolean isJinhuo, User user) { if (isJinhuo) { // 创建进货记录 Jinhuo jinhuo = new Jinhuo(); jinhuo.setId(Data.jinhuoList.size() + 1); jinhuo.setDingdan(dingdan); jinhuo.setChanpin(chanpin); jinhuo.setZujian(zujian); jinhuo.setBancai(bancai); jinhuo.setShuliang(shuliang); jinhuo.setDate(new Date()); jinhuo.setUser(user); Data.jinhuoList.add(jinhuo); } else { // 消耗数量转为负数 shuliang = -shuliang; } // 更新库存 updateKucun(bancai, shuliang); } private void updateKucun(Bancai bancai, int changeAmount) { // 查找现有库存记录 for (Kucun k : Data.kucuns) { if (k.getBancai().getId().equals(bancai.getId())) { k.setShuliang(k.getShuliang() + changeAmount); return; } } // 如果没有找到库存记录,创建新的 Kucun newKucun = new Kucun(); newKucun.setId(Data.kucuns.size() + 1); newKucun.setBancai(bancai); newKucun.setShuliang(Math.max(changeAmount, 0)); // 确保不为负 Data.kucuns.add(newKucun); } // 新建订单方法 private void createNewDingdan() { // 创建新订单(示例:实际应弹窗或跳转页面) Dingdan newDingdan = new Dingdan(); newDingdan.setId( (Data.dingdans.size() + 1)); newDingdan.setNumber("新建订单" + System.currentTimeMillis()); newDingdan.setChanpins(new ArrayList<>()); Data.dingdans.add(newDingdan); // 刷新订单下拉框 setupDingdanSpinner(); spinnerDingdan.setSelection(Data.dingdans.size() - 1); Toast.makeText(getContext(), "新建订单成功", Toast.LENGTH_SHORT).show(); } // 为当前订单添加产品 private void addChanpinToDingdan() { if (selectedDingdan == null) { Toast.makeText(getContext(), "请先选择订单", Toast.LENGTH_SHORT).show(); return; } // 创建新产品(示例:实际应弹窗输入产品信息) Chanpin newChanpin = new Chanpin(); newChanpin.setId( (Data.chanpins.size() + 1)); newChanpin.setName("新产品" + System.currentTimeMillis()); newChanpin.setZujians(new ArrayList<>()); // 添加到全局列表 Data.chanpins.add(newChanpin); // 添加到当前订单的产品列表 Dingdan_Chanpin dc = new Dingdan_Chanpin(); dc.setId(selectedDingdan.getChanpins().size() + 1); dc.setChanpin(newChanpin); dc.setDingdan(selectedDingdan); selectedDingdan.getChanpins().add(dc); // 刷新产品下拉框 setupChanpinSpinner(selectedDingdan); spinnerChanpin.setSelection(selectedDingdan.getChanpins().size() - 1); Toast.makeText(getContext(), "产品添加成功", Toast.LENGTH_SHORT).show(); } // 为当前产品添加组件 private void addZujianToChanpin() { if (selectedChanpin == null) { Toast.makeText(getContext(), "请先选择产品", Toast.LENGTH_SHORT).show(); return; } // // 创建新组件(示例) // Zujian newZujian = new Zujian(); // newZujian.setId( (Data.zujians.size() + 1)); // newZujian.setName("新组件" + System.currentTimeMillis()); // // // 添加到全局列表 // Data.zujians.add(newZujian); // // // 添加到当前产品的组件列表 // Chanpin_Zujian cz = new Chanpin_Zujian(); // cz.setId(selectedChanpin.getZujians().size() + 1); // cz.setZujian(newZujian); // cz.setChanpin(selectedChanpin); // selectedChanpin.getZujians().add(cz); // // // 刷新组件下拉框 // setupZujianSpinner(selectedChanpin); // spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1); // // Toast.makeText(getContext(), "组件添加成功", Toast.LENGTH_SHORT).show(); showCreateZujianDialog(); } // 新建板材 private void createNewBancai() { // 创建新板材(示例) Random rand = new Random(12345); Bancai newBancai = new Bancai(); newBancai.setId((Data.bancais.size() + 1)); newBancai.setCaizhi(Data.bancais.get(rand.nextInt(Data.bancais.size()-1)).getCaizhi()); newBancai.setMupi1(Data.bancais.get(rand.nextInt(Data.bancais.size()-1)).getMupi1()); newBancai.setMupi2(Data.bancais.get(rand.nextInt(Data.bancais.size()-1)).getMupi2()); // 添加到全局列表 Data.bancais.add(newBancai); // 刷新板材下拉框 setupBancaiSpinner(selectedChanpin, selectedZujian); spinnerBancai.setSelection(Data.bancais.size() - 1); Toast.makeText(getContext(), "新建板材成功", Toast.LENGTH_SHORT).show(); } private void showCreateZujianDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("添加新组件和板材"); // 创建自定义布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_create_zujian_bancai, null); EditText etZujianName = dialogView.findViewById(R.id.et_zujian_name); Spinner spinnerCaizhi = dialogView.findViewById(R.id.spinner_caizhi); Spinner spinnerMupi1 = dialogView.findViewById(R.id.spinner_mupi1); Spinner spinnerMupi2 = dialogView.findViewById(R.id.spinner_mupi2); // 设置材质下拉框适配器(只显示名称) ArrayAdapter<Caizhi> caizhiAdapter = new ArrayAdapter<Caizhi>( requireContext(), android.R.layout.simple_spinner_item, Data.caizhis) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getView(position, convertView, parent); Caizhi caizhi = getItem(position); if (caizhi != null) { textView.setText(caizhi.getName()); } return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getDropDownView(position, convertView, parent); Caizhi caizhi = getItem(position); if (caizhi != null) { textView.setText(caizhi.getName()); } return textView; } }; caizhiAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerCaizhi.setAdapter(caizhiAdapter); // 设置木皮下拉框适配器(名称+油或不加) ArrayAdapter<Mupi> mupiAdapter = new ArrayAdapter<Mupi>( requireContext(), android.R.layout.simple_spinner_item, Data.mupis) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getView(position, convertView, parent); Mupi mupi = getItem(position); if (mupi != null) { textView.setText(mupi.formatMupiDisplay()); } return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getDropDownView(position, convertView, parent); Mupi mupi = getItem(position); if (mupi != null) { textView.setText(mupi.formatMupiDisplay()); } return textView; } }; mupiAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerMupi1.setAdapter(mupiAdapter); spinnerMupi2.setAdapter(mupiAdapter); // 添加木皮预览标签 builder.setPositiveButton("创建", (dialog, which) -> { // 获取用户输入 String zujianName = etZujianName.getText().toString().trim(); Caizhi selectedCaizhi = (Caizhi) spinnerCaizhi.getSelectedItem(); Mupi selectedMupi1 = (Mupi) spinnerMupi1.getSelectedItem(); Mupi selectedMupi2 = (Mupi) spinnerMupi2.getSelectedItem(); if (zujianName.isEmpty()) { Toast.makeText(getContext(), "请输入组件名称", Toast.LENGTH_SHORT).show(); return; } // 创建新组件 Zujian newZujian = new Zujian(); newZujian.setId(Data.zujians.size() + 1); newZujian.setName(zujianName); // 创建新板材 Bancai newBancai = new Bancai(); newBancai.setId(Data.bancais.size() + 1); newBancai.setCaizhi(selectedCaizhi); newBancai.setMupi1(selectedMupi1); newBancai.setMupi2(selectedMupi2); // 添加到全局列表 Data.zujians.add(newZujian); Data.bancais.add(newBancai); // 添加到当前产品的组件列表 Chanpin_Zujian cz = new Chanpin_Zujian(); cz.setId(selectedChanpin.getZujians().size() + 1); cz.setZujian(newZujian); cz.setBancai(newBancai); // 关联新创建的板材 cz.setChanpin(selectedChanpin); selectedChanpin.getZujians().add(cz); // 刷新组件下拉框 setupZujianSpinner(selectedChanpin); spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1); Toast.makeText(getContext(), "组件和板材添加成功", Toast.LENGTH_SHORT).show(); }); builder.setNegativeButton("取消", null); builder.show(); } }<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <EditText android:id="@+id/et_zujian_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入组件名称"/> <EditText android:id="@+id/et_bancai_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入板材名称(可选)" android:layout_marginTop="8dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="材质选择" android:layout_marginTop="16dp"/> <Spinner android:id="@+id/spinner_caizhi" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="木皮1" android:layout_marginTop="8dp"/> <Spinner android:id="@+id/spinner_mupi1" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="木皮2(可选)" android:layout_marginTop="8dp"/> <Spinner android:id="@+id/spinner_mupi2" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout>添加组件和板材页面显示没有下拉框

时间: 2025-08-04 19:58:36 浏览: 8
<think>我们正在处理一个AndroidFragment(AddInventoryFragment)的代码,用户报告在添加组件和板材的对话框中,材质和木皮的下拉框(Spinner)没有显示。问题出在对话框的布局文件(R.layout.dialog_create_zujian_bancai)中,用户提供的布局代码里确实有Spinner,但是运行时没有显示数据?或者根本看不到Spinner?从代码中,我们可以看到在`showCreateZujianDialog`方法中,我们创建了一个AlertDialog,并设置了自定义视图(dialog_create_zujian_bancai)。在这个视图里,有三个Spinner:spinner_caizhi,spinner_mupi1,spinner_mupi2。并且我们在代码中为它们设置了适配器(ArrayAdapter)。用户说“添加组件和板材页面显示没有下拉框”,可能的原因有:1.对话框的布局文件没有被正确加载,或者Spinner的id与代码中findViewById的id不匹配。2.适配器设置有问题,数据为空导致没有显示。3.对话框显示时发生了异常,但没有捕获,导致布局未正常显示。我们检查了代码,在设置适配器时,我们使用了:spinnerCaizhi.setAdapter(caizhiAdapter);spinnerMupi1.setAdapter(mupiAdapter);spinnerMupi2.setAdapter(mupiAdapter);数据源分别是Data.caizhis和Data.mupis,需要确保这两个数据源不为空。另外,在布局文件中,我们为每个Spinner都设置了,所以布局应该是正确的。可能的问题是在设置Spinner适配器时,使用了同一个mupiAdapter实例给两个Spinner,这通常是可以的,但需要确保数据存在。但是,用户说没有显示下拉框,所以我们需要检查是否有异常发生。我们可以通过Logcat查看是否有异常堆栈。另外,注意在`showCreateZujianDialog`方法中,我们使用了自定义布局`R.layout.dialog_create_zujian_bancai`,用户提供了这个布局的代码(在问题最后)。这个布局是有效的,包含了三个Spinner。考虑到用户可能遇到的是空数据问题,我们可以:1.在设置适配器之前,检查Data.caizhis和Data.mupis是否为空,并确保它们有数据。2.如果数据为空,可以初始化一些示例数据。但是,用户代码中,这些数据应该是从Data类中获取的,所以我们需要确保Data类中已经初始化了caizhis和mupis。另外,还有一个可能:在对话框布局中,Spinner的高度可能设置不正确,但我们看到布局中高度是wrap_content,所以应该是正常的。考虑到代码中出现了关于`getView`中`convertView`为null的日志,这可能是由于适配器在渲染时出错,例如在`getView`方法中发生了空指针异常,这会导致Spinner不显示。我们检查适配器的`getView`方法:对于caizhiAdapter:```java@NonNull@OverridepublicViewgetView(intposition,ViewconvertView,@NonNullViewGroupparent){TextViewtextView=(TextView)super.getView(position,convertView,parent);Caizhicaizhi=getItem(position);if(caizhi!=null){textView.setText(caizhi.getName());}returntextView;}```这里我们调用了`super.getView`,并假设返回的是TextView,但实际上`android.R.layout.simple_spinner_item`是一个TextView吗?如果是,那么这是安全的。但要注意,如果`super.getView`返回的不是TextView,那么就会抛出ClassCastException。同样地,mupiAdapter中:```javatextView.setText(mupi.formatMupiDisplay());```这里我们使用了自定义的`formatMupiDisplay`方法,如果mupi为null,这里就会抛出空指针异常。所以,我们需要确保在适配器的数据中,没有null值,并且在适配器中处理了可能的null情况。改进建议:1.在caizhiAdapter和mupiAdapter的`getView`和`getDropDownView`方法中,增加对null的处理。2.如果数据项为null,设置一个默认文本(如"未知")。但是,更好的做法是确保数据源中没有null值。另外,在`getView`方法中,我们发现调用了`super.getView`,然后设置文本。如果`super.getView`返回的视图不是TextView,那么应该使用其他方式。但`android.R.layout.simple_spinner_item`的根视图是一个TextView,所以没有问题。然而,为了安全起见,我们可以打印日志来检查是否发生了异常。由于用户描述问题为“没有下拉框”,最可能的原因是数据适配器出现了异常,导致Spinner无法正常显示。因此,我们尝试捕获可能发生的异常,并在适配器中添加更健壮的处理。具体修改:1.检查Data.caizhis和Data.mupis是否为空,如果为空则添加一些默认值。2.在适配器中,对getItem(position)返回null的情况进行处理。另外,我们在布局文件中,每个Spinner的高度都是wrap_content,所以不会因为高度为0而不显示。但是,用户提供的布局代码中,每个Spinner都是可见的,所以布局没有问题。考虑到在创建新组件的时候才弹出这个对话框,而之前的Spinner(订单、产品、组件)都工作正常,所以可能是这个对话框的数据问题。我们修改适配器,确保即使数据项为null也不崩溃:例如,对于caizhiAdapter:```java@NonNull@OverridepublicViewgetView(intposition,ViewconvertView,@NonNullViewGroupparent){TextViewtextView=(TextView)super.getView(position,convertView,parent);Caizhicaizhi=getItem(position);Stringtext=caizhi!=null?caizhi.getName():"未知材质";textView.setText(text);returntextView;}```同样地,对mupiAdapter:```java@NonNull@OverridepublicViewgetView(intposition,ViewconvertView,@NonNullViewGroupparent){TextViewtextView=(TextView)super.getView(position,convertView,parent);Mupimupi=getItem(position);Stringtext=mupi!=null?mupi.formatMupiDisplay():"未知木皮";textView.setText(text);returntextView;}```并且,在`getDropDownView`中也同样处理。此外,确保Data类中的caizhis和mupis已经初始化,并且有数据。如果问题依旧,我们需要在代码中添加日志,查看在设置适配器时是否有异常抛出。我们可以在设置适配器的代码周围加上try-catch,并打印日志:```javatry{spinnerCaizhi.setAdapter(caizhiAdapter);}catch(Exceptione){Log.e(TAG,"Errorsettingcaizhispinneradapter",e);}```同样对另外两个Spinner也进行同样的处理。由于用户没有提供具体的错误日志,所以我们需要在代码中主动捕获异常。综上所述,我们将对适配器进行空安全处理,并添加异常捕获。修改后的代码:在`showCreateZujianDialog`方法中,修改两个适配器的实现,增强健壮性,并在设置适配器时捕获异常。另外,确保数据源不为空。如果为空,可以临时添加一个空对象,以防止适配器出错。但是,由于我们无法控制Data类的初始化,所以最好在获取数据源时进行非空判断,如果为空则使用一个空列表。修改如下:将:```javaArrayAdapter<Caizhi>caizhiAdapter=newArrayAdapter<Caizhi>(...);```改为:```java//如果Data.caizhis为空,使用一个空列表避免崩溃List<Caizhi>caizhis=Data.caizhis!=null?Data.caizhis:newArrayList<>();ArrayAdapter<Caizhi>caizhiAdapter=newArrayAdapter<Caizhi>(requireContext(),android.R.layout.simple_spinner_item,caizhis){...}```同样处理mupiAdapter。这样即使数据源为空,也不会导致适配器崩溃。现在,我们重写适配器部分,并添加日志。由于代码较长,我们只展示修改后的适配器部分:```javaprivatevoidshowCreateZujianDialog(){//...其他代码不变...//设置材质下拉框适配器(只显示名称)List<Caizhi>caizhis=Data.caizhis!=null?Data.caizhis:newArrayList<>();ArrayAdapter<Caizhi>caizhiAdapter=newArrayAdapter<Caizhi>(requireContext(),android.R.layout.simple_spinner_item,caizhis){@NonNull@OverridepublicViewgetView(intposition,ViewconvertView,@NonNullViewGroupparent){TextViewtextView;try{textView=(TextView)super.getView(position,convertView,parent);}catch(Exceptione){Log.e(TAG,"ErroringetView",e);//创建一个新的TextView作为应急textView=newTextView(parent.getContext());textView.setLayoutParams(newViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT));}Caizhicaizhi=getItem(position);textView.setText(caizhi!=null?caizhi.getName():"未知材质");returntextView;}@OverridepublicViewgetDropDownView(intposition,ViewconvertView,@NonNullViewGroupparent){TextViewtextView=(TextView)super.getDropDownView(position,convertView,parent);Caizhicaizhi=getItem(position);textView.setText(caizhi!=null?caizhi.getName():"未知材质");returntextView;}};//设置木皮下拉框适配器(名称+油或不加)List<Mupi>mupis=Data.mupis!=null?Data.mupis:newArrayList<>();ArrayAdapter<Mupi>mupiAdapter=newArrayAdapter<Mupi>(requireContext(),android.R.layout.simple_spinner_item,mupis){@NonNull@OverridepublicViewgetView(intposition,ViewconvertView,@NonNullViewGroupparent){TextViewtextView;try{textView=(TextView)super.getView(position,convertView,parent);}catch(Exceptione){Log.e(TAG,"ErroringetView",e);textView=newTextView(parent.getContext());textView.setLayoutParams(newViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT));}Mupimupi=getItem(position);textView.setText(mupi!=null?mupi.formatMupiDisplay():"未知木皮");returntextView;}@OverridepublicViewgetDropDownView(intposition,ViewconvertView,@NonNullViewGroupparent){TextViewtextView=(TextView)super.getDropDownView(position,convertView,parent);Mupimupi=getItem(position);textView.setText(mupi!=null?mupi.formatMupiDisplay():"未知木皮");returntextView;}};//...其他代码...//设置适配器,并捕获异常try{spinnerCaizhi.setAdapter(caizhiAdapter);}catch(Exceptione){Log.e(TAG,"Errorsettingcaizhiadapter",e);Toast.makeText(getContext(),"设置材质下拉框失败",Toast.LENGTH_SHORT).show();}try{spinnerMupi1.setAdapter(mupiAdapter);}catch(Exceptione){Log.e(TAG,"Errorsettingmupi1adapter",e);Toast.makeText(getContext(),"设置木皮下拉框失败",Toast.LENGTH_SHORT).show();}try{spinnerMupi2.setAdapter(mupiAdapter);}catch(Exceptione){Log.e(TAG,"Errorsettingmupi2adapter",e);Toast.makeText(getContext(),"设置木皮下拉框失败",Toast.LENGTH_SHORT).show();}//...其他代码...}```另外,确保在Data类中,caizhis和mupis已经初始化。例如:Data.caizhis=newArrayList<>();//并添加一些数据Data.mupis=newArrayList<>();//并添加一些数据如果用户没有初始化,那么将使用空列表,至少不会崩溃,但是会显示“未知材质”等。这样修改后,Spinner应该能够显示出来,即使没有数据,也会显示“未知材质”等。最后,如果问题仍然存在,我们需要检查对话框的布局文件是否被正确加载,以及Spinner的id是否正确,是否与代码中findViewById的id匹配。在对话框布局中,我们定义的id是:spinner_caizhispinner_mupi1spinner_mupi2代码中也是使用这些id,所以应该匹配。综上所述,我们进行了以下改动:1.确保数据源非空(如果为空则使用空列表)。2.在适配器中处理了数据项为null的情况。3.在设置文本时,使用了默认值。4.在设置适配器时捕获了异常。5.在getView中捕获了异常,并创建了应急的TextView。这样修改后,应该能够解决用户的问题。由于代码较长,我们只展示了修改的关键部分。如果用户依然遇到问题,建议通过日志(Logcat)查看具体的异常信息。另外,注意在对话框中,我们使用了`requireContext()`,在Fragment中,如果Fragment没有附加到Activity,这可能会抛出异常。我们可以改为使用`getContext()`,并检查是否为null。所以,我们修改为:```javaViewdialogView=LayoutInflater.from(getContext()).inflate(R.layout.dialog_create_zujian_bancai,null);```以及适配器的context参数使用`getContext()`。由于在Fragment中,`getContext()`可能在Fragment未被附加时返回null,所以我们在使用前检查。但在`showCreateZujianDialog`被调用时,Fragment应该已经附加了。为了安全,我们可以:```javaContextcontext=getContext();if(context==null){//如果context为空,直接返回return;}```然后在后面使用context。修改后的`showCreateZujianDialog`方法开头:```javaprivatevoidshowCreateZujianDialog(){Contextcontext=getContext();if(context==null){Log.e(TAG,"Contextisnull,cannotshowdialog");return;}AlertDialog.Builderbuilder=newAlertDialog.Builder(context);ViewdialogView=LayoutInflater.from(context).inflate(R.layout.dialog_create_zujian_bancai,null);//...其他代码中使用context...```适配器创建时,第一个参数改为context。这样修改后,应该更加健壮。请用户测试修改后的代码,并查看Logcat中是否有相关错误日志。如果问题仍未解决,我们需要更多的错误信息。由于问题描述没有具体的错误日志,我们只能给出以上修改建议。</think> 针对您的问题,我看到在`showCreateZujianDialog()`方法中,为材质和木皮下拉框设置了适配器,但布局文件中没有正确显示下拉框。这通常是适配器设置不正确或数据源问题导致的。以下是详细的解决方案: ### 问题原因分析: 1. **数据源可能为空**:`Data.caizhis`或`Data.mupis`可能没有初始化数据 2. **下拉框渲染问题**:Spinner的适配器配置可能不正确 3. **布局问题**:自定义布局可能没有正确应用 ### 完整的修复方案: #### 1. 确保数据源有默认值 ```java // 在Data类中添加示例数据 public class Data { public static List<Caizhi> caizhis = Arrays.asList( new Caizhi(1, "橡木"), new Caizhi(2, "胡桃木"), new Caizhi(3, "枫木") ); public static List<Mupi> mupis = Arrays.asList( new Mupi(1, "橡木皮", false), new Mupi(2, "胡桃木皮", true), new Mupi(3, "枫木皮", false) ); } ``` #### 2. 修改showCreateZujianDialog方法 ```java private void showCreateZujianDialog() { Context context = getContext(); if (context == null) return; AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle("添加新组件和板材"); // 创建自定义布局 View dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_create_zujian_bancai, null); EditText etZujianName = dialogView.findViewById(R.id.et_zujian_name); Spinner spinnerCaizhi = dialogView.findViewById(R.id.spinner_caizhi); Spinner spinnerMupi1 = dialogView.findViewById(R.id.spinner_mupi1); Spinner spinnerMupi2 = dialogView.findViewById(R.id.spinner_mupi2); // 确保数据源不为null List<Caizhi> caizhiList = Data.caizhis != null ? Data.caizhis : new ArrayList<>(); List<Mupi> mupiList = Data.mupis != null ? Data.mupis : new ArrayList<>(); // 设置材质下拉框适配器(显示名称) ArrayAdapter<Caizhi> caizhiAdapter = new ArrayAdapter<Caizhi>( context, android.R.layout.simple_spinner_item, caizhiList) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(android.R.layout.simple_spinner_item, parent, false); } TextView textView = (TextView) convertView; Caizhi caizhi = getItem(position); textView.setText(caizhi != null ? caizhi.getName() : "请选择材质"); return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(android.R.layout.simple_spinner_dropdown_item, parent, false); } TextView textView = (TextView) convertView; Caizhi caizhi = getItem(position); textView.setText(caizhi != null ? caizhi.getName() : "请选择材质"); return textView; } }; spinnerCaizhi.setAdapter(caizhiAdapter); // 设置木皮下拉框适配器 ArrayAdapter<Mupi> mupiAdapter = new ArrayAdapter<Mupi>( context, android.R.layout.simple_spinner_item, mupiList) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(android.R.layout.simple_spinner_item, parent, false); } TextView textView = (TextView) convertView; Mupi mupi = getItem(position); textView.setText(mupi != null ? mupi.formatMupiDisplay() : "请选择木皮"); return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(getContext()) .inflate(android.R.layout.simple_spinner_dropdown_item, parent, false); } TextView textView = (TextView) convertView; Mupi mupi = getItem(position); textView.setText(mupi != null ? mupi.formatMupiDisplay() : "请选择木皮"); return textView; } }; // 设置适配器 spinnerMupi1.setAdapter(mupiAdapter); spinnerMupi2.setAdapter(mupiAdapter); // 设置默认选择 if (!mupiList.isEmpty()) { spinnerMupi1.setSelection(0); spinnerMupi2.setSelection(0); } builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { // [原有逻辑...] }); builder.setNegativeButton("取消", null); builder.show(); } ``` #### 3. 更新Mupi类,确保formatMupiDisplay方法安全 ```java public class Mupi { // ...其他属性 public String formatMupiDisplay() { return (name != null ? name : "未命名") + (isOiled ? "(油)" : ""); } } ``` #### 4. 检查布局文件(dialog_create_zujian_bancai.xml) ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <!-- 组件名称输入 --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="组件名称"/> <EditText android:id="@+id/et_zujian_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入组件名称" android:inputType="text"/> <!-- 材质选择 --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="材质" android:layout_marginTop="16dp"/> <Spinner android:id="@+id/spinner_caizhi" android:layout_width="match_parent" android:layout_height="50dp" android:background="@android:drawable/btn_dropdown"/> <!-- 木皮1选择 --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="木皮1" android:layout_marginTop="8dp"/> <Spinner android:id="@+id/spinner_mupi1" android:layout_width="match_parent" android:layout_height="50dp" android:background="@android:drawable/btn_dropdown"/> <!-- 木皮2选择 --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="木皮2(可选)" android:layout_marginTop="8dp"/> <Spinner android:id="@+id/spinner_mupi2" android:layout_width="match_parent" android:layout_height="50dp" android:background="@android:drawable/btn_dropdown"/> </LinearLayout> ``` ### 关键修改点说明: 1. **数据源安全检查**: - 添加了空检查:`Data.caizhis != null ? Data.caizhis : new ArrayList<>()` - 添加了默认数据初始化 2. **适配器重写**: - 显式创建视图(解决convertView为null的问题) - 使用android原生布局确保兼容性 - 添加了默认文本("请选择材质") 3. **下拉框高度设定**: - 设置明确高度:`android:layout_height="50dp"` - 添加下拉图标:`android:background="@android:drawable/btn_dropdown"` 4. **安全处理**: - 添加了context空检查 - 确保formatMupiDisplay方法能处理空值 ### 额外建议: 1. 在`onCreate`中初始化测试数据: ```java // 在Activity/Fragment的onCreate中 if (Data.caizhis == null || Data.caizhis.isEmpty()) { Data.caizhis = Arrays.asList( new Caizhi(1, "橡木"), new Caizhi(2, "胡桃木"), // 更多示例... ); } ``` 2. 添加调试日志: ```java Log.d("SpinnerDebug", "材质数据量: " + Data.caizhis.size()); Log.d("SpinnerDebug", "木皮数据量: " + Data.mupis.size()); ``` 3. 考虑使用更现代的MaterialSpinner: ```gradle // build.gradle implementation 'com.jaredrummler:material-spinner:1.3.1' ``` ```java // 使用示例 MaterialSpinner spinner = new MaterialSpinner(context); spinner.setItems(Data.caizhis.stream().map(Caizhi::getName).collect(Collectors.toList())); ``` ### 可能遇到的问题排查: 1. 如果仍然不显示下拉框: - 检查`Data.caizhis`和`Data.mupis`是否有真实数据 - 查看Logcat是否有空指针异常 - 尝试使用基础ArrayAdapter`new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, names)` 2. 如果数据量很大: - 实现过滤功能 - 使用RecyclerView替代Spinner - 添加搜索功能 3. 如果性能有问题: - 使用ViewHolder模式优化 - 避免在主线程处理大数据集 - 考虑分页加载
阅读全文

相关推荐

package com.example.kucun2.entity.data; import android.util.Log; import androidx.annotation.NonNull; import com.google.gson.Gson; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Proxy; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Objects; import java.util.Set; import okhttp3.Call; import okhttp3.Callback; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; /** * 支持数据变更自动同步的泛型集合类 * @param <T> 继承自 SynchronizableEntity 的实体类型 */ public class SynchronizedList<T extends SynchronizableEntity> implements List<T> { private final List<T> list = new ArrayList<>(); private final OkHttpClient client = new OkHttpClient(); private static final Gson gson = new Gson(); private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private final Class<T> entityClass; // 类型标记 // 添加批量操作模式标志 private boolean batchMode = false; // 属性变更监听器 private final List> listeners = new ArrayList<>(); // 直接接受Class参数的构造函数 public SynchronizedList(Class<T> entityClass) { this.entityClass = entityClass; } // 安全的类型转换方法 private T safeCast(Object o) { if (o != null && entityClass.isInstance(o)) { return entityClass.cast(o); } return null; } public interface PropertyChangeListener<T> { void onPropertyChange(T entity, String propertyName, Object oldValue, Object newValue); } public void addPropertyChangeListener(PropertyChangeListener<T> listener) { listeners.add(listener); } public void removePropertyChangeListener(PropertyChangeListener<T> listener) { listeners.remove(listener); } // 添加方法来获取原始对象 @SuppressWarnings("unchecked") public T getOriginal(T proxy) { if (proxy == null) return null; // 检查是否为代理对象 if (java.lang.reflect.Proxy.isProxyClass(proxy.getClass())) { try { java.lang.reflect.InvocationHandler handler = java.lang.reflect.Proxy.getInvocationHandler(proxy); if (handler instanceof IProxyHandler) { Object original = ((IProxyHandler) handler).getOriginal(); // 安全类型检查 if (entityClass.isInstance(original)) { return (T) original; } } } catch (Exception e) { Log.e("SynchronizedList", "Failed to get proxy handler", e); } } return proxy; } /** * 同步实体到后端 * * @param entity 要同步的实体 */ private void syncEntity(T entity) { if (batchMode) return; String operation = "add"; T originalEntity = getOriginal(entity); String endpoint = originalEntity.getEndpoint(operation); String json = gson.toJson(originalEntity); RequestBody body = RequestBody.create(json, JSON); Request request = new Request.Builder() .url(endpoint) .method(getHttpMethod(operation), body) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { Log.e("SynchronizedList", "同步失败: " + entity.getClass().getSimpleName(), e); } @Override public void onResponse(@NonNull Call call, @NonNull Response response) { if (!response.isSuccessful()) { Log.e("SynchronizedList", "同步失败: " + response.code() + " - " + response.message()); } response.close(); } }); } // 添加用于批量操作的方法 public void beginBatch() { this.batchMode = true; } public void endBatch() { this.batchMode = false; // 批量结束后触发一次全量同步 syncAllEntities(); } private void syncAllEntities() { for (T entity : list) { syncEntity(entity); } } private String getHttpMethod(String operation) { switch (operation) { case "add": return "POST"; case "update": return "PUT"; case "delete": return "DELETE"; default: return "POST"; } } // 获取类实现的所有接口(包括父类接口) private Class<?>[] getInterfaces(Class<?> clazz) { Set<Class<?>> interfaces = new HashSet<>(); while (clazz != null) { interfaces.addAll(Arrays.asList(clazz.getInterfaces())); clazz = clazz.getSuperclass(); } return interfaces.toArray(new Class<?>[0]); } /** * 创建代理对象,用于监听属性变更 */ // 优化 createProxy 方法 private T createProxy(T original) { if (original == null) return null; // 确保代理对象实现原始对象的所有接口+目标接口 Class<?>[] interfaces = new Class<?>[]{ SynchronizableEntity.class, // 强制实现目标接口 entityClass // 实体类或接口 }; // 使用动态代理实现接口 return (T) Proxy.newProxyInstance( original.getClass().getClassLoader(), new Class<?>[] { EntityClassGrassrootsid.class }, // 只代理接口 new EntityProxyHandler(original) ); // if (!entityClass.isInstance(original)) { // throw new IllegalArgumentException("Invalid entity type"); // } // // 这里使用动态代理模式监听setter方法调用 // return (T) java.lang.reflect.Proxy.newProxyInstance( // original.getClass().getClassLoader(), // original.getClass().getInterfaces(), // (proxy, method, args) -> { // // 只拦截setter方法 // if (method.getName().startsWith("set") && args.length == 1) { // String propertyName = method.getName().substring(3); // propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1); // // // 获取旧值 // Object oldValue = original.getClass() // .getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1)) // .invoke(original); // // // 调用原始方法 // Object result = method.invoke(original, args); // // // 触发监听器 // for (PropertyChangeListener<T> listener : listeners) { // listener.onPropertyChange(original, propertyName, oldValue, args[0]); // } // // // 自动同步到后端 // syncEntity(original); // return result; // } // return method.invoke(original, args); // } // ); } // 以下是List接口的实现 @Override public int size() { return list.size(); } @Override public boolean isEmpty() { return list.isEmpty(); } @Override public boolean contains(Object o) { return list.contains(o); } @NonNull @Override public Iterator<T> iterator() { return list.iterator(); } @NonNull @Override public Object[] toArray() { return list.toArray(); } @NonNull @Override public <T1> T1[] toArray(@NonNull T1[] a) { return list.toArray(a); } @Override public boolean add(T t) { T proxy = createProxy(t); boolean result = list.add(proxy); if (!batchMode) { syncEntity(proxy); } return result; // 添加时创建代理 } @Override public boolean remove(Object o) { T entity = safeCast(o); if (entity != null) { syncEntity((T) entity); // 删除前同步 } return list.remove(o); } @Override public boolean containsAll(@NonNull Collection<?> c) { return list.containsAll(c); } @Override public boolean addAll(@NonNull Collection<? extends T> c) { boolean modified = false; for (T t : c) { modified |= add(t); } return modified; } @Override public boolean addAll(int index, @NonNull Collection<? extends T> c) { for (T t : c) { add(index++, t); } return true; } @Override public boolean removeAll(@NonNull Collection<?> c) { for (Object o : c) { T entity = safeCast(o); if (entity != null) { syncEntity(entity); } } return list.removeAll(c); } @Override public boolean retainAll(@NonNull Collection<?> c) { List<T> toRemove = new ArrayList<>(); for (T t : list) { if (!c.contains(t)) { toRemove.add(t); } } // 使用安全转换 for (T entity : toRemove) { syncEntity(entity); } return list.retainAll(c); } @Override public void clear() { for (T t : list) { syncEntity(t); // 清空前同步 } list.clear(); } @Override public T get(int index) { return list.get(index); } @Override public T set(int index, T element) { T old = list.set(index, createProxy(element)); if (old != null) { syncEntity(old); // 替换旧元素前同步 } return old; } @Override public void add(int index, T element) { list.add(index, createProxy(element)); } @Override public T remove(int index) { T removed = list.remove(index); if (removed != null) { syncEntity(removed); // 删除前同步 } return removed; } @Override public int indexOf(Object o) { return list.indexOf(o); } @Override public int lastIndexOf(Object o) { return list.lastIndexOf(o); } @NonNull @Override public ListIterator<T> listIterator() { return list.listIterator(); } @NonNull @Override public ListIterator<T> listIterator(int index) { return list.listIterator(index); } @NonNull @Override public List<T> subList(int fromIndex, int toIndex) { return list.subList(fromIndex, toIndex); } // 触发属性变更通知 // 添加类型安全的属性监听 private void firePropertyChange(T entity, String propertyName, Object oldValue, Object newValue) { if (oldValue != null && newValue != null && oldValue.equals(newValue)) { return; // 值未变化时不触发监听 } for (PropertyChangeListener<T> listener : listeners) { try { listener.onPropertyChange(entity, propertyName, oldValue, newValue); } catch (Exception e) { Log.e("SynchronizedList", "Listener error", e); } } } // 修改代理处理器以支持获取原始对象 /* 完整的 EntityProxyHandler 实现 */ private class EntityProxyHandler implements IProxyHandler, java.lang.reflect.InvocationHandler { private final T original; private final Map<String, Object> propertyValues = new HashMap<>(); public EntityProxyHandler(T original) { this.original = original; cachePropertyValues(); } private void cachePropertyValues() { // 获取类信息 Class<?> clazz = original.getClass(); // 遍历所有getter方法 for (Method method : clazz.getMethods()) { String methodName = method.getName(); // 只处理getter方法 if (methodName.startsWith("get") && !methodName.equals("getClass") && method.getParameterTypes().length == 0) { try { // 获取属性名(去掉"get"并将首字母小写) String propertyName = methodName.substring(3); propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1); // 调用getter获取值 Object value = method.invoke(original); propertyValues.put(propertyName, value); } catch (Exception e) { Log.e("Wrapper", "Failed to cache property " + methodName, e); } } } } @Override public T getOriginal() { return original; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); // 只拦截setter方法 if (methodName.startsWith("set") && args != null && args.length == 1) { String propertyName = methodName.substring(3); propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1); Object oldValue = propertyValues.get(propertyName); Object newValue = args[0]; // 如果值未改变,不触发同步 if (Objects.equals(oldValue, newValue)) { return null; } // 调用原始对象的setter方法 Method setter = original.getClass().getMethod(methodName, newValue.getClass()); setter.invoke(original, newValue); // 更新属性缓存 propertyValues.put(propertyName, newValue); // 触发属性变更监听 firePropertyChange(original, propertyName, oldValue, newValue); // 非批量模式下自动同步 if (!batchMode) { syncEntity(original); } } // 其他接口方法直接调用原始对象 return method.invoke(original, args); } private Object getPropertyValue(String propertyName) { String getterName = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); try { Method getter = original.getClass().getMethod(getterName); return getter.invoke(original); } catch (Exception e) { Log.e("ProxyHandler", "Failed to get property value: " + propertyName, e); return null; } } } // 在 SynchronizedList 类中添加 private interface IProxyHandler { Object getOriginal(); } }package com.example.kucun2.entity; import android.annotation.SuppressLint; import com.example.kucun2.entity.data.SynchronizableEntity; import java.util.Objects; //板材 public class Bancai extends SynchronizableEntity { private Integer id; private Caizhi caizhi; private Mupi mupi1; private Mupi mupi2; private Double houdu; public Bancai() { } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Bancai bancai = (Bancai) o; return Objects.equals(id, bancai.id) && Objects.equals(caizhi, bancai.caizhi) && Objects.equals(mupi1, bancai.mupi1) && Objects.equals(mupi2, bancai.mupi2) && Objects.equals(houdu, bancai.houdu); } @Override public int hashCode() { return Objects.hash(id, caizhi, mupi1, mupi2, houdu); } public Bancai(Integer id, Caizhi caizhi, Mupi mupi1, Mupi mupi2, Double houdu) { this.id = id; this.caizhi = caizhi; this.mupi1 = mupi1; this.mupi2 = mupi2; this.houdu = houdu; } public Integer getId() { return id; } public Caizhi getCaizhi() { return caizhi; } public Mupi getMupi1() { return mupi1; } public Mupi getMupi2() { return mupi2; } public Double getHoudu() { return houdu; } public void setId(Integer id) { this.id = id; } public void setCaizhi(Caizhi caizhi) { this.caizhi = caizhi; if (caizhi!=null&&caizhi.getBancais()!=null){ this.caizhi.getBancais().add(this); } } public void setMupi1(Mupi mupi1) { this.mupi1 = mupi1; if (mupi1!=null&&mupi1.getBancais()!=null){ this.mupi1.getBancais().add(this); } } public void setMupi2(Mupi mupi2) { this.mupi2 = mupi2; if (mupi2!=null&&mupi2.getBancais()!=null){ this.mupi2.getBancais().add(this); } } public void setHoudu(Double houdu) { this.houdu = houdu; } /** * 表格中显示的文字 * @return */ @SuppressLint("DefaultLocale") public String TableText(){ String boardInfo=""; boardInfo +=String.format("%.1f", this.getHoudu())+this.getCaizhi().getName()+"("; if (mupi1 != null) { boardInfo += (this.getMupi1().getYou()?this.getMupi1().getName()+"油":this.getMupi1().getName()); } if (mupi2 != null&&mupi1 != null) { boardInfo+=","; } if (mupi2 != null) { boardInfo += (this.getMupi2().getYou()?this.getMupi2().getName()+"油":this.getMupi2().getName()); } boardInfo+=")"; return boardInfo; } } package com.example.kucun2.entity.data; import com.example.kucun2.function.MyAppFnction; public abstract class SynchronizableEntity implements EntityClassGrassrootsid { /** * 添加url * @param type 操作增删改查 * @return 返回相对url */ public String getEndpoint(String type){ //从String.xml获取url return MyAppFnction.getStringResource("String","url_"+type+"_"+this.getClass().getSimpleName()); } } package com.example.kucun2.ui.jinhuo; import static android.content.ContentValues.TAG; import android.app.AlertDialog; import android.app.DatePickerDialog; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.MultiAutoCompleteTextView; import android.widget.RadioGroup; import android.widget.SearchView; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import com.example.kucun2.R; import com.example.kucun2.entity.*; import com.example.kucun2.entity.data.Data; import com.example.kucun2.function.Adapter; import com.google.android.material.textfield.TextInputEditText; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Random; public class AddInventoryFragment extends Fragment { private Spinner spinnerDingdan, spinnerChanpin, spinnerZujian, spinnerBancai; private EditText etShuliang; private RadioGroup rgType; private Dingdan selectedDingdan; private Chanpin selectedChanpin; private Zujian selectedZujian; private Bancai selectedBancai; // 创建新订单产品组件按钮 private Button btnNewDingdan, btnAddChanpin, btnAddZujian; // 日期格式化 private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); /** * 初始化 * @param inflater The LayoutInflater object that can be used to inflate * any views in the fragment, * @param container If non-null, this is the parent view that the fragment's * UI should be attached to. The fragment should not add the view itself, * but this can be used to generate the LayoutParams of the view. * @param savedInstanceState If non-null, this fragment is being re-constructed * from a previous saved state as given here. * * @return */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_add_inventory, container, false); // 初始化UI组件 spinnerDingdan = view.findViewById(R.id.spinner_dingdan); spinnerChanpin = view.findViewById(R.id.spinner_chanpin); spinnerZujian = view.findViewById(R.id.spinner_zujian); spinnerBancai = view.findViewById(R.id.spinner_bancai); etShuliang = view.findViewById(R.id.et_shuliang); rgType = view.findViewById(R.id.rg_type); Button btnSubmit = view.findViewById(R.id.btn_submit); // 初始化新按钮 btnNewDingdan = view.findViewById(R.id.btn_new_dingdan); btnAddChanpin = view.findViewById(R.id.btn_add_chanpin); btnAddZujian = view.findViewById(R.id.btn_add_zujian); // 设置按钮点击事件 btnNewDingdan.setOnClickListener(v -> createNewDingdan()); btnAddChanpin.setOnClickListener(v -> showAddChanpinDialog()); btnAddZujian.setOnClickListener(v -> addZujianToChanpin()); // 设置订单选择器 setupDingdanSpinner(); // 提交按钮点击事件 btnSubmit.setOnClickListener(v -> addInventoryRecord()); return view; } private void setupDingdanSpinner() { Adapter.setupDingdanSpinner(spinnerDingdan,Data.dingdans,getContext()); spinnerDingdan.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedDingdan = (Dingdan) parent.getItemAtPosition(position); setupChanpinSpinner(selectedDingdan); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupChanpinSpinner(Dingdan dingdan) { // 获取该订单的产品列表 List<Chanpin> chanpins = new ArrayList<>(); for (Dingdan_Chanpin dc : dingdan.getChanpins()) { chanpins.add(dc.getChanpin()); } Adapter.setupChanpinSpinner(spinnerChanpin,chanpins,getContext()); spinnerChanpin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedChanpin = (Chanpin) parent.getItemAtPosition(position); setupZujianSpinner(selectedChanpin); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } /** * 组件下拉框刷新 * @param chanpin */ private void setupZujianSpinner(Chanpin chanpin) { // 获取该产品的组件列表 List<Zujian> zujians = new ArrayList<>(); for (Chanpin_Zujian cz : chanpin.getZujians()) { zujians.add(cz.getZujian()); } Adapter.setupZujianSpinner(spinnerZujian,zujians,getContext()); spinnerZujian.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedZujian = (Zujian) parent.getItemAtPosition(position); setupBancaiSpinner(selectedChanpin, selectedZujian); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } /** * 板材刷新 * @param chanpin * @param zujian */ private void setupBancaiSpinner(Chanpin chanpin, Zujian zujian) { // 获取该组件关联的板材 List<Bancai> bancais = new ArrayList<>(); for (Chanpin_Zujian cz : chanpin.getZujians()) { if (cz.getZujian().getId().equals(zujian.getId())) { bancais.add(cz.getBancai()); } } Adapter.setupBancaiSpinners(spinnerBancai,bancais,getContext()); spinnerBancai.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedBancai = (Bancai) parent.getItemAtPosition(position); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } // ... addInventoryRecord和createRecord方法保持不变 ... private void addInventoryRecord() { // 验证必填项 if (selectedDingdan == null || selectedChanpin == null || selectedZujian == null || selectedBancai == null) { Toast.makeText(getContext(), "请选择订单、产品、组件和板材", Toast.LENGTH_SHORT).show(); return; } String shuliangStr = etShuliang.getText().toString().trim(); if (shuliangStr.isEmpty()) { Toast.makeText(getContext(), "请输入数量", Toast.LENGTH_SHORT).show(); return; } // 解析数量 int shuliang; try { shuliang = Integer.parseInt(shuliangStr); } catch (NumberFormatException e) { Toast.makeText(getContext(), "请输入有效的数量", Toast.LENGTH_SHORT).show(); return; } // 确定操作类型(进货或消耗) boolean isJinhuo = rgType.getCheckedRadioButtonId() == R.id.rb_jinhuo; // 实际开发中应从登录信息获取当前用户 User currentUser = new User(1, "当前用户", "user", "password",1); // 创建记录 createRecord(selectedDingdan, selectedChanpin, selectedZujian, selectedBancai, shuliang, isJinhuo, currentUser); Toast.makeText(getContext(), "记录添加成功", Toast.LENGTH_SHORT).show(); etShuliang.setText(""); // 清空输入框 } private void createRecord(Dingdan dingdan, Chanpin chanpin, Zujian zujian, Bancai bancai, int shuliang, boolean isJinhuo, User user) { if (isJinhuo) { // 创建进货记录 Jinhuo jinhuo = new Jinhuo(); jinhuo.setId(Data.jinhuoList.size() + 1); jinhuo.setDingdan(dingdan); jinhuo.setChanpin(chanpin); jinhuo.setZujian(zujian); jinhuo.setBancai(bancai); jinhuo.setShuliang(shuliang); jinhuo.setDate(new Date()); jinhuo.setUser(user); Data.jinhuoList.add(jinhuo); } else { // 消耗数量转为负数 shuliang = -shuliang; } // 更新库存 updateKucun(bancai, shuliang); } private void updateKucun(Bancai bancai, int changeAmount) { // 查找现有库存记录 for (Kucun k : Data.kucuns) { if (k.getBancai().getId().equals(bancai.getId())) { k.setShuliang(k.getShuliang() + changeAmount); return; } } // 如果没有找到库存记录,创建新的 Kucun newKucun = new Kucun(); newKucun.setId(Data.kucuns.size() + 1); newKucun.setBancai(bancai); newKucun.setShuliang(Math.max(changeAmount, 0)); // 确保不为负 Data.kucuns.add(newKucun); } // 新建订单方法 private void createNewDingdan() { showNewDingdanDialog(); } /** * 向订单添加产品 * @param chanpin */ private void addChanpinToDingdan(Chanpin chanpin) { if (selectedDingdan == null) { Toast.makeText(getContext(), "请先选择订单", Toast.LENGTH_SHORT).show(); return; } // 检查产品是否已在订单中 for (Dingdan_Chanpin dc : selectedDingdan.getChanpins()) { if (dc.getChanpin().getId().equals(chanpin.getId())) { Toast.makeText(getContext(), "该产品已添加到订单", Toast.LENGTH_SHORT).show(); return; } } // 添加到当前订单的产品列表 Dingdan_Chanpin dc = new Dingdan_Chanpin(); dc.setId(selectedDingdan.getChanpins().size() + 1); dc.setChanpin(chanpin); dc.setDingdan(selectedDingdan); selectedDingdan.getChanpins().add(dc); // 刷新产品下拉框 setupChanpinSpinner(selectedDingdan); // 选中新添加的产品 spinnerChanpin.setSelection(selectedDingdan.getChanpins().size() - 1); Toast.makeText(getContext(), "产品添加成功", Toast.LENGTH_SHORT).show(); } // 为当前产品添加组件 private void addZujianToChanpin() { if (selectedChanpin == null) { Toast.makeText(getContext(), "请先选择产品", Toast.LENGTH_SHORT).show(); return; } // // 创建新组件(示例) // Zujian newZujian = new Zujian(); // newZujian.setId( (Data.zujians.size() + 1)); // newZujian.setName("新组件" + System.currentTimeMillis()); // // // 添加到全局列表 // Data.zujians.add(newZujian); // // // 添加到当前产品的组件列表 // Chanpin_Zujian cz = new Chanpin_Zujian(); // cz.setId(selectedChanpin.getZujians().size() + 1); // cz.setZujian(newZujian); // cz.setChanpin(selectedChanpin); // selectedChanpin.getZujians().add(cz); // // // 刷新组件下拉框 // setupZujianSpinner(selectedChanpin); // spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1); // // Toast.makeText(getContext(), "组件添加成功", Toast.LENGTH_SHORT).show(); showCreateZujianDialog(); } // 新建订单对话框 /*** * 新建订单对话框 */ private void showNewDingdanDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("新建订单"); // 加载布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_new_dingdan, null); EditText etOrderNumber = dialogView.findViewById(R.id.et_order_number); EditText etOrderDate = dialogView.findViewById(R.id.et_order_date); EditText etDeliveryDate = dialogView.findViewById(R.id.et_delivery_date); Button btnPickOrderDate = dialogView.findViewById(R.id.btn_pick_order_date); Button btnPickDeliveryDate = dialogView.findViewById(R.id.btn_pick_delivery_date); // 设置今日日期作为默认值 Date today = new Date(); etOrderDate.setText(dateFormat.format(today)); // 日期选择监听器 DatePickerDialog.OnDateSetListener orderDateListener = (view, year, month, dayOfMonth) -> { Calendar cal = Calendar.getInstance(); cal.set(year, month, dayOfMonth); etOrderDate.setText(dateFormat.format(cal.getTime())); }; DatePickerDialog.OnDateSetListener deliveryDateListener = (view, year, month, dayOfMonth) -> { Calendar cal = Calendar.getInstance(); cal.set(year, month, dayOfMonth); etDeliveryDate.setText(dateFormat.format(cal.getTime())); }; // 下单日期选择按钮 btnPickOrderDate.setOnClickListener(v -> { Calendar cal = Calendar.getInstance(); new DatePickerDialog(requireContext(), orderDateListener, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)) .show(); }); /** * / 出货日期选择按钮 */ btnPickDeliveryDate.setOnClickListener(v -> { Calendar cal = Calendar.getInstance(); new DatePickerDialog(requireContext(), deliveryDateListener, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)) .show(); }); builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { String orderNumber = etOrderNumber.getText().toString().trim(); String orderDateStr = etOrderDate.getText().toString(); String deliveryDateStr = etDeliveryDate.getText().toString(); for (Dingdan dingdan:Data.dingdans ) { if(dingdan.getNumber().equals(orderNumber)){ Toast.makeText(getContext(), "已有该订单号", Toast.LENGTH_SHORT).show(); return; } } // 验证输入 if (orderNumber.isEmpty()) { Toast.makeText(getContext(), "请输入订单号", Toast.LENGTH_SHORT).show(); return; } try { // 解析日期 Date orderDate = dateFormat.parse(orderDateStr); Date deliveryDate = deliveryDateStr.isEmpty() ? null : dateFormat.parse(deliveryDateStr); // 创建订单 createAndSaveDingdan(orderNumber, orderDate, deliveryDate); } catch (ParseException e) { Toast.makeText(getContext(), "日期格式错误", Toast.LENGTH_SHORT).show(); } }); builder.setNegativeButton("取消", null); builder.show(); } /** * 创建并保存订单 */ private void createAndSaveDingdan(String orderNumber, Date orderDate, Date deliveryDate) { Dingdan newDingdan = new Dingdan(); newDingdan.setId(Data.dingdans.size() + 1); newDingdan.setNumber(orderNumber); newDingdan.setXiadan(orderDate); newDingdan.setJiaohuo(deliveryDate); newDingdan.setChanpins(new ArrayList<>()); Data.dingdans.add(newDingdan); // 刷新下拉框 setupDingdanSpinner(); spinnerDingdan.setSelection(Data.dingdans.size() - 1); Toast.makeText(getContext(), "新建订单成功", Toast.LENGTH_SHORT).show(); } /** * 显示添加产品弹窗 */ private void showAddChanpinDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("添加产品到订单"); // 加载布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_add_chanpin, null); Spinner spinnerChanpinSelection = dialogView.findViewById(R.id.spinner_chanpin_selection); Button btnNewChanpin = dialogView.findViewById(R.id.btn_new_chanpin); // 设置产品下拉框 Adapter.setupChanpinSpinner(spinnerChanpinSelection, Data.chanpins, getContext()); // 新建产品按钮点击事件 btnNewChanpin.setOnClickListener(v -> { showNewChanpinDialog(() -> { // 新建产品后刷新下拉框 Adapter.setupChanpinSpinner(spinnerChanpinSelection, Data.chanpins, getContext()); // 默认选中新建的产品 spinnerChanpinSelection.setSelection(Data.chanpins.size() - 1); }); }); builder.setView(dialogView); builder.setPositiveButton("添加", (dialog, which) -> { Chanpin selectedChanpin = (Chanpin) spinnerChanpinSelection.getSelectedItem(); if (selectedChanpin != null) { // 将选中的产品添加到当前订单 addChanpinToDingdan(selectedChanpin); } }); builder.setNegativeButton("取消", null); builder.show(); } /** * 显示新建产品弹窗 * @param refreshCallback 新建后的回调,用于刷新产品列表 */ private void showNewChanpinDialog(Runnable refreshCallback) { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("新建产品"); View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_new_chanpin, null); EditText etChanpinName = dialogView.findViewById(R.id.et_chanpin_name); builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { String chanpinName = etChanpinName.getText().toString().trim(); if (chanpinName.isEmpty()) { Toast.makeText(getContext(), "请输入产品名称", Toast.LENGTH_SHORT).show(); return; } // 检查名称是否重复 for (Chanpin cp : Data.chanpins) { if (cp.getName().equals(chanpinName)) { Toast.makeText(getContext(), "产品名称重复", Toast.LENGTH_SHORT).show(); return; } } // 创建新产品 Chanpin newChanpin = new Chanpin(); newChanpin.setId(Data.chanpins.size() + 1); newChanpin.setName(chanpinName); newChanpin.setZujians(new ArrayList<>()); Data.chanpins.add(newChanpin); refreshCallback.run(); Toast.makeText(getContext(), "产品创建成功", Toast.LENGTH_SHORT).show(); }); builder.setNegativeButton("取消", null); builder.show(); } /** * 添加新组件 */ private void showCreateZujianDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("添加新组件"); // 创建自定义布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_create_zujian_bancai, null); EditText etZujianName = dialogView.findViewById(R.id.et_zujian_name); Spinner spinnerbancai = dialogView.findViewById(R.id.spinner_bancai); SearchView searchBancai = dialogView.findViewById(R.id.search_bancai); Button btnAddBancai = dialogView.findViewById(R.id.btn_add_bancai); // 设置添加板材按钮点击事件 btnAddBancai.setOnClickListener(v -> { // 弹出添加板材的弹窗,并传入当前Spinner用于刷新 showCreateBancaiDialog(spinnerbancai); }); // 板材适配器 Adapter.setupBancaiSpinners(spinnerbancai,Data.bancais,getContext()); // 设置搜索功能 searchBancai.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { // 过滤板材列表 List<Bancai> filteredList = new ArrayList<>(); for (Bancai bancai : Data.bancais) { if ( bancai.TableText().toLowerCase().contains(newText.toLowerCase())) { filteredList.add(bancai); } } // 板材适配器 Adapter.setupBancaiSpinners(spinnerbancai,filteredList,getContext()); return true; } }); // 添加木皮预览标签 builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { // 获取用户输入 String zujianName = etZujianName.getText().toString().trim(); Bancai selectedBancai = (Bancai) spinnerbancai.getSelectedItem(); if (zujianName.isEmpty()) { Toast.makeText(getContext(), "请输入组件名称", Toast.LENGTH_SHORT).show(); return; } // 创建新组件 Zujian newZujian = new Zujian(); newZujian.setId(Data.zujians.size() + 1); newZujian.setName(zujianName); // 创建新板材 // 添加到全局列表 Data.zujians.add(newZujian); // 添加到当前产品的组件列表 Chanpin_Zujian cz = new Chanpin_Zujian(); cz.setId(selectedChanpin.getZujians().size() + 1); cz.setZujian(newZujian); cz.setBancai(selectedBancai); // 关联新创建的板材 cz.setChanpin(selectedChanpin); selectedChanpin.getZujians().add(cz); // 刷新组件下拉框 setupZujianSpinner(selectedChanpin); spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1); Toast.makeText(getContext(), "组件和板材添加成功", Toast.LENGTH_SHORT).show(); }); builder.setNegativeButton("取消", null); builder.show(); } // 显示创建板材的弹窗 private void showCreateBancaiDialog(Spinner spinnerToRefresh) { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("添加新板材"); // 加载布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_create_bancai, null); Spinner spinnerCaizhi = dialogView.findViewById(R.id.spinner_caizhi); Spinner spinnerMupi1 = dialogView.findViewById(R.id.spinner_mupi1); Spinner spinnerMupi2 = dialogView.findViewById(R.id.spinner_mupi2); EditText TextInputEditTextHoudu=dialogView.findViewById(R.id.edittext_houdu); TextInputEditTextHoudu.setTextIsSelectable(true); // 绑定新建材质按钮 Button btnNewCaizhi = dialogView.findViewById(R.id.btn_new_caizhi); btnNewCaizhi.setOnClickListener(v -> { showNewOptionDialog("材质", option -> { // 避免重复添加 for (Caizhi caizhi : Data.caizhis) { if (caizhi.getName().equals(option)) return; } // 创建新材质 Caizhi newCaizhi = new Caizhi(); newCaizhi.setName(option); newCaizhi.setId(Data.caizhis.size() + 1); newCaizhi.setBancais(new ArrayList<>()); Data.caizhis.add(newCaizhi); // 刷新下拉框 Adapter.setupCaizhiSpinner(spinnerCaizhi, Data.caizhis, requireContext()); spinnerCaizhi.setSelection(Data.caizhis.size() - 1); }); }); // 绑定新建木皮按钮 Button btnNewMupi = dialogView.findViewById(R.id.btn_new_mupi); btnNewMupi.setOnClickListener(v -> { // 弹出新建木皮对话框 showNewMupiDialog(() -> { // 回调中刷新木皮下拉框 Adapter.setupMupiSpinner(spinnerMupi1, Data.mupis, requireContext()); Adapter.setupMupiSpinner(spinnerMupi2, Data.mupis, requireContext()); }); }); // 获取所有材质选项(从现有板材中提取) List<Caizhi> allCaizhi = Data.caizhis; List<Mupi> allMupi = Data.mupis; // 设置下拉框适配器 Adapter.setupCaizhiSpinner(spinnerCaizhi, allCaizhi, requireContext()); Adapter.setupMupiSpinner(spinnerMupi1, allMupi, requireContext()); Adapter.setupMupiSpinner(spinnerMupi2, allMupi, requireContext()); builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { Caizhi caizhi = (Caizhi)spinnerCaizhi.getSelectedItem() ; Mupi mupi1 = (Mupi)spinnerMupi1.getSelectedItem() ; Mupi mupi2 = (Mupi) spinnerMupi2.getSelectedItem() ; // 获取 TextInputEditText 的内容并进行校验 String houduText = TextInputEditTextHoudu.getText().toString().trim(); Double houdu = null; try { if (!houduText.isEmpty()) { // 检查输入是否为空 houdu = Double.valueOf(houduText); // 尝试将字符串转换为 Double } } catch (NumberFormatException e) { // 捕获转换异常并提示用户 Toast.makeText(getContext(), "厚度输入无效,请输入数字", Toast.LENGTH_SHORT).show(); return; } // 校验 caizhi 和 houdu 是否均有效 if (caizhi == null || houdu == null) { Toast.makeText(getContext(), "请选择材质并输入有效的厚度", Toast.LENGTH_SHORT).show(); return; } // 创建新板材 Bancai newBancai = new Bancai(); newBancai.setId(Data.bancais.size() + 1); newBancai.setCaizhi(caizhi); newBancai.setMupi1(mupi1); newBancai.setMupi2(mupi2); newBancai.setHoudu(houdu); caizhi.getBancais().add(newBancai); if (mupi1 != null) { mupi1.getBancais().add(newBancai); } if (mupi2 != null) { mupi2.getBancais().add(newBancai); } // 添加到全局列表 Data.bancais.add(newBancai); // 刷新Spinner(如果传入) if (spinnerToRefresh != null) { Adapter.setupBancaiSpinners(spinnerToRefresh, Data.bancais, getContext()); spinnerToRefresh.setSelection(Data.bancais.size() - 1); } Toast.makeText(getContext(), "板材添加成功", Toast.LENGTH_SHORT).show(); }); builder.setNegativeButton("取消", null); builder.show(); } // 显示新建选项的弹窗 /** * 显示新建选项的弹窗 * @param type 新建什么 * @param listener 反回 */ private void showNewOptionDialog(String type, OnOptionCreatedListener listener) { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("新建" + type); final EditText input = new EditText(requireContext()); input.setHint("请输入" + type); builder.setView(input); builder.setPositiveButton("确定", (dialog, which) -> { String option = input.getText().toString().trim(); if (!option.isEmpty()) { listener.onOptionCreated(option); } }); builder.setNegativeButton("取消", null); builder.show(); } // 回调接口 interface OnOptionCreatedListener { void onOptionCreated(String option); } // 新建木皮对话框 private void showNewMupiDialog(Runnable refreshCallback) { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("新建木皮"); View view = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_new_mupi, null); EditText etName = view.findViewById(R.id.et_mupi_name); RadioGroup rgFinish = view.findViewById(R.id.rg_finish); builder.setView(view); builder.setPositiveButton("创建", (dialog, which) -> { String name = etName.getText().toString().trim(); if (name.isEmpty()) { Toast.makeText(getContext(), "请输入木皮名称", Toast.LENGTH_SHORT).show(); return; } // 避免重复添加 for (Mupi m : Data.mupis) { if (m.getName().equals(name)) return; } // 创建木皮对象 Mupi newMupi = new Mupi(); newMupi.setId(Data.mupis.size() + 1); newMupi.setName(name); newMupi.setYou(rgFinish.getCheckedRadioButtonId() == R.id.rb_painted); newMupi.setBancais(new ArrayList<>()); Data.mupis.add(newMupi); refreshCallback.run(); }); builder.setNegativeButton("取消", null); builder.show(); } } E FATAL EXCEPTION: main Process: com.example.kucun2, PID: 22195 java.lang.IllegalArgumentException: com.example.kucun2.entity.data.SynchronizableEntity is not an interface at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:635) at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:602) at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:230) at java.lang.reflect.WeakCache.get(WeakCache.java:127) at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:438) at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:873) at com.example.kucun2.entity.data.SynchronizedList.createProxy(SynchronizedList.java:186) at com.example.kucun2.entity.data.SynchronizedList.add(SynchronizedList.java:263) at com.example.kucun2.ui.jinhuo.AddInventoryFragment.createAndSaveDingdan(AddInventoryFragment.java:445) at com.example.kucun2.ui.jinhuo.AddInventoryFragment.lambda$showNewDingdanDialog$8(AddInventoryFragment.java:423) at com.example.kucun2.ui.jinhuo.AddInventoryFragment.$r8$lambda$viLBw5kNmkDSVG17JoXzuH5G85E(Unknown Source:0) at com.example.kucun2.ui.jinhuo.AddInventoryFragment$$ExternalSyntheticLambda20.onClick(D8$$SyntheticClass:0) at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:250) at android.os.Handler.dispatchMessage(Handler.java:109) at android.os.Looper.loopOnce(Looper.java:250) at android.os.Looper.loop(Looper.java:340) at android.app.ActivityThread.main(ActivityThread.java:9913) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:621) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957) 2025-06-09 20:52:42.415 22195-22195 Process com.example.kucun2 I Sending signal. PID: 22195 SIG: 9 2025-06-09 21:35:57.386 22849-22849 AndroidRuntime com.example.kucun2 E FATAL EXCEPTION: main Process: com.example.kucun2, PID: 22849 java.lang.ClassCastException: $Proxy4 cannot be cast to com.example.kucun2.entity.data.SynchronizableEntity at com.example.kucun2.entity.data.SynchronizedList.createProxy(SynchronizedList.java:188) at com.example.kucun2.entity.data.SynchronizedList.add(SynchronizedList.java:265) at com.example.kucun2.ui.jinhuo.AddInventoryFragment.createAndSaveDingdan(AddInventoryFragment.java:445) at com.example.kucun2.ui.jinhuo.AddInventoryFragment.lambda$showNewDingdanDialog$8(AddInventoryFragment.java:423) at com.example.kucun2.ui.jinhuo.AddInventoryFragment.$r8$lambda$viLBw5kNmkDSVG17JoXzuH5G85E(Unknown Source:0) at com.example.kucun2.ui.jinhuo.AddInventoryFragment$$ExternalSyntheticLambda20.onClick(D8$$SyntheticClass:0) at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:250) at android.os.Handler.dispatchMessage(Handler.java:109) at android.os.Looper.loopOnce(Looper.java:250) at android.os.Looper.loop(Looper.java:340) at android.app.ActivityThread.main(ActivityThread.java:9913) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:621) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957)

package com.example.kucun2.ui.jinhuo; import static android.content.ContentValues.TAG; import android.app.AlertDialog; import android.app.DatePickerDialog; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.MultiAutoCompleteTextView; import android.widget.RadioGroup; import android.widget.SearchView; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import com.example.kucun2.R; import com.example.kucun2.entity.*; import com.example.kucun2.entity.data.Data; import com.example.kucun2.function.Adapter; import com.google.android.material.textfield.TextInputEditText; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Random; public class AddInventoryFragment extends Fragment { private Spinner spinnerDingdan, spinnerChanpin, spinnerZujian, spinnerBancai; private EditText etShuliang; private RadioGroup rgType; private Dingdan selectedDingdan; private Chanpin selectedChanpin; private Zujian selectedZujian; private Bancai selectedBancai; // 创建新订单产品组件按钮 private Button btnNewDingdan, btnAddChanpin, btnAddZujian; // 日期格式化 private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); /** * 初始化 * @param inflater The LayoutInflater object that can be used to inflate * any views in the fragment, * @param container If non-null, this is the parent view that the fragment's * UI should be attached to. The fragment should not add the view itself, * but this can be used to generate the LayoutParams of the view. * @param savedInstanceState If non-null, this fragment is being re-constructed * from a previous saved state as given here. * * @return */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_add_inventory, container, false); // 初始化UI组件 spinnerDingdan = view.findViewById(R.id.spinner_dingdan); spinnerChanpin = view.findViewById(R.id.spinner_chanpin); spinnerZujian = view.findViewById(R.id.spinner_zujian); spinnerBancai = view.findViewById(R.id.spinner_bancai); etShuliang = view.findViewById(R.id.et_shuliang); rgType = view.findViewById(R.id.rg_type); Button btnSubmit = view.findViewById(R.id.btn_submit); // 初始化新按钮 btnNewDingdan = view.findViewById(R.id.btn_new_dingdan); btnAddChanpin = view.findViewById(R.id.btn_add_chanpin); btnAddZujian = view.findViewById(R.id.btn_add_zujian); // 设置按钮点击事件 btnNewDingdan.setOnClickListener(v -> createNewDingdan()); btnAddChanpin.setOnClickListener(v -> showAddChanpinDialog()); btnAddZujian.setOnClickListener(v -> addZujianToChanpin()); // 设置订单选择器 setupDingdanSpinner(); // 提交按钮点击事件 btnSubmit.setOnClickListener(v -> addInventoryRecord()); return view; } private void setupDingdanSpinner() { Adapter.setupDingdanSpinner(spinnerDingdan,Data.dingdans,getContext()); spinnerDingdan.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedDingdan = (Dingdan) parent.getItemAtPosition(position); setupChanpinSpinner(selectedDingdan); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupChanpinSpinner(Dingdan dingdan) { // 获取该订单的产品列表 List<Chanpin> chanpins = new ArrayList<>(); if (dingdan != null && dingdan.getDingdanChanpin() != null) { for (Dingdan_Chanpin dc : dingdan.getDingdanChanpin()) { if (dc != null && dc.getChanpin() != null) { chanpins.add(dc.getChanpin()); } } } // 设置产品下拉框适配器 Adapter.setupChanpinSpinner(spinnerChanpin, chanpins, getContext()); // 设置产品选择监听器 spinnerChanpin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedChanpin = (Chanpin) parent.getItemAtPosition(position); if (selectedChanpin != null) { setupZujianSpinner(selectedChanpin); } } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } /** * 组件下拉框刷新 * @param chanpin */ private void setupZujianSpinner(Chanpin chanpin) { // 获取该产品的组件列表 List<Zujian> zujians = new ArrayList<>(); for (Chanpin_Zujian cz : chanpin.getChanpinZujian()) { zujians.add(cz.getZujian()); } Adapter.setupZujianSpinner(spinnerZujian,zujians,getContext()); spinnerZujian.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedZujian = (Zujian) parent.getItemAtPosition(position); setupBancaiSpinner(selectedChanpin, selectedZujian); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } /** * 板材刷新 * @param chanpin * @param zujian */ private void setupBancaiSpinner(Chanpin chanpin, Zujian zujian) { // 获取该组件关联的板材 List<Bancai> bancais = new ArrayList<>(); for (Chanpin_Zujian cz : chanpin.getChanpinZujian()) { if (cz.getZujian().getId().equals(zujian.getId())) { bancais.add(cz.getBancai()); } } Adapter.setupBancaiSpinners(spinnerBancai,bancais,getContext()); spinnerBancai.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedBancai = (Bancai) parent.getItemAtPosition(position); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } // ... addInventoryRecord和createRecord方法保持不变 ... private void addInventoryRecord() { // 验证必填项 if (selectedDingdan == null || selectedChanpin == null || selectedZujian == null || selectedBancai == null) { Toast.makeText(getContext(), "请选择订单、产品、组件和板材", Toast.LENGTH_SHORT).show(); return; } String shuliangStr = etShuliang.getText().toString().trim(); if (shuliangStr.isEmpty()) { Toast.makeText(getContext(), "请输入数量", Toast.LENGTH_SHORT).show(); return; } // 解析数量 int shuliang; try { shuliang = Integer.parseInt(shuliangStr); } catch (NumberFormatException e) { Toast.makeText(getContext(), "请输入有效的数量", Toast.LENGTH_SHORT).show(); return; } // 确定操作类型(进货或消耗) boolean isJinhuo = rgType.getCheckedRadioButtonId() == R.id.rb_jinhuo; // 实际开发中应从登录信息获取当前用户 User currentUser = new User(1, "当前用户", "user", "password",1); // 创建记录 createRecord(selectedDingdan, selectedChanpin, selectedZujian, selectedBancai, shuliang, isJinhuo, currentUser); Toast.makeText(getContext(), "记录添加成功", Toast.LENGTH_SHORT).show(); etShuliang.setText(""); // 清空输入框 } private void createRecord(Dingdan dingdan, Chanpin chanpin, Zujian zujian, Bancai bancai, int shuliang, boolean isJinhuo, User user) { if (isJinhuo) { // 创建进货记录 Jinhuo jinhuo = new Jinhuo(); jinhuo.setId(Data.jinhuoList.size() + 1); jinhuo.setDingdan(dingdan); jinhuo.setChanpin(chanpin); jinhuo.setZujian(zujian); jinhuo.setBancai(bancai); jinhuo.setShuliang(shuliang); jinhuo.setDate(new Date()); jinhuo.setUser(user); Data.jinhuoList.add(jinhuo); } else { // 消耗数量转为负数 shuliang = -shuliang; } // 更新库存 updateKucun(bancai, shuliang); } private void updateKucun(Bancai bancai, int changeAmount) { // 查找现有库存记录 for (Kucun k : Data.kucuns) { if (k.getBancai().getId().equals(bancai.getId())) { k.setShuliang(k.getShuliang() + changeAmount); return; } } // 如果没有找到库存记录,创建新的 Kucun newKucun = new Kucun(); newKucun.setId(Data.kucuns.size() + 1); newKucun.setBancai(bancai); newKucun.setShuliang(Math.max(changeAmount, 0)); // 确保不为负 Data.kucuns.add(newKucun); } // 新建订单方法 private void createNewDingdan() { showNewDingdanDialog(); } /** * 向订单添加产品 * @param chanpin */ private void addChanpinToDingdan(Chanpin chanpin) { if (selectedDingdan == null||chanpin==null) { Toast.makeText(getContext(), "请先选择订单", Toast.LENGTH_SHORT).show(); return; } Log.d(TAG, "addChanpinToDingdan: "); // 检查产品是否已在订单中 for (Dingdan_Chanpin dc : selectedDingdan.getDingdanChanpin()) { if (dc.getChanpin().getId().equals(chanpin.getId())) { Toast.makeText(getContext(), "该产品已添加到订单", Toast.LENGTH_SHORT).show(); return; } } // 添加到当前订单的产品列表 Dingdan_Chanpin dc = new Dingdan_Chanpin(); //dc.setId(selectedDingdan.getDingdanChanpin().size() + 1); dc.setChanpin(chanpin); dc.setDingdan(selectedDingdan); selectedDingdan.getDingdanChanpin().add(dc); // 刷新产品下拉框 setupChanpinSpinner(selectedDingdan); // 选中新添加的产品 spinnerChanpin.setSelection(selectedDingdan.getDingdanChanpin().size() - 1); Toast.makeText(getContext(), "产品添加成功", Toast.LENGTH_SHORT).show(); } // 为当前产品添加组件 private void addZujianToChanpin() { if (selectedChanpin == null) { Toast.makeText(getContext(), "请先选择产品", Toast.LENGTH_SHORT).show(); return; } // // 创建新组件(示例) // Zujian newZujian = new Zujian(); // newZujian.setId( (Data.zujians.size() + 1)); // newZujian.setName("新组件" + System.currentTimeMillis()); // // // 添加到全局列表 // Data.zujians.add(newZujian); // // // 添加到当前产品的组件列表 // Chanpin_Zujian cz = new Chanpin_Zujian(); // cz.setId(selectedChanpin.getZujians().size() + 1); // cz.setZujian(newZujian); // cz.setChanpin(selectedChanpin); // selectedChanpin.getZujians().add(cz); // // // 刷新组件下拉框 // setupZujianSpinner(selectedChanpin); // spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1); // // Toast.makeText(getContext(), "组件添加成功", Toast.LENGTH_SHORT).show(); showCreateZujianDialog(); } // 新建订单对话框 /*** * 新建订单对话框 */ private void showNewDingdanDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("新建订单"); // 加载布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_new_dingdan, null); EditText etOrderNumber = dialogView.findViewById(R.id.et_order_number); EditText etOrderDate = dialogView.findViewById(R.id.et_order_date); EditText etDeliveryDate = dialogView.findViewById(R.id.et_delivery_date); Button btnPickOrderDate = dialogView.findViewById(R.id.btn_pick_order_date); Button btnPickDeliveryDate = dialogView.findViewById(R.id.btn_pick_delivery_date); // 设置今日日期作为默认值 Date today = new Date(); etOrderDate.setText(dateFormat.format(today)); // 日期选择监听器 DatePickerDialog.OnDateSetListener orderDateListener = (view, year, month, dayOfMonth) -> { Calendar cal = Calendar.getInstance(); cal.set(year, month, dayOfMonth); etOrderDate.setText(dateFormat.format(cal.getTime())); }; DatePickerDialog.OnDateSetListener deliveryDateListener = (view, year, month, dayOfMonth) -> { Calendar cal = Calendar.getInstance(); cal.set(year, month, dayOfMonth); etDeliveryDate.setText(dateFormat.format(cal.getTime())); }; // 下单日期选择按钮 btnPickOrderDate.setOnClickListener(v -> { Calendar cal = Calendar.getInstance(); new DatePickerDialog(requireContext(), orderDateListener, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)) .show(); }); /** * / 出货日期选择按钮 */ btnPickDeliveryDate.setOnClickListener(v -> { Calendar cal = Calendar.getInstance(); new DatePickerDialog(requireContext(), deliveryDateListener, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)) .show(); }); builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { String orderNumber = etOrderNumber.getText().toString().trim(); String orderDateStr = etOrderDate.getText().toString(); String deliveryDateStr = etDeliveryDate.getText().toString(); for (Dingdan dingdan:Data.dingdans ) { if (dingdan.getNumber()==null||orderNumber==null){ Log.d(TAG, "showNewDingdanDialog: "); return; } if(dingdan.getNumber().equals(orderNumber)){ Toast.makeText(getContext(), "已有该订单号", Toast.LENGTH_SHORT).show(); return; } } // 验证输入 if (orderNumber.isEmpty()) { Toast.makeText(getContext(), "请输入订单号", Toast.LENGTH_SHORT).show(); return; } try { // 解析日期 Date orderDate = dateFormat.parse(orderDateStr); Date deliveryDate = deliveryDateStr.isEmpty() ? null : dateFormat.parse(deliveryDateStr); // 创建订单 createAndSaveDingdan(orderNumber, orderDate, deliveryDate); } catch (ParseException e) { Toast.makeText(getContext(), "日期格式错误", Toast.LENGTH_SHORT).show(); } }); builder.setNegativeButton("取消", null); builder.show(); } /** * 创建并保存订单 */ private void createAndSaveDingdan(String orderNumber, Date orderDate, Date deliveryDate) { Dingdan newDingdan = new Dingdan(); newDingdan.setId(Data.dingdans.size() + 1); newDingdan.setNumber(orderNumber); newDingdan.setXiadan(orderDate); newDingdan.setJiaohuo(deliveryDate); newDingdan.setDingdanChanpin(new ArrayList<>()); newDingdan.setDingdanChanpinZujian(new ArrayList<>()); Data.dingdans.add(newDingdan); // 刷新下拉框 setupDingdanSpinner(); spinnerDingdan.setSelection(Data.dingdans.size() - 1); Toast.makeText(getContext(), "新建订单成功", Toast.LENGTH_SHORT).show(); } /** * 显示添加产品弹窗 */ private void showAddChanpinDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("添加产品到订单"); // 加载布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_add_chanpin, null); Spinner spinnerChanpinSelection = dialogView.findViewById(R.id.spinner_chanpin_selection); Button btnNewChanpin = dialogView.findViewById(R.id.btn_new_chanpin); // 设置产品下拉框 if (Data.chanpins == null || Data.chanpins.isEmpty()) { Toast.makeText(getContext(), "没有可用的产品,请先创建产品", Toast.LENGTH_SHORT).show(); return; } Adapter.setupChanpinSpinner(spinnerChanpinSelection, Data.chanpins, getContext()); // 新建产品按钮点击事件 btnNewChanpin.setOnClickListener(v -> { showNewChanpinDialog(() -> { // 新建产品后刷新下拉框 Adapter.setupChanpinSpinner(spinnerChanpinSelection, Data.chanpins, getContext()); // 默认选中新建的产品 spinnerChanpinSelection.setSelection(Data.chanpins.size() - 1); }); }); builder.setView(dialogView); builder.setPositiveButton("添加", (dialog, which) -> { Chanpin selectedChanpin = (Chanpin) spinnerChanpinSelection.getSelectedItem(); if (selectedChanpin == null) { Toast.makeText(getContext(), "请选择一个产品", Toast.LENGTH_SHORT).show(); return; } // 将选中的产品添加到当前订单 addChanpinToDingdan(selectedChanpin); }); builder.setNegativeButton("取消", null); builder.show(); } /** * 显示新建产品弹窗 * @param refreshCallback 新建后的回调,用于刷新产品列表 */ private void showNewChanpinDialog(Runnable refreshCallback) { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("新建产品"); View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_new_chanpin, null); EditText etChanpinName = dialogView.findViewById(R.id.et_chanpin_name); builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { String chanpinName = etChanpinName.getText().toString().trim(); if (chanpinName.isEmpty()) { Toast.makeText(getContext(), "请输入产品名称", Toast.LENGTH_SHORT).show(); return; } // 检查名称是否重复 for (Chanpin cp : Data.chanpins) { if (cp.getBianhao().equals(chanpinName)) { Toast.makeText(getContext(), "产品名称重复", Toast.LENGTH_SHORT).show(); return; } } // 创建新产品 Chanpin newChanpin = new Chanpin(); newChanpin.setId(Data.chanpins.size() + 1); newChanpin.setBianhao(chanpinName); newChanpin.setChanpinZujian(new ArrayList<>()); Data.chanpins.add(newChanpin); refreshCallback.run(); Toast.makeText(getContext(), "产品创建成功", Toast.LENGTH_SHORT).show(); }); builder.setNegativeButton("取消", null); builder.show(); } /** * 添加新组件 */ private void showCreateZujianDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("添加新组件"); // 创建自定义布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_create_zujian_bancai, null); EditText etZujianName = dialogView.findViewById(R.id.et_zujian_name); Spinner spinnerbancai = dialogView.findViewById(R.id.spinner_bancai); SearchView searchBancai = dialogView.findViewById(R.id.search_bancai); Button btnAddBancai = dialogView.findViewById(R.id.btn_add_bancai); // 设置添加板材按钮点击事件 btnAddBancai.setOnClickListener(v -> { // 弹出添加板材的弹窗,并传入当前Spinner用于刷新 showCreateBancaiDialog(spinnerbancai); }); // 板材适配器 Adapter.setupBancaiSpinners(spinnerbancai,Data.bancais,getContext()); // 设置搜索功能 searchBancai.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { // 过滤板材列表 List<Bancai> filteredList = new ArrayList<>(); for (Bancai bancai : Data.bancais) { if ( bancai.TableText().toLowerCase().contains(newText.toLowerCase())) { filteredList.add(bancai); } } // 板材适配器 Adapter.setupBancaiSpinners(spinnerbancai,filteredList,getContext()); return true; } }); // 添加木皮预览标签 builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { // 获取用户输入 String zujianName = etZujianName.getText().toString().trim(); Bancai selectedBancai = (Bancai) spinnerbancai.getSelectedItem(); if (zujianName.isEmpty()) { Toast.makeText(getContext(), "请输入组件名称", Toast.LENGTH_SHORT).show(); return; } // 创建新组件 Zujian newZujian = new Zujian(); newZujian.setId(Data.zujians.size() + 1); newZujian.setName(zujianName); // 创建新板材 // 添加到全局列表 Data.zujians.add(newZujian); // 添加到当前产品的组件列表 Chanpin_Zujian cz = new Chanpin_Zujian(); cz.setZujian(newZujian); cz.setBancai(selectedBancai); // 关联新创建的板材 cz.setChanpin(selectedChanpin); selectedChanpin.getChanpinZujian().add(cz); // 刷新组件下拉框 setupZujianSpinner(selectedChanpin); spinnerZujian.setSelection(selectedChanpin.getChanpinZujian().size() - 1); Toast.makeText(getContext(), "组件和板材添加成功", Toast.LENGTH_SHORT).show(); }); builder.setNegativeButton("取消", null); builder.show(); } // 显示创建板材的弹窗 private void showCreateBancaiDialog(Spinner spinnerToRefresh) { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("添加新板材"); // 加载布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_create_bancai, null); Spinner spinnerCaizhi = dialogView.findViewById(R.id.spinner_caizhi); Spinner spinnerMupi1 = dialogView.findViewById(R.id.spinner_mupi1); Spinner spinnerMupi2 = dialogView.findViewById(R.id.spinner_mupi2); EditText TextInputEditTextHoudu=dialogView.findViewById(R.id.edittext_houdu); TextInputEditTextHoudu.setTextIsSelectable(true); // 绑定新建材质按钮 Button btnNewCaizhi = dialogView.findViewById(R.id.btn_new_caizhi); btnNewCaizhi.setOnClickListener(v -> { showNewOptionDialog("材质", option -> { // 避免重复添加 for (Caizhi caizhi : Data.caizhis) { if (caizhi.getName().equals(option)) return; } // 创建新材质 Caizhi newCaizhi = new Caizhi(); newCaizhi.setName(option); newCaizhi.setId(Data.caizhis.size() + 1); newCaizhi.setBancai(new ArrayList<>()); Data.caizhis.add(newCaizhi); // 刷新下拉框 Adapter.setupCaizhiSpinner(spinnerCaizhi, Data.caizhis, requireContext()); spinnerCaizhi.setSelection(Data.caizhis.size() - 1); }); }); // 绑定新建木皮按钮 Button btnNewMupi = dialogView.findViewById(R.id.btn_new_mupi); btnNewMupi.setOnClickListener(v -> { // 弹出新建木皮对话框 showNewMupiDialog(() -> { // 回调中刷新木皮下拉框 Adapter.setupMupiSpinner(spinnerMupi1, Data.mupis, requireContext()); Adapter.setupMupiSpinner(spinnerMupi2, Data.mupis, requireContext()); }); }); // 获取所有材质选项(从现有板材中提取) List<Caizhi> allCaizhi = Data.caizhis; List<Mupi> allMupi = Data.mupis; // 设置下拉框适配器 Adapter.setupCaizhiSpinner(spinnerCaizhi, allCaizhi, requireContext()); Adapter.setupMupiSpinner(spinnerMupi1, allMupi, requireContext()); Adapter.setupMupiSpinner(spinnerMupi2, allMupi, requireContext()); builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { Caizhi caizhi = (Caizhi)spinnerCaizhi.getSelectedItem() ; Mupi mupi1 = (Mupi)spinnerMupi1.getSelectedItem() ; Mupi mupi2 = (Mupi) spinnerMupi2.getSelectedItem() ; // 获取 TextInputEditText 的内容并进行校验 String houduText = TextInputEditTextHoudu.getText().toString().trim(); Double houdu = null; try { if (!houduText.isEmpty()) { // 检查输入是否为空 houdu = Double.valueOf(houduText); // 尝试将字符串转换为 Double } } catch (NumberFormatException e) { // 捕获转换异常并提示用户 Toast.makeText(getContext(), "厚度输入无效,请输入数字", Toast.LENGTH_SHORT).show(); return; } // 校验 caizhi 和 houdu 是否均有效 if (caizhi == null || houdu == null) { Toast.makeText(getContext(), "请选择材质并输入有效的厚度", Toast.LENGTH_SHORT).show(); return; } // 创建新板材 Bancai newBancai = new Bancai(); newBancai.setId(Data.bancais.size() + 1); newBancai.setCaizhi(caizhi); newBancai.setMupi1(mupi1); newBancai.setMupi2(mupi2); newBancai.setHoudu(houdu); caizhi.getBancai().add(newBancai); if (mupi1 != null) { mupi1.getBancais().add(newBancai); } if (mupi2 != null) { mupi2.getBancais().add(newBancai); } // 添加到全局列表 Data.bancais.add(newBancai); // 刷新Spinner(如果传入) if (spinnerToRefresh != null) { Adapter.setupBancaiSpinners(spinnerToRefresh, Data.bancais, getContext()); spinnerToRefresh.setSelection(Data.bancais.size() - 1); } Toast.makeText(getContext(), "板材添加成功", Toast.LENGTH_SHORT).show(); }); builder.setNegativeButton("取消", null); builder.show(); } // 显示新建选项的弹窗 /** * 显示新建选项的弹窗 * @param type 新建什么 * @param listener 反回 */ private void showNewOptionDialog(String type, OnOptionCreatedListener listener) { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("新建" + type); final EditText input = new EditText(requireContext()); input.setHint("请输入" + type); builder.setView(input); builder.setPositiveButton("确定", (dialog, which) -> { String option = input.getText().toString().trim(); if (!option.isEmpty()) { listener.onOptionCreated(option); } }); builder.setNegativeButton("取消", null); builder.show(); } // 回调接口 interface OnOptionCreatedListener { void onOptionCreated(String option); } // 新建木皮对话框 private void showNewMupiDialog(Runnable refreshCallback) { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("新建木皮"); View view = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_new_mupi, null); EditText etName = view.findViewById(R.id.et_mupi_name); RadioGroup rgFinish = view.findViewById(R.id.rg_finish); builder.setView(view); builder.setPositiveButton("创建", (dialog, which) -> { String name = etName.getText().toString().trim(); if (name.isEmpty()) { Toast.makeText(getContext(), "请输入木皮名称", Toast.LENGTH_SHORT).show(); return; } // 避免重复添加 for (Mupi m : Data.mupis) { if (m.getName().equals(name)) return; } // 创建木皮对象 Mupi newMupi = new Mupi(); newMupi.setId(Data.mupis.size() + 1); newMupi.setName(name); newMupi.setYou(rgFinish.getCheckedRadioButtonId() == R.id.rb_painted); newMupi.setBancais(new ArrayList<>()); Data.mupis.add(newMupi); refreshCallback.run(); }); builder.setNegativeButton("取消", null); builder.show(); } }<?xml version="1.0" encoding="utf-8"?> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="组件选择" android:textStyle="bold" android:layout_marginTop="8dp"/> <Spinner android:id="@+id/et_zujian_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:padding="8dp"/> <Button android:id="@+id/btn_add_zujian" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="+" android:layout_marginLeft="8dp"/> <SearchView android:id="@+id/search_bancai" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:queryHint="搜索板材..." android:iconifiedByDefault="false" android:layout_marginBottom="8dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="板材选择" android:textStyle="bold" android:layout_marginTop="8dp"/> <Spinner android:id="@+id/spinner_bancai" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:padding="8dp"/> <Button android:id="@+id/btn_add_bancai" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="+" android:layout_marginLeft="8dp"/> <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="选择订单" /> <Spinner android:id="@+id/spinner_dingdan" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:prompt="@string/select_dingdan" /> <Button android:id="@+id/btn_new_dingdan" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="新建订单" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="选择产品" android:layout_marginTop="16dp"/> <Spinner android:id="@+id/spinner_chanpin" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:prompt="@string/select_chanpin" /> <Button android:id="@+id/btn_add_chanpin" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="添加产品" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="选择组件" android:layout_marginTop="16dp"/> <Spinner android:id="@+id/spinner_zujian" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:prompt="@string/select_zujian" /> <Button android:id="@+id/btn_add_zujian" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="添加组件" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="选择板材" android:layout_marginTop="16dp"/> <Spinner android:id="@+id/spinner_bancai" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:prompt="@string/select_bancai" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="数量" android:layout_marginTop="16dp"/> <EditText android:id="@+id/et_shuliang" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="number" /> <RadioGroup android:id="@+id/rg_type" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:orientation="horizontal"> <RadioButton android:id="@+id/rb_jinhuo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="进货" android:checked="true"/> <RadioButton android:id="@+id/rb_xiaohao" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="消耗" /> </RadioGroup> <Button android:id="@+id/btn_submit" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="提交" /> </ScrollView>E FATAL EXCEPTION: main Process: com.example.kucun2, PID: 15672 java.lang.ClassCastException: androidx.appcompat.widget.AppCompatSpinner cannot be cast to android.widget.EditText at com.example.kucun2.ui.jinhuo.AddInventoryFragment.showCreateZujianDialog(AddInventoryFragment.java:565) at com.example.kucun2.ui.jinhuo.AddInventoryFragment.addZujianToChanpin(AddInventoryFragment.java:344) at com.example.kucun2.ui.jinhuo.AddInventoryFragment.lambda$onCreateView$2(AddInventoryFragment.java:90) at com.example.kucun2.ui.jinhuo.AddInventoryFragment.$r8$lambda$g7ZiJT_Sfp7Zl8Vt7clUdS_KcN8(Unknown Source:0) at com.example.kucun2.ui.jinhuo.AddInventoryFragment$$ExternalSyntheticLambda2.onClick(D8$$SyntheticClass:0) at android.view.View.performClick(View.java:8166) at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1218) at android.view.View.performClickInternal(View.java:8143) at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0) at android.view.View$PerformClick.run(View.java:32198)

package com.example.kucun2.ui.dingdan;//package com.example.kucun2; import static android.content.ContentValues.TAG; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.app.AlertDialog; import android.content.Context; import android.graphics.Color; import android.graphics.Typeface; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import android.widget.PopupMenu; import android.widget.SearchView; import android.widget.Spinner; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.Toast; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import com.example.kucun2.R; import com.example.kucun2.View.HorizontalScrollTextView; import com.example.kucun2.entity.Bancai; import com.example.kucun2.entity.Chanpin; import com.example.kucun2.entity.Chanpin_Zujian; import com.example.kucun2.entity.Dingdan; import com.example.kucun2.entity.Dingdan_chanpin_zujian; import com.example.kucun2.entity.Dingdan_Chanpin; import com.example.kucun2.entity.data.Data; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; public class OrderDisplayFragment extends Fragment { private TableLayout table; private HorizontalScrollView horizontalScrollView; private ValueAnimator scrollIndicatorAnimator; private boolean isIndicatorVisible = false; // 添加排序相关的成员变量 private int currentSortColumn = -1; private boolean sortAscending = true; private List<Object[]> allTableRowsData = new ArrayList<>(); // 添加搜索相关成员变量 private SearchView searchView; private Spinner columnSelector; private List<Object[]> filteredTableRowsData = new ArrayList<>(); /** *加载初始化 * @param inflater The LayoutInflater object that can be used to inflate * any views in the fragment, * @param container If non-null, this is the parent view that the fragment's * UI should be attached to. The fragment should not add the view itself, * but this can be used to generate the LayoutParams of the view. * @param savedInstanceState If non-null, this fragment is being re-constructed * from a previous saved state as given here. * * @return */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_order_display, container, false); table = view.findViewById(R.id.orderTable); horizontalScrollView = view.findViewById(R.id.horizontalScrollContainer); View scrollIndicator = view.findViewById(R.id.scroll_indicator); // 获取搜索控件 searchView = view.findViewById(R.id.search_view); columnSelector = view.findViewById(R.id.column_selector); // 初始化表头选择器 initColumnSelector(); // 设置搜索监听 searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { applySearchFilter(); return true; } @Override public boolean onQueryTextChange(String newText) { applySearchFilter(); return true; } }); LinearLayout fixedSearchBar = view.findViewById(R.id.fixedSearchBar); View placeholder = view.findViewById(R.id.search_bar_placeholder); // 添加全局布局监听器以获取正确的搜索框高度 fixedSearchBar.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 获取搜索框的实际高度 int searchBarHeight = fixedSearchBar.getHeight(); // 设置占位视图的高度 ViewGroup.LayoutParams params = placeholder.getLayoutParams(); params.height = searchBarHeight; placeholder.setLayoutParams(params); // 确保仅运行一次 fixedSearchBar.getViewTreeObserver().removeOnGlobalLayoutListener(this); } } ); Log.d(TAG, "onCreateView: "+Data.dingdans.get(0).getNumber()); // 添加表头 addTableHeader(table); // 填充表格数据 fillTableData(); // 添加滚动监听 horizontalScrollView.getViewTreeObserver().addOnScrollChangedListener(() -> { int maxScroll = horizontalScrollView.getChildAt(0).getWidth() - horizontalScrollView.getWidth(); int currentScroll = horizontalScrollView.getScrollX(); if (currentScroll > 0 && maxScroll > 0) { if (!isIndicatorVisible) { showScrollIndicator(); } // 更新滚动指示器位置 updateScrollIndicatorPosition(currentScroll, maxScroll); } else { hideScrollIndicator(); } }); return view; } /** * 获取数据 */ private void fillTableData() { List<Dingdan> orders = Data.dingdans; List<Dingdan_Chanpin> orderProducts = Data.dingdanChanpins; List<Dingdan_chanpin_zujian> orderMaterials = Data.dingdanBancais; for (Dingdan order : orders) { for (Dingdan_Chanpin orderProduct : orderProducts) { if (orderProduct.getDingdan().getId().equals(order.getId())) { Chanpin product = orderProduct.getChanpin(); for (Chanpin_Zujian component : product.getChanpinZujian()) { for (Dingdan_chanpin_zujian material : orderMaterials) { // 创建行数据但不立即添加到表格 Object[] rowData = createRowData( order, product,orderProduct, component, material ); allTableRowsData.add(rowData); filteredTableRowsData.add(rowData); // if (material.getZujian() != null && // material.getZujian().getId().equals(component.getId())) { // // addTableRow(createRowData( // order, product, component, material // )); // } } } } } } // 初始排序 sortTableData(-1, true); // 初始显示原始顺序 } /** * 排序表格数据并刷新显示 * @param columnIndex 要排序的列索引 * @param ascending 是否升序排列 */ private void sortTableData(int columnIndex, boolean ascending) { // 更新排序状态 if (columnIndex >= 0) { if (currentSortColumn == columnIndex) { // 相同列点击时切换排序方向 sortAscending = !ascending; } else { currentSortColumn = columnIndex; sortAscending = true; // 新列默认升序 } } // 创建排序比较器 Comparator<Object[]> comparator = (row1, row2) -> { if (currentSortColumn < 0) { return 0; // 返回0表示相等,保持原顺序 } Object value1 = row1[currentSortColumn]; Object value2 = row2[currentSortColumn]; if (value1 == null && value2 == null) return 0; if (value1 == null) return -1; if (value2 == null) return 1; // 根据不同列数据类型定制比较规则 try { // 数值列:2(数量), 5(板材/组件), 6(订购数量) if (currentSortColumn == 2 || currentSortColumn == 5 || currentSortColumn == 6) { double d1 = Double.parseDouble(value1.toString()); double d2 = Double.parseDouble(value2.toString()); return sortAscending ? Double.compare(d1, d2) : Double.compare(d2, d1); } // 其他列按字符串排序 else { String s1 = value1.toString().toLowerCase(); String s2 = value2.toString().toLowerCase(); return sortAscending ? s1.compareTo(s2) : s2.compareTo(s1); } } catch (NumberFormatException e) { // 解析失败时按字符串比较 String s1 = value1.toString().toLowerCase(); String s2 = value2.toString().toLowerCase(); return sortAscending ? s1.compareTo(s2) : s2.compareTo(s1); } }; // 刷新表格显示 Collections.sort(filteredTableRowsData, comparator); // 刷新显示 refreshTableWithData(filteredTableRowsData); } /** * 表格数据动态添加 * @param rowData */ private void addTableRow(Object[] rowData) { TableRow row = new TableRow(requireContext()); TableLayout.LayoutParams rowParams = new TableLayout.LayoutParams( TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT ); row.setLayoutParams(rowParams); row.setMinimumHeight(dpToPx(36)); for (int i = 0; i < rowData.length; i++) { final Object data = rowData[i]; // 判断是否为操作列(最后一列) if (i == rowData.length - 1) { // 创建操作按钮 Button actionButton = new Button(requireContext()); actionButton.setText("操作"); actionButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); actionButton.setBackgroundResource(R.drawable.btn_selector); // 自定义按钮样式 // 设置按钮点击监听器 actionButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { handleRowAction(rowData,v); } }); // 设置按钮布局参数 TableRow.LayoutParams btnParams = new TableRow.LayoutParams( 0, // 宽度由权重控制 TableRow.LayoutParams.WRAP_CONTENT, 0.5f ); btnParams.weight = 0.5f; int margin = dpToPx(1); btnParams.setMargins(margin, margin, margin, margin); actionButton.setLayoutParams(btnParams); actionButton.setHeight(11); row.addView(actionButton); } else { // 正常文本列的代码(保持原逻辑) HorizontalScrollTextView textView = new HorizontalScrollTextView(requireContext()); textView.setText(String.valueOf(data)); textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); int padding = dpToPx(8); textView.setPadding(padding, padding / 2, padding, padding); textView.setMinWidth(dpToPx(50)); TableRow.LayoutParams colParams=null; // 设置背景边框 textView.setBackgroundResource(R.drawable.cell_border); if ( data.toString().length() > 10){ colParams = new TableRow.LayoutParams( 0, // 宽度将由权重控制 TableRow.LayoutParams.MATCH_PARENT, 2.0f ); colParams.weight = 2; }else{ colParams = new TableRow.LayoutParams( 0, // 宽度将由权重控制 TableRow.LayoutParams.MATCH_PARENT, 1.0f ); colParams.weight = 1; } textView.setLayoutParams(colParams); row.addView(textView); } } table.addView(row); } // 动态添加表头 (使用自定义TextView) private void addTableHeader(TableLayout table) { TableRow headerRow = new TableRow(requireContext()); headerRow.setLayoutParams(new TableLayout.LayoutParams( TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT )); // 设置行背景颜色 headerRow.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.purple_500)); // 定义表头 // 更新表头数组(添加操作列) String[] headers = getResources().getStringArray(R.array.table_headers); List<String> headerList = new ArrayList<>(Arrays.asList(headers)); headerList.add("操作"); // 添加操作列标题 headers = headerList.toArray(new String[0]); // 更新权重数组(添加操作列权重) float[] weights = {1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 1.0f, 1.0f, 0.5f}; // 新增操作列权重0.5 // 更新优先级数组(添加操作列优先级) boolean[] priority = {false, false, false, false, true, false, false, false}; for (int i = 0; i < headers.length; i++) { HorizontalScrollTextView headerView = new HorizontalScrollTextView(requireContext()); headerView.setText(headers[i]); headerView.setTextColor(Color.WHITE); headerView.setTypeface(null, Typeface.BOLD); headerView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); headerView.setPadding(dpToPx(8), dpToPx(8), dpToPx(8), dpToPx(8)); // 为优先级高的列设置最小宽度 if (priority[i]) { headerView.setMinWidth(dpToPx(220)); } // 设置布局参数 TableRow.LayoutParams colParams = new TableRow.LayoutParams( priority[i] ? TableRow.LayoutParams.WRAP_CONTENT : 0, TableRow.LayoutParams.MATCH_PARENT, priority[i] ? 0 : weights[i] // 优先级列不使用权重 ); headerView.setLayoutParams(colParams); final int columnIndex = i; headerView.setOnClickListener(v -> { // 排序并刷新表格 sortTableData(columnIndex, sortAscending); // 更新排序指示器(可选) showSortIndicator(headerView); }); headerRow.addView(headerView); } table.addView(headerRow); } // 添加排序指示器(可选) private void showSortIndicator(View header) { // 实现:在表头右侧添加↑或↓指示符 // 实现逻辑根据设计需求 // header.setTooltipText(new ); } /** * */ private void showScrollIndicator() { isIndicatorVisible = true; View indicator = getView().findViewById(R.id.scroll_indicator); if (scrollIndicatorAnimator != null && scrollIndicatorAnimator.isRunning()) { scrollIndicatorAnimator.cancel(); } indicator.setVisibility(View.VISIBLE); indicator.setAlpha(0f); scrollIndicatorAnimator = ObjectAnimator.ofFloat(indicator, "alpha", 0f, 0.8f); scrollIndicatorAnimator.setDuration(300); scrollIndicatorAnimator.start(); } /**+ * */ private void hideScrollIndicator() { isIndicatorVisible = false; View indicator = getView().findViewById(R.id.scroll_indicator); if (scrollIndicatorAnimator != null && scrollIndicatorAnimator.isRunning()) { scrollIndicatorAnimator.cancel(); } scrollIndicatorAnimator = ObjectAnimator.ofFloat(indicator, "alpha", indicator.getAlpha(), 0f); scrollIndicatorAnimator.setDuration(300); scrollIndicatorAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { indicator.setVisibility(View.INVISIBLE); } }); scrollIndicatorAnimator.start(); } /** * * @param currentScroll * @param maxScroll */ private void updateScrollIndicatorPosition(int currentScroll, int maxScroll) { View indicator = getView().findViewById(R.id.scroll_indicator); FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) indicator.getLayoutParams(); // 计算指示器位置(0-100%) float percentage = (float) currentScroll / maxScroll; int maxMargin = getResources().getDisplayMetrics().widthPixels - indicator.getWidth(); // 设置右边距(控制位置) params.rightMargin = (int) (maxMargin * percentage); indicator.setLayoutParams(params); } // 处理行操作的方法 private void handleRowAction(Object[] rowData ,View anchorButton) { // 安全地从行数据中提取关键信息 String orderNumber = safeGetString(rowData[0]); // 订单号 String productId = safeGetString(rowData[1]); // 产品ID String componentName = safeGetString(rowData[3]); // 组件名称 // 安全地获取订购数量 double materialQuantity = 0.0; try { if (rowData[6] != null) { if (rowData[6] instanceof Number) { materialQuantity = ((Number) rowData[6]).doubleValue(); } else { materialQuantity = Double.parseDouble(rowData[6].toString()); } } } catch (Exception e) { Log.e("OrderFragment", "Failed to parse material quantity", e); } Context context = getContext(); if (context == null || anchorButton == null) { Log.w("PopupMenu", "Context or anchorButton is null"); return; } PopupMenu popupMenu = new PopupMenu(context, anchorButton); // 强制设置菜单在锚点视图下方显示(关键设置) popupMenu.setGravity(Gravity.BOTTOM); // 如果使用支持库,设置弹出方向 // 设置在锚点视图下方显示 // popupMenu.setOverlapAnchor(true); // 填充菜单项 popupMenu.getMenuInflater().inflate(R.menu.row_actions_menu, popupMenu.getMenu()); // 设置菜单项点击监听器 popupMenu.setOnMenuItemClickListener(item -> { int itemId = item.getItemId(); if (itemId == R.id.action_view_details) { showDetailDialog(orderNumber, productId); return true; } else if (itemId == R.id.action_edit) { editRowData(rowData); return true; } else if (itemId == R.id.action_delete) { deleteRowWithConfirm(rowData); return true; } return false; }); popupMenu.show(); } // 安全获取字符串值的方法 private String safeGetString(Object value) { if (value == null) return ""; if (value instanceof String) return (String) value; return value.toString(); } // 查看详情对话框 private void showDetailDialog(String orderNumber, String productId) { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("订单详情") .setMessage("订单号: " + orderNumber + "\n产品ID: " + productId) .setPositiveButton("确定", null) .show(); } // 编辑行数据 private void editRowData(Object[] rowData) { // 实现编辑逻辑 // 这里创建包含表单的对话框 Toast.makeText(requireContext(), "编辑操作: " + rowData[0], Toast.LENGTH_SHORT).show(); } // 带确认的删除操作 private void deleteRowWithConfirm(Object[] rowData) { new AlertDialog.Builder(requireContext()) .setTitle("确认删除") .setMessage("确定要删除订单 " + rowData[0] + " 吗?") .setPositiveButton("删除", (dialog, which) -> { // 实际删除逻辑 deleteRow(rowData); }) .setNegativeButton("取消", null) .show(); } // 实际删除行数据 private void deleteRow(Object[] rowData) { // 1. 从allTableRowsData中移除对应行 for (Iterator<Object[]> iterator = allTableRowsData.iterator(); iterator.hasNext();) { Object[] row = iterator.next(); if (Arrays.equals(row, rowData)) { iterator.remove(); break; } } // 2. 从filteredTableRowsData中移除 filteredTableRowsData.removeIf(row -> Arrays.equals(row, rowData)); // 3. 刷新表格 refreshTableWithData(filteredTableRowsData); Toast.makeText(requireContext(), "已删除订单", Toast.LENGTH_SHORT).show(); } // DP转PX工具方法 private int dpToPx(int dp) { return (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics() ); } /** * 数据组合 * @param order * @param product * @param component * @param material * @return */ private Object[] createRowData(Dingdan order, Chanpin product,Dingdan_Chanpin dingdan_chanpin, Chanpin_Zujian component, Dingdan_chanpin_zujian material) { Bancai board = material.getBancai(); String boardInfo = board.TableText(); ; return new Object[] { order.getNumber(), // 订单号 product.getBianhao(), // 产品编号 dingdan_chanpin.getShuliang(), // 产品数量 (根据需求调整) component.getZujian().getName(), // 组件名 boardInfo, // 板材信息 Math.round(component.getOne_howmany()), // 板材/组件 material.getShuliang() , // 订购数量 "操作" }; } // 初始化列选择器 private void initColumnSelector() { ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource( requireContext(), R.array.table_headers, android.R.layout.simple_spinner_item ); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); columnSelector.setAdapter(adapter); // 添加"所有列"选项 columnSelector.setSelection(0); // 默认选择第一个选项(所有列) // 列选择变化监听 columnSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { applySearchFilter(); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } // 应用搜索过滤 private void applySearchFilter() { String query = searchView.getQuery().toString().trim().toLowerCase(); int selectedColumn = columnSelector.getSelectedItemPosition(); filteredTableRowsData.clear(); if (query.isEmpty()) { // 没有搜索词,显示所有数据 filteredTableRowsData.addAll(allTableRowsData); } else { // 根据选择的列进行过滤 for (Object[] row : allTableRowsData) { // 如果选择"所有列"(位置0),检查所有列 if (selectedColumn == 0) { for (Object cell : row) { if (cell != null && cell.toString().toLowerCase().contains(query)) { filteredTableRowsData.add(row); break; } } } // 检查特定列 else if (selectedColumn >= 1 && selectedColumn <= row.length) { int columnIndex = selectedColumn - 1; // 调整索引(0=所有列,1=第一列) if (row[columnIndex] != null && row[columnIndex].toString().toLowerCase().contains(query)) { filteredTableRowsData.add(row); } } } } // 刷新表格显示 refreshTableWithData(filteredTableRowsData); } /** * 刷新表格显示 */ private void refreshTableWithData(Iterable<? extends Object[]> dataToShow) { // 移除除表头外的所有行 removeAllRowsSafely(); // 添加过滤后的行 for (Object[] rowData : dataToShow) { addTableRow(rowData); } } private void removeAllRowsSafely() { // 移除除表头外的所有行(如果有表头) if (table.getChildCount() > 0) { // 保留表头(索引0) for (int i = table.getChildCount() - 1; i >= 1; i--) { View child = table.getChildAt(i); table.removeView(child); // 清理视图引用(非常重要!) cleanupRowViews((TableRow) child); } } } private void cleanupRowViews(TableRow row) { int childCount = row.getChildCount(); for (int i = 0; i < childCount; i++) { View view = row.getChildAt(i); // 解除视图的所有监听器 view.setOnClickListener(null); // 特别是操作按钮,需要取消所有监听器 if (view instanceof Button) { Button button = (Button) view; button.setOnClickListener(null); // 清空按钮的数据引用 button.setTag(null); } } // 从父视图中移除行 if (row.getParent() != null) { ((ViewGroup) row.getParent()).removeView(row); } } }package com.example.kucun2.entity.data; import android.util.Log; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; /** * 支持数据变更自动同步的泛型集合类 * 基于SynchronizableEntity的事件机制实现数据变更自动同步 * * @param <T> 必须是SynchronizableEntity或其子类 */ public class SynchronizedList<T extends SynchronizableEntity> implements List<T> { // 使用ArrayList作为底层存储 private final List<T> list = new ArrayList<>(); public SynchronizedList(Class T ) { } // 实体变更监听器 private final EntityChangeListener<T> entityChangeListener = new EntityChangeListener<>(); @Override public int size() { return list.size(); } @Override public boolean isEmpty() { return list.isEmpty(); } @Override public boolean contains(Object o) { return list.contains(o); } @Override public Iterator<T> iterator() { return new SyncedIterator<>(list.iterator(), entityChangeListener); } @Override public Object[] toArray() { return list.toArray(); } @Override public <E> E[] toArray(E[] a) { return list.toArray(a); } // 添加元素时注册监听器 @Override public boolean add(T element) { if (element != null) { element.addPropertyChangeListener(entityChangeListener); } Log.d("z","element"); return list.add(element); } // 移除元素时注销监听器 @Override public boolean remove(Object o) { if (o instanceof SynchronizableEntity) { ((SynchronizableEntity) o).removePropertyChangeListener(entityChangeListener); } return list.remove(o); } @Override public boolean containsAll(Collection<?> c) { return list.containsAll(c); } // 批量添加时逐个注册监听器 @Override public boolean addAll(Collection<? extends T> c) { for (T element : c) { if (element != null) { element.addPropertyChangeListener(entityChangeListener); } } return list.addAll(c); } @Override public boolean addAll(int index, Collection<? extends T> c) { for (T element : c) { if (element != null) { element.addPropertyChangeListener(entityChangeListener); } } return list.addAll(index, c); } // 批量移除时逐个注销监听器 @Override public boolean removeAll(Collection<?> c) { for (Object o : c) { if (o instanceof SynchronizableEntity) { ((SynchronizableEntity) o).removePropertyChangeListener(entityChangeListener); } } return list.removeAll(c); } @Override public boolean retainAll(Collection<?> c) { // 先移除未保留元素的监听器 for (T element : list) { if (!c.contains(element)) { element.removePropertyChangeListener(entityChangeListener); } } return list.retainAll(c); } // 清空集合时移除所有监听器 @Override public void clear() { for (T element : list) { element.removePropertyChangeListener(entityChangeListener); } list.clear(); } @Override public T get(int index) { return list.get(index); } // 替换元素时更新监听器 @Override public T set(int index, T element) { T oldElement = list.get(index); if (oldElement != null) { oldElement.removePropertyChangeListener(entityChangeListener); } if (element != null) { element.addPropertyChangeListener(entityChangeListener); } return list.set(index, element); } // 在指定位置添加元素时注册监听器 @Override public void add(int index, T element) { if (element != null) { element.addPropertyChangeListener(entityChangeListener); } list.add(index, element); } // 移除元素时注销监听器 @Override public T remove(int index) { T removed = list.remove(index); if (removed != null) { removed.removePropertyChangeListener(entityChangeListener); } return removed; } @Override public int indexOf(Object o) { return list.indexOf(o); } @Override public int lastIndexOf(Object o) { return list.lastIndexOf(o); } @Override public ListIterator<T> listIterator() { return new SyncedListIterator<>(list.listIterator(), entityChangeListener); } @Override public ListIterator<T> listIterator(int index) { return new SyncedListIterator<>(list.listIterator(index), entityChangeListener); } @Override public List<T> subList(int fromIndex, int toIndex) { return list.subList(fromIndex, toIndex); } /** * 内部实体变更监听器 * 监听属性变化并触发同步操作 */ private static class EntityChangeListener<T extends SynchronizableEntity> implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent evt) { @SuppressWarnings("unchecked") T entity = (T) evt.getSource(); entity.sync(); // 触发同步操作 } } /** * 增强的Iterator实现 * 移除元素时自动注销监听器 */ private static class SyncedIterator<T extends SynchronizableEntity> implements Iterator<T> { private final Iterator<T> iterator; private final EntityChangeListener<T> listener; private T current; public SyncedIterator(Iterator<T> iterator, EntityChangeListener<T> listener) { this.iterator = iterator; this.listener = listener; } @Override public boolean hasNext() { return iterator.hasNext(); } @Override public T next() { current = iterator.next(); return current; } @Override public void remove() { if (current != null) { current.removePropertyChangeListener(listener); } iterator.remove(); } } /** * 增强的ListIterator实现 * 支持添加/设置元素时的监听器管理 */ private static class SyncedListIterator<T extends SynchronizableEntity> implements ListIterator<T> { private final ListIterator<T> iterator; private final EntityChangeListener<T> listener; private T lastReturned; public SyncedListIterator(ListIterator<T> iterator, EntityChangeListener<T> listener) { this.iterator = iterator; this.listener = listener; } @Override public boolean hasNext() { return iterator.hasNext(); } @Override public T next() { lastReturned = iterator.next(); return lastReturned; } @Override public boolean hasPrevious() { return iterator.hasPrevious(); } @Override public T previous() { lastReturned = iterator.previous(); return lastReturned; } @Override public int nextIndex() { return iterator.nextIndex(); } @Override public int previousIndex() { return iterator.previousIndex(); } @Override public void remove() { if (lastReturned != null) { lastReturned.removePropertyChangeListener(listener); } iterator.remove(); } @Override public void set(T e) { if (lastReturned != null) { lastReturned.removePropertyChangeListener(listener); } if (e != null) { e.addPropertyChangeListener(listener); } iterator.set(e); lastReturned = e; } @Override public void add(T e) { if (e != null) { e.addPropertyChangeListener(listener); } iterator.add(e); } } }package com.example.kucun2.entity.data; import android.content.Context; import android.util.Log; import com.example.kucun2.entity.*; import com.example.kucun2.function.MyAppFnction; import com.example.kucun2.function.TLSUtils; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.io.IOException; import java.lang.reflect.Type; import java.util.*; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.X509TrustManager; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class Data { // 数据集合声明(保持原有属性名不变) public static SynchronizedList<Bancai> bancais = new SynchronizedList<>(Bancai.class); public static SynchronizedList<Caizhi> caizhis = new SynchronizedList<>(Caizhi.class); public static SynchronizedList<Mupi> mupis = new SynchronizedList<>(Mupi.class); public static SynchronizedList<Chanpin> chanpins = new SynchronizedList<>(Chanpin.class); public static SynchronizedList<Chanpin_Zujian> chanpinZujians = new SynchronizedList<>(Chanpin_Zujian.class); public static SynchronizedList<Dingdan> dingdans = new SynchronizedList<>(Dingdan.class); public static SynchronizedList<Dingdan_Chanpin> dingdanChanpins = new SynchronizedList<>(Dingdan_Chanpin.class); public static SynchronizedList<Dingdan_chanpin_zujian> dingdanBancais = new SynchronizedList<>(Dingdan_chanpin_zujian.class); public static SynchronizedList<Kucun> kucuns = new SynchronizedList<>(Kucun.class); public static SynchronizedList<Zujian> zujians = new SynchronizedList<>(Zujian.class); public static SynchronizedList<User> users = new SynchronizedList<>(Bancai.class); public static SynchronizedList<Jinhuo> jinhuoList = new SynchronizedList<>(Bancai.class); private static final Gson gson = new Gson(); private static OkHttpClient client ; private static final String TAG = "DataLoader"; public static void loadAllData(Context context, LoadDataCallback callback) { // 确保使用安全的客户端 if (client == null) { client= MyAppFnction.getClient(); } //禁用同步 SynchronizableEntity.setSyncEnabled(false); String url = MyAppFnction.getStringResource("string", "url") + MyAppFnction.getStringResource("string", "url_all"); Log.d("url", "loadAllData: " + url); Request request = new Request.Builder() .url(url) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "Failed to load data", e); SynchronizableEntity.setSyncEnabled(true); if (callback != null) callback.onFailure(); } @Override public void onResponse(Call call, Response response) throws IOException { if (!response.isSuccessful()) { Log.e(TAG, "Unexpected response code: " + response.code()); if (callback != null) callback.onFailure(); return; } String responseData = response.body().string(); SynchronizableEntity.setSyncEnabled(true); parseAndAssignData(responseData, context, callback); } }); } // 解析并赋值数据 private static void parseAndAssignData(String jsonData, Context context, LoadDataCallback callback) { // 创建包含所有数据类型的TypeToken Type informationType = new TypeToken<Information<AllDataResponse>>(){}.getType(); Information<AllDataResponse> information = gson.fromJson(jsonData, informationType); Log.e(TAG, "Invalid response data"+jsonData); if (information == null || information.getData() == null || information.getStatus() != 200) { Log.e(TAG, "Invalid response data"); if (callback != null) callback.onFailure(); return; } AllDataResponse allData = information.getData(); // 赋值到对应的列表(使用安全方法保持已有引用) updateList(bancais, allData.bancais); updateList(caizhis, allData.caizhis); updateList(mupis, allData.mupis); updateList(chanpins, allData.chanpins); updateList(chanpinZujians, allData.chanpin_zujians); updateList(dingdans, allData.dingdans); updateList(dingdanChanpins, allData.dingdan_chanpins); updateList(dingdanBancais, allData.dingdan_bancais); updateList(kucuns, allData.kucuns); updateList(zujians, allData.zujians); updateList(users, allData.users); updateList(jinhuoList, allData.jinhuos); // 在设置引用关系前关闭同步 SynchronizableEntity.setSyncEnabled(false); resolveReferences(); // 为所有实体设置正确状态(已存在服务器) setAllEntitiesState(SynchronizableEntity.SyncState.MODIFIED); // 启用同步 SynchronizableEntity.setSyncEnabled(true); if (callback != null) callback.onSuccess(); } // 更新列表内容但保持对象引用不变 private static <T> void updateList(List<T> existingList, List<T> newList) { if (newList == null) return; existingList.clear(); existingList.addAll(newList); } // 解析对象间的引用关系(使用ID关联) private static void resolveReferences() { // 创建ID到对象的映射 Map<Integer, Bancai> bancaiMap = createIdMap(bancais); Map<Integer, Caizhi> caizhiMap = createIdMap(caizhis); Map<Integer, Mupi> mupiMap = createIdMap(mupis); Map<Integer, Chanpin> chanpinMap = createIdMap(chanpins); Map<Integer, Zujian> zujianMap = createIdMap(zujians); Map<Integer, Dingdan> dingdanMap = createIdMap(dingdans); Map<Integer, Kucun> kucunMap = createIdMap(kucuns); // 解析Bancai引用 for (Bancai bancai : bancais) { if (bancai.getCaizhi() != null) { bancai.setCaizhi(caizhiMap.get(bancai.getCaizhi().getId())); } if (bancai.getMupi1() != null) { bancai.setMupi1(mupiMap.get(bancai.getMupi1().getId())); } if (bancai.getMupi2() != null) { bancai.setMupi2(mupiMap.get(bancai.getMupi2().getId())); } } // 解析Kucun引用 for (Kucun kucun : kucuns) { if (kucun.getBancai() != null) { kucun.setBancai(bancaiMap.get(kucun.getBancai().getId())); } } // 解析订单相关的嵌套对象 for (Dingdan_Chanpin dc : dingdanChanpins) { if (dc.getDingdan() != null) { dc.setDingdan(dingdanMap.get(dc.getDingdan().getId())); } if (dc.getChanpin() != null) { dc.setChanpin(chanpinMap.get(dc.getChanpin().getId())); } } // 解析产品相关的嵌套对象 for (Chanpin_Zujian cz : chanpinZujians) { if (cz.getChanpin() != null) { cz.setChanpin(chanpinMap.get(cz.getChanpin().getId())); } if (cz.getZujian() != null) { cz.setZujian(zujianMap.get(cz.getZujian().getId())); } if (cz.getBancai() != null) { cz.setBancai(bancaiMap.get(cz.getBancai().getId())); } } // 解析库存关联 for (Kucun k : kucuns) { if (k.getBancai() != null) { k.setBancai(bancaiMap.get(k.getBancai().getId())); } } } // 创建ID到对象的映射 private static <T extends EntityClassGrassrootsid> Map<Integer, T> createIdMap(List<T> list) { Map<Integer, T> map = new HashMap<>(); for (T item : list) { map.put(item.getId(), item); } return map; } // 回调接口 public interface LoadDataCallback { void onSuccess(); void onFailure(); } // 内部类用于解析JSON响应 public static class AllDataResponse { public List<Bancai> bancais; public List<Caizhi> caizhis; public List<Mupi> mupis; public List<Chanpin> chanpins; public List<Chanpin_Zujian> chanpin_zujians; public List<Dingdan> dingdans; public List<Dingdan_Chanpin> dingdan_chanpins; public List<Dingdan_chanpin_zujian> dingdan_bancais; public List<Kucun> kucuns; public List<Zujian> zujians; public List<User> users; public List<Jinhuo> jinhuos; } // 新增方法:设置所有实体状态 private static void setAllEntitiesState(SynchronizableEntity.SyncState state) { setListState(bancais, state); setListState(caizhis, state); setListState(mupis, state); setListState(dingdanBancais, state); setListState(dingdans, state); setListState(chanpins, state); setListState(chanpinZujians, state); setListState(zujians, state); setListState(jinhuoList, state); setListState(kucuns, state); setListState(users, state); setListState(caizhis, state); // ... 其他列表 } private static <T extends SynchronizableEntity> void setListState(List<T> list, SynchronizableEntity.SyncState state) { for (T entity : list) { entity.setState(state); } } } 记录:onCreateView: 鐩存帴鍏ュ簱 表格没数据

package com.example.kucun2.ui.jinhuo; import static android.content.ContentValues.TAG; import android.app.AlertDialog; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.RadioGroup; import android.widget.SearchView; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import com.example.kucun2.R; import com.example.kucun2.entity.*; import com.example.kucun2.entity.data.Data; import com.example.kucun2.function.Adapter; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Random; public class AddInventoryFragment extends Fragment { private Spinner spinnerDingdan, spinnerChanpin, spinnerZujian, spinnerBancai; private EditText etShuliang; private RadioGroup rgType; private Dingdan selectedDingdan; private Chanpin selectedChanpin; private Zujian selectedZujian; private Bancai selectedBancai; // 创建新订单产品组件按钮 private Button btnNewDingdan, btnAddChanpin, btnAddZujian; /** * 初始化 * @param inflater The LayoutInflater object that can be used to inflate * any views in the fragment, * @param container If non-null, this is the parent view that the fragment's * UI should be attached to. The fragment should not add the view itself, * but this can be used to generate the LayoutParams of the view. * @param savedInstanceState If non-null, this fragment is being re-constructed * from a previous saved state as given here. * * @return */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_add_inventory, container, false); // 初始化UI组件 spinnerDingdan = view.findViewById(R.id.spinner_dingdan); spinnerChanpin = view.findViewById(R.id.spinner_chanpin); spinnerZujian = view.findViewById(R.id.spinner_zujian); spinnerBancai = view.findViewById(R.id.spinner_bancai); etShuliang = view.findViewById(R.id.et_shuliang); rgType = view.findViewById(R.id.rg_type); Button btnSubmit = view.findViewById(R.id.btn_submit); // 初始化新按钮 btnNewDingdan = view.findViewById(R.id.btn_new_dingdan); btnAddChanpin = view.findViewById(R.id.btn_add_chanpin); btnAddZujian = view.findViewById(R.id.btn_add_zujian); // 设置按钮点击事件 btnNewDingdan.setOnClickListener(v -> createNewDingdan()); btnAddChanpin.setOnClickListener(v -> addChanpinToDingdan()); btnAddZujian.setOnClickListener(v -> addZujianToChanpin()); // 设置订单选择器 setupDingdanSpinner(); // 提交按钮点击事件 btnSubmit.setOnClickListener(v -> addInventoryRecord()); return view; } private void setupDingdanSpinner() { Adapter.setupDingdanSpinner(spinnerDingdan,Data.dingdans,getContext()); spinnerDingdan.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedDingdan = (Dingdan) parent.getItemAtPosition(position); setupChanpinSpinner(selectedDingdan); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupChanpinSpinner(Dingdan dingdan) { // 获取该订单的产品列表 List<Chanpin> chanpins = new ArrayList<>(); for (Dingdan_Chanpin dc : dingdan.getChanpins()) { chanpins.add(dc.getChanpin()); } Adapter.setupChanpinSpinner(spinnerChanpin,chanpins,getContext()); spinnerChanpin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedChanpin = (Chanpin) parent.getItemAtPosition(position); setupZujianSpinner(selectedChanpin); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupZujianSpinner(Chanpin chanpin) { // 获取该产品的组件列表 List<Zujian> zujians = new ArrayList<>(); for (Chanpin_Zujian cz : chanpin.getZujians()) { zujians.add(cz.getZujian()); } Adapter.setupZujianSpinner(spinnerZujian,zujians,getContext()); spinnerZujian.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedZujian = (Zujian) parent.getItemAtPosition(position); setupBancaiSpinner(selectedChanpin, selectedZujian); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupBancaiSpinner(Chanpin chanpin, Zujian zujian) { // 获取该组件关联的板材 List<Bancai> bancais = new ArrayList<>(); for (Chanpin_Zujian cz : chanpin.getZujians()) { if (cz.getZujian().getId().equals(zujian.getId())) { bancais.add(cz.getBancai()); } } Adapter.setupBancaiSpinners(spinnerBancai,bancais,getContext()); spinnerBancai.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedBancai = (Bancai) parent.getItemAtPosition(position); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } // ... addInventoryRecord和createRecord方法保持不变 ... private void addInventoryRecord() { // 验证必填项 if (selectedDingdan == null || selectedChanpin == null || selectedZujian == null || selectedBancai == null) { Toast.makeText(getContext(), "请选择订单、产品、组件和板材", Toast.LENGTH_SHORT).show(); return; } String shuliangStr = etShuliang.getText().toString().trim(); if (shuliangStr.isEmpty()) { Toast.makeText(getContext(), "请输入数量", Toast.LENGTH_SHORT).show(); return; } // 解析数量 int shuliang; try { shuliang = Integer.parseInt(shuliangStr); } catch (NumberFormatException e) { Toast.makeText(getContext(), "请输入有效的数量", Toast.LENGTH_SHORT).show(); return; } // 确定操作类型(进货或消耗) boolean isJinhuo = rgType.getCheckedRadioButtonId() == R.id.rb_jinhuo; // 实际开发中应从登录信息获取当前用户 User currentUser = new User(1, "当前用户", "user", "password",1); // 创建记录 createRecord(selectedDingdan, selectedChanpin, selectedZujian, selectedBancai, shuliang, isJinhuo, currentUser); Toast.makeText(getContext(), "记录添加成功", Toast.LENGTH_SHORT).show(); etShuliang.setText(""); // 清空输入框 } private void createRecord(Dingdan dingdan, Chanpin chanpin, Zujian zujian, Bancai bancai, int shuliang, boolean isJinhuo, User user) { if (isJinhuo) { // 创建进货记录 Jinhuo jinhuo = new Jinhuo(); jinhuo.setId(Data.jinhuoList.size() + 1); jinhuo.setDingdan(dingdan); jinhuo.setChanpin(chanpin); jinhuo.setZujian(zujian); jinhuo.setBancai(bancai); jinhuo.setShuliang(shuliang); jinhuo.setDate(new Date()); jinhuo.setUser(user); Data.jinhuoList.add(jinhuo); } else { // 消耗数量转为负数 shuliang = -shuliang; } // 更新库存 updateKucun(bancai, shuliang); } private void updateKucun(Bancai bancai, int changeAmount) { // 查找现有库存记录 for (Kucun k : Data.kucuns) { if (k.getBancai().getId().equals(bancai.getId())) { k.setShuliang(k.getShuliang() + changeAmount); return; } } // 如果没有找到库存记录,创建新的 Kucun newKucun = new Kucun(); newKucun.setId(Data.kucuns.size() + 1); newKucun.setBancai(bancai); newKucun.setShuliang(Math.max(changeAmount, 0)); // 确保不为负 Data.kucuns.add(newKucun); } // 新建订单方法 private void createNewDingdan() { // 创建新订单(示例:实际应弹窗或跳转页面) Dingdan newDingdan = new Dingdan(); newDingdan.setId( (Data.dingdans.size() + 1)); newDingdan.setNumber("新建订单" + System.currentTimeMillis()); newDingdan.setChanpins(new ArrayList<>()); Data.dingdans.add(newDingdan); // 刷新订单下拉框 setupDingdanSpinner(); spinnerDingdan.setSelection(Data.dingdans.size() - 1); Toast.makeText(getContext(), "新建订单成功", Toast.LENGTH_SHORT).show(); } // 为当前订单添加产品 private void addChanpinToDingdan() { if (selectedDingdan == null) { Toast.makeText(getContext(), "请先选择订单", Toast.LENGTH_SHORT).show(); return; } // 创建新产品(示例:实际应弹窗输入产品信息) Chanpin newChanpin = new Chanpin(); newChanpin.setId( (Data.chanpins.size() + 1)); newChanpin.setName("新产品" + System.currentTimeMillis()); newChanpin.setZujians(new ArrayList<>()); // 添加到全局列表 Data.chanpins.add(newChanpin); // 添加到当前订单的产品列表 Dingdan_Chanpin dc = new Dingdan_Chanpin(); dc.setId(selectedDingdan.getChanpins().size() + 1); dc.setChanpin(newChanpin); dc.setDingdan(selectedDingdan); selectedDingdan.getChanpins().add(dc); // 刷新产品下拉框 setupChanpinSpinner(selectedDingdan); spinnerChanpin.setSelection(selectedDingdan.getChanpins().size() - 1); Toast.makeText(getContext(), "产品添加成功", Toast.LENGTH_SHORT).show(); } // 为当前产品添加组件 private void addZujianToChanpin() { if (selectedChanpin == null) { Toast.makeText(getContext(), "请先选择产品", Toast.LENGTH_SHORT).show(); return; } // // 创建新组件(示例) // Zujian newZujian = new Zujian(); // newZujian.setId( (Data.zujians.size() + 1)); // newZujian.setName("新组件" + System.currentTimeMillis()); // // // 添加到全局列表 // Data.zujians.add(newZujian); // // // 添加到当前产品的组件列表 // Chanpin_Zujian cz = new Chanpin_Zujian(); // cz.setId(selectedChanpin.getZujians().size() + 1); // cz.setZujian(newZujian); // cz.setChanpin(selectedChanpin); // selectedChanpin.getZujians().add(cz); // // // 刷新组件下拉框 // setupZujianSpinner(selectedChanpin); // spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1); // // Toast.makeText(getContext(), "组件添加成功", Toast.LENGTH_SHORT).show(); showCreateZujianDialog(); } // 新建板材 private void createNewBancai() { // 创建新板材(示例) Random rand = new Random(12345); Bancai newBancai = new Bancai(); newBancai.setId((Data.bancais.size() + 1)); newBancai.setCaizhi(Data.bancais.get(rand.nextInt(Data.bancais.size()-1)).getCaizhi()); newBancai.setMupi1(Data.bancais.get(rand.nextInt(Data.bancais.size()-1)).getMupi1()); newBancai.setMupi2(Data.bancais.get(rand.nextInt(Data.bancais.size()-1)).getMupi2()); // 添加到全局列表 Data.bancais.add(newBancai); // 刷新板材下拉框 setupBancaiSpinner(selectedChanpin, selectedZujian); spinnerBancai.setSelection(Data.bancais.size() - 1); Toast.makeText(getContext(), "新建板材成功", Toast.LENGTH_SHORT).show(); } private void showCreateZujianDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("添加新组件"); // 创建自定义布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_create_zujian_bancai, null); EditText etZujianName = dialogView.findViewById(R.id.et_zujian_name); Spinner spinnerbancai = dialogView.findViewById(R.id.spinner_bancai); SearchView searchBancai = dialogView.findViewById(R.id.search_bancai); // 板材适配器 Adapter.setupBancaiSpinners(spinnerbancai,Data.bancais,getContext()); // 设置搜索功能 searchBancai.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { // 过滤板材列表 List<Bancai> filteredList = new ArrayList<>(); for (Bancai bancai : Data.bancais) { if ( bancai.TableText().toLowerCase().contains(newText.toLowerCase())) { filteredList.add(bancai); } } // 板材适配器 Adapter.setupBancaiSpinners(spinnerbancai,filteredList,getContext()); return true; } }); // 添加木皮预览标签 builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { // 获取用户输入 String zujianName = etZujianName.getText().toString().trim(); Bancai selectedBancai = (Bancai) spinnerbancai.getSelectedItem(); if (zujianName.isEmpty()) { Toast.makeText(getContext(), "请输入组件名称", Toast.LENGTH_SHORT).show(); return; } // 创建新组件 Zujian newZujian = new Zujian(); newZujian.setId(Data.zujians.size() + 1); newZujian.setName(zujianName); // 创建新板材 // 添加到全局列表 Data.zujians.add(newZujian); // 添加到当前产品的组件列表 Chanpin_Zujian cz = new Chanpin_Zujian(); cz.setId(selectedChanpin.getZujians().size() + 1); cz.setZujian(newZujian); cz.setBancai(selectedBancai); // 关联新创建的板材 cz.setChanpin(selectedChanpin); selectedChanpin.getZujians().add(cz); // 刷新组件下拉框 setupZujianSpinner(selectedChanpin); spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1); Toast.makeText(getContext(), "组件和板材添加成功", Toast.LENGTH_SHORT).show(); }); builder.setNegativeButton("取消", null); builder.show(); } }<?xml version="1.0" encoding="utf-8"?> <EditText android:id="@+id/et_zujian_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入组件名称"/> <SearchView android:id="@+id/search_bancai" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:queryHint="搜索板材..." android:iconifiedByDefault="false" android:layout_marginBottom="8dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="板材选择" android:textStyle="bold" android:layout_marginTop="8dp"/> <Spinner android:id="@+id/spinner_bancai" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp"/> 在添加组件弹框中 板材下拉框后面加一个按键点击弹出另一个弹窗添加板材

package com.example.kucun2.ui.jinhuo; import static android.content.ContentValues.TAG; import android.app.AlertDialog; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.RadioGroup; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import com.example.kucun2.R; import com.example.kucun2.entity.*; import com.example.kucun2.entity.data.Data; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Random; public class AddInventoryFragment extends Fragment { private Spinner spinnerDingdan, spinnerChanpin, spinnerZujian, spinnerBancai; private EditText etShuliang; private RadioGroup rgType; private Dingdan selectedDingdan; private Chanpin selectedChanpin; private Zujian selectedZujian; private Bancai selectedBancai; // 创建新订单产品组件按钮 private Button btnNewDingdan, btnAddChanpin, btnAddZujian; /** * 初始化 * @param inflater The LayoutInflater object that can be used to inflate * any views in the fragment, * @param container If non-null, this is the parent view that the fragment's * UI should be attached to. The fragment should not add the view itself, * but this can be used to generate the LayoutParams of the view. * @param savedInstanceState If non-null, this fragment is being re-constructed * from a previous saved state as given here. * * @return */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_add_inventory, container, false); // 初始化UI组件 spinnerDingdan = view.findViewById(R.id.spinner_dingdan); spinnerChanpin = view.findViewById(R.id.spinner_chanpin); spinnerZujian = view.findViewById(R.id.spinner_zujian); spinnerBancai = view.findViewById(R.id.spinner_bancai); etShuliang = view.findViewById(R.id.et_shuliang); rgType = view.findViewById(R.id.rg_type); Button btnSubmit = view.findViewById(R.id.btn_submit); // 初始化新按钮 btnNewDingdan = view.findViewById(R.id.btn_new_dingdan); btnAddChanpin = view.findViewById(R.id.btn_add_chanpin); btnAddZujian = view.findViewById(R.id.btn_add_zujian); // 设置按钮点击事件 btnNewDingdan.setOnClickListener(v -> createNewDingdan()); btnAddChanpin.setOnClickListener(v -> addChanpinToDingdan()); btnAddZujian.setOnClickListener(v -> addZujianToChanpin()); // 设置订单选择器 setupDingdanSpinner(); // 提交按钮点击事件 btnSubmit.setOnClickListener(v -> addInventoryRecord()); return view; } private void setupDingdanSpinner() { // 定制订单适配器显示订单号(number) ArrayAdapter<Dingdan> dingdanAdapter = new ArrayAdapter<Dingdan>( requireContext(), android.R.layout.simple_spinner_item, Data.dingdans) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getView(position, convertView, parent); Dingdan dingdan = getItem(position); if (dingdan != null) { textView.setText(dingdan.getNumber()); } return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getDropDownView(position, convertView, parent); Dingdan dingdan = getItem(position); if (dingdan != null) { textView.setText(dingdan.getNumber()); } return textView; } }; dingdanAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerDingdan.setAdapter(dingdanAdapter); spinnerDingdan.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedDingdan = (Dingdan) parent.getItemAtPosition(position); setupChanpinSpinner(selectedDingdan); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupChanpinSpinner(Dingdan dingdan) { // 获取该订单的产品列表 List<Chanpin> chanpins = new ArrayList<>(); for (Dingdan_Chanpin dc : dingdan.getChanpins()) { chanpins.add(dc.getChanpin()); } // 定制产品适配器显示产品名(name) ArrayAdapter<Chanpin> chanpinAdapter = new ArrayAdapter<Chanpin>( requireContext(), android.R.layout.simple_spinner_item, chanpins) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { Log.d(TAG, "getView:position="+position+",convertView="+convertView+",parent="+parent); TextView textView = (TextView) super.getView(position, convertView, parent);//也是 convertView=null 就不报错 Chanpin chanpin = getItem(position); if (chanpin != null) { textView.setText(chanpin.getName()); } return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getDropDownView(position, convertView, parent); Chanpin chanpin = getItem(position); if (chanpin != null) { textView.setText(chanpin.getName()); } return textView; } }; chanpinAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerChanpin.setAdapter(chanpinAdapter); spinnerChanpin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedChanpin = (Chanpin) parent.getItemAtPosition(position); setupZujianSpinner(selectedChanpin); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupZujianSpinner(Chanpin chanpin) { // 获取该产品的组件列表 List<Zujian> zujians = new ArrayList<>(); for (Chanpin_Zujian cz : chanpin.getZujians()) { zujians.add(cz.getZujian()); } // 定制组件适配器显示组件名(name) ArrayAdapter<Zujian> zujianAdapter = new ArrayAdapter<Zujian>( requireContext(), android.R.layout.simple_spinner_item, zujians) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { Log.d(TAG, "getView:position="+position+",convertView="+convertView+",parent="+parent); TextView textView = (TextView) super.getView(position, convertView, parent);//也是 convertView=null 就不报错 Zujian zujian = getItem(position); if (zujian != null) { textView.setText(zujian.getName()); } return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getDropDownView(position, convertView, parent); Zujian zujian = getItem(position); if (zujian != null) { textView.setText(zujian.getName()); } return textView; } }; zujianAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerZujian.setAdapter(zujianAdapter); spinnerZujian.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedZujian = (Zujian) parent.getItemAtPosition(position); setupBancaiSpinner(selectedChanpin, selectedZujian); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } private void setupBancaiSpinner(Chanpin chanpin, Zujian zujian) { // 获取该组件关联的板材 List<Bancai> bancais = new ArrayList<>(); for (Chanpin_Zujian cz : chanpin.getZujians()) { if (cz.getZujian().getId().equals(zujian.getId())) { bancais.add(cz.getBancai()); } } // 定制板材适配器显示TableText(保持不变) ArrayAdapter<Bancai> bancaiAdapter = new ArrayAdapter<Bancai>( requireContext(), android.R.layout.simple_spinner_item, bancais) { @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { Log.d(TAG, "getView:position="+position+",convertView="+convertView+",parent="+parent); TextView textView = (TextView) super.getView(position, convertView, parent);// 点击添加组件才会一直报 convertView=null java.lang.NullPointerException Bancai bancai = getItem(position); if (bancai != null) { textView.setText(bancai.TableText()); } return textView; } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { TextView textView = (TextView) super.getDropDownView(position, convertView, parent); Bancai bancai = getItem(position); if (bancai != null) { textView.setText(bancai.TableText()); } return textView; } }; bancaiAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerBancai.setAdapter(bancaiAdapter); spinnerBancai.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { selectedBancai = (Bancai) parent.getItemAtPosition(position); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); } // ... addInventoryRecord和createRecord方法保持不变 ... private void addInventoryRecord() { // 验证必填项 if (selectedDingdan == null || selectedChanpin == null || selectedZujian == null || selectedBancai == null) { Toast.makeText(getContext(), "请选择订单、产品、组件和板材", Toast.LENGTH_SHORT).show(); return; } String shuliangStr = etShuliang.getText().toString().trim(); if (shuliangStr.isEmpty()) { Toast.makeText(getContext(), "请输入数量", Toast.LENGTH_SHORT).show(); return; } // 解析数量 int shuliang; try { shuliang = Integer.parseInt(shuliangStr); } catch (NumberFormatException e) { Toast.makeText(getContext(), "请输入有效的数量", Toast.LENGTH_SHORT).show(); return; } // 确定操作类型(进货或消耗) boolean isJinhuo = rgType.getCheckedRadioButtonId() == R.id.rb_jinhuo; // 实际开发中应从登录信息获取当前用户 User currentUser = new User(1, "当前用户", "user", "password",1); // 创建记录 createRecord(selectedDingdan, selectedChanpin, selectedZujian, selectedBancai, shuliang, isJinhuo, currentUser); Toast.makeText(getContext(), "记录添加成功", Toast.LENGTH_SHORT).show(); etShuliang.setText(""); // 清空输入框 } private void createRecord(Dingdan dingdan, Chanpin chanpin, Zujian zujian, Bancai bancai, int shuliang, boolean isJinhuo, User user) { if (isJinhuo) { // 创建进货记录 Jinhuo jinhuo = new Jinhuo(); jinhuo.setId(Data.jinhuoList.size() + 1); jinhuo.setDingdan(dingdan); jinhuo.setChanpin(chanpin); jinhuo.setZujian(zujian); jinhuo.setBancai(bancai); jinhuo.setShuliang(shuliang); jinhuo.setDate(new Date()); jinhuo.setUser(user); Data.jinhuoList.add(jinhuo); } else { // 消耗数量转为负数 shuliang = -shuliang; } // 更新库存 updateKucun(bancai, shuliang); } private void updateKucun(Bancai bancai, int changeAmount) { // 查找现有库存记录 for (Kucun k : Data.kucuns) { if (k.getBancai().getId().equals(bancai.getId())) { k.setShuliang(k.getShuliang() + changeAmount); return; } } // 如果没有找到库存记录,创建新的 Kucun newKucun = new Kucun(); newKucun.setId(Data.kucuns.size() + 1); newKucun.setBancai(bancai); newKucun.setShuliang(Math.max(changeAmount, 0)); // 确保不为负 Data.kucuns.add(newKucun); } // 新建订单方法 private void createNewDingdan() { // 创建新订单(示例:实际应弹窗或跳转页面) Dingdan newDingdan = new Dingdan(); newDingdan.setId( (Data.dingdans.size() + 1)); newDingdan.setNumber("新建订单" + System.currentTimeMillis()); newDingdan.setChanpins(new ArrayList<>()); Data.dingdans.add(newDingdan); // 刷新订单下拉框 setupDingdanSpinner(); spinnerDingdan.setSelection(Data.dingdans.size() - 1); Toast.makeText(getContext(), "新建订单成功", Toast.LENGTH_SHORT).show(); } // 为当前订单添加产品 private void addChanpinToDingdan() { if (selectedDingdan == null) { Toast.makeText(getContext(), "请先选择订单", Toast.LENGTH_SHORT).show(); return; } // 创建新产品(示例:实际应弹窗输入产品信息) Chanpin newChanpin = new Chanpin(); newChanpin.setId( (Data.chanpins.size() + 1)); newChanpin.setName("新产品" + System.currentTimeMillis()); newChanpin.setZujians(new ArrayList<>()); // 添加到全局列表 Data.chanpins.add(newChanpin); // 添加到当前订单的产品列表 Dingdan_Chanpin dc = new Dingdan_Chanpin(); dc.setId(selectedDingdan.getChanpins().size() + 1); dc.setChanpin(newChanpin); dc.setDingdan(selectedDingdan); selectedDingdan.getChanpins().add(dc); // 刷新产品下拉框 setupChanpinSpinner(selectedDingdan); spinnerChanpin.setSelection(selectedDingdan.getChanpins().size() - 1); Toast.makeText(getContext(), "产品添加成功", Toast.LENGTH_SHORT).show(); } // 为当前产品添加组件 private void addZujianToChanpin() { if (selectedChanpin == null) { Toast.makeText(getContext(), "请先选择产品", Toast.LENGTH_SHORT).show(); return; } // // 创建新组件(示例) // Zujian newZujian = new Zujian(); // newZujian.setId( (Data.zujians.size() + 1)); // newZujian.setName("新组件" + System.currentTimeMillis()); // // // 添加到全局列表 // Data.zujians.add(newZujian); // // // 添加到当前产品的组件列表 // Chanpin_Zujian cz = new Chanpin_Zujian(); // cz.setId(selectedChanpin.getZujians().size() + 1); // cz.setZujian(newZujian); // cz.setChanpin(selectedChanpin); // selectedChanpin.getZujians().add(cz); // // // 刷新组件下拉框 // setupZujianSpinner(selectedChanpin); // spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1); // // Toast.makeText(getContext(), "组件添加成功", Toast.LENGTH_SHORT).show(); showCreateZujianDialog(); } // 新建板材 private void createNewBancai() { // 创建新板材(示例) Random rand = new Random(12345); Bancai newBancai = new Bancai(); newBancai.setId((Data.bancais.size() + 1)); newBancai.setCaizhi(Data.bancais.get(rand.nextInt(Data.bancais.size()-1)).getCaizhi()); newBancai.setMupi1(Data.bancais.get(rand.nextInt(Data.bancais.size()-1)).getMupi1()); newBancai.setMupi2(Data.bancais.get(rand.nextInt(Data.bancais.size()-1)).getMupi2()); // 添加到全局列表 Data.bancais.add(newBancai); // 刷新板材下拉框 setupBancaiSpinner(selectedChanpin, selectedZujian); spinnerBancai.setSelection(Data.bancais.size() - 1); Toast.makeText(getContext(), "新建板材成功", Toast.LENGTH_SHORT).show(); } private void showCreateZujianDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); builder.setTitle("添加新组件和板材"); // 创建自定义布局 View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_create_zujian_bancai, null); EditText etZujianName = dialogView.findViewById(R.id.et_zujian_name); EditText etBancaiName = dialogView.findViewById(R.id.et_bancai_name); Spinner spinnerCaizhi = dialogView.findViewById(R.id.spinner_caizhi); Spinner spinnerMupi1 = dialogView.findViewById(R.id.spinner_mupi1); Spinner spinnerMupi2 = dialogView.findViewById(R.id.spinner_mupi2); // 设置材质下拉框 ArrayAdapter<Caizhi> caizhiAdapter = new ArrayAdapter<>( requireContext(), android.R.layout.simple_spinner_item, Data.caizhis); caizhiAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerCaizhi.setAdapter(caizhiAdapter); // 设置木皮下拉框 ArrayAdapter<Mupi> mupiAdapter = new ArrayAdapter<>( requireContext(), android.R.layout.simple_spinner_item, Data.mupis); mupiAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerMupi1.setAdapter(mupiAdapter); spinnerMupi2.setAdapter(mupiAdapter); builder.setView(dialogView); builder.setPositiveButton("创建", (dialog, which) -> { // 获取用户输入 String zujianName = etZujianName.getText().toString().trim(); String bancaiName = etBancaiName.getText().toString().trim(); Caizhi selectedCaizhi = (Caizhi) spinnerCaizhi.getSelectedItem(); Mupi selectedMupi1 = (Mupi) spinnerMupi1.getSelectedItem(); Mupi selectedMupi2 = (Mupi) spinnerMupi2.getSelectedItem(); if (zujianName.isEmpty()) { Toast.makeText(getContext(), "请输入组件名称", Toast.LENGTH_SHORT).show(); return; } // 创建新组件 Zujian newZujian = new Zujian(); newZujian.setId(Data.zujians.size() + 1); newZujian.setName(zujianName); // 创建新板材 Bancai newBancai = new Bancai(); newBancai.setId(Data.bancais.size() + 1); newBancai.setCaizhi(selectedCaizhi); newBancai.setMupi1(selectedMupi1); newBancai.setMupi2(selectedMupi2); // 添加到全局列表 Data.zujians.add(newZujian); Data.bancais.add(newBancai); // 添加到当前产品的组件列表 Chanpin_Zujian cz = new Chanpin_Zujian(); cz.setId(selectedChanpin.getZujians().size() + 1); cz.setZujian(newZujian); cz.setBancai(newBancai); // 关联新创建的板材 cz.setChanpin(selectedChanpin); selectedChanpin.getZujians().add(cz); // 刷新组件下拉框 setupZujianSpinner(selectedChanpin); spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1); Toast.makeText(getContext(), "组件和板材添加成功", Toast.LENGTH_SHORT).show(); }); builder.setNegativeButton("取消", null); builder.show(); } }添加组件和板材页面下拉框木皮输出name+油或不加 材质输出name

每次重启项目报错1970-01-01 08:00:00.000 0-0 <no-tag> I ---------------------------- PROCESS ENDED (21062) for package com.example.kucun2 ---------------------------- 2025-06-16 02:13:56.761 22497-22497 cmd cmd E BBinder_init Processname cmd 2025-06-16 02:13:56.762 22497-22497 cmd cmd E BBinder_init hasGetProcessName cmd 2025-06-16 02:13:56.797 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.810 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684480, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.811 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684485, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.811 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684489, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.812 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684493, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.812 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684497, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.813 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684502, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.813 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684506, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.814 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684510, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.814 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684514, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.815 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684519, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.815 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684526, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.816 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684531, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.816 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684535, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.816 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684540, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.817 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684544, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.819 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684579, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.819 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684583, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.820 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684597, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.821 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684601, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.821 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684606, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.822 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684625, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.822 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684629, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.822 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684633, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.828 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684733, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.828 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684739, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.829 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684753, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.829 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684757, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.829 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684761, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.830 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684765, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.830 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684769, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.830 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684773, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.830 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684777, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.831 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684781, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.831 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684785, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.831 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684795, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.832 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684801, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.835 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684854, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.835 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684858, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.835 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684862, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.835 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684867, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.836 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.839 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.840 22500-22500 IPCThreadState service E Binder transaction failure. id: 152684962, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.841 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.842 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.847 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.850 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.850 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.852 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.853 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.856 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.860 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.869 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.870 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.877 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.881 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.895 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.900 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.907 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.909 22500-22500 Parcel service E Reading a NULL string not supported here. 2025-06-16 02:13:56.919 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686226, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.919 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686230, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.919 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686234, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.920 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686238, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.921 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686253, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.921 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686257, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.922 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686261, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.922 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686265, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.922 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686269, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.922 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686273, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.923 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686277, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.923 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686283, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.923 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686289, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.923 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686293, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.924 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686297, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.924 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686302, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.924 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686306, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.925 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686311, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.926 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686323, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.926 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686328, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.926 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686332, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.929 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686373, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.930 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686382, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.930 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686386, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.931 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686395, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.931 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686402, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.932 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686407, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.932 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686411, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.932 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686416, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.933 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686420, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.933 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686424, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.933 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686430, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.934 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686435, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.934 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686439, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.934 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686445, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.942 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686554, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.942 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686559, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.943 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686564, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.943 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686568, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.944 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686573, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.944 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686577, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.944 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686581, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.945 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686585, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.945 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686589, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.945 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686594, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.946 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686598, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.946 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686602, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.946 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686606, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.946 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686610, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.947 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686614, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.947 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686618, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.947 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686622, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.947 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686626, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.948 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686630, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.948 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686643, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.948 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686647, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.949 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686651, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.949 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686656, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.949 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686660, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.950 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686664, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.950 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686669, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.951 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686681, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.951 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686686, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.951 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686690, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.952 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686700, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.952 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686704, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.953 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686708, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.953 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686712, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.954 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686727, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.954 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686731, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.954 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686735, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.954 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686739, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.955 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686743, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.955 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686747, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.955 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686751, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.955 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686755, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.956 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686759, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.956 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686763, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.956 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686769, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.956 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686774, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.957 22500-22500 IPCThreadState service E Binder transaction failure. id: 152686779, BR_*: 29201, error: -1 (Operation not permitted) 2025-06-16 02:13:56.972 22500-22500 IPCThreadState service E Binder transaction failure. id: 152687050, BR_*: 29201, error: -1 (Operation not permitted) 1970-01-01 08:00:00.000 0-0 <no-tag> I ---------------------------- PROCESS STARTED (21838) for package com.example.kucun2 -----------package com.example.kucun2.entity.data; import static android.content.ContentValues.TAG; import android.content.Context; import android.util.Log; import com.example.kucun2.R; import com.example.kucun2.entity.Information; import com.example.kucun2.function.MyAppFnction; import com.example.kucun2.function.TLSUtils; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.io.IOException; import java.lang.reflect.Type; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import okhttp3.Call; import okhttp3.Callback; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; public class ApiClient { // 使用Volley、Retrofit或OkHttp实现以下方法 private static final Gson gson = new Gson(); private static OkHttpClient client; private static final String TAG = "ApiClient"; private static final String CERT_FILE = "selfsigned.crt"; // 证书文件名 // 初始化方法 public static void init(Context context) { if (client != null) return; try { // 创建信任管理器 X509TrustManager trustManager = TLSUtils.createTrustManager(context, CERT_FILE); // 创建SSL上下文 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{trustManager}, null); // 配置OkHttpClient client = new OkHttpClient.Builder() .sslSocketFactory(sslContext.getSocketFactory(), trustManager) .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .build(); Log.d(TAG, "OkHttpClient initialized with custom certificate: " + CERT_FILE); } catch (Exception e) { Log.e(TAG, "Failed to initialize secure client", e); // 回退到默认配置(生产环境不应使用) client = new OkHttpClient(); } } public static <T, R> void post(String url, Information<T> requestData, ApiCallback<R> callback) { // 1. 构建请求体(JSON格式) String jsonRequest = ReflectionJsonUtils.toJson(requestData); RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonRequest); Log.d(TAG, "post: "+url); // 2. 创建POST请求 Request request = new Request.Builder() .url(url) .post(body) .build(); Log.d(TAG, "POST请求URL: " + url); Log.d(TAG, "请求数据: " + jsonRequest); // 3. 发送异步请求 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "请求失败: " + e.getMessage()); if (callback != null) { callback.onError(-1, e.getMessage()); } } @Override public void onResponse(Call call, Response response) throws IOException { try (ResponseBody responseBody = response.body()) { if (!response.isSuccessful()) { Log.e(TAG, "服务器响应错误: " + response.code() + " - " + response.message()); if (callback != null) { callback.onError(response.code(), response.message()); } return; } // 4. 处理成功响应 String jsonResponse = responseBody.string(); Log.d(TAG, "服务器响应: " + jsonResponse); // 5. 解析为Information对象 // 注意:这里需要提前确定响应中data的类型(TypeToken) Type responseType = new TypeToken<Information<R>>() { }.getType(); Information<R> responseInfo = gson.fromJson(jsonResponse, responseType); if (callback != null) { callback.onSuccess(responseInfo); } } } }); } public static <T, R> void put(String url, Information<T> data, ApiCallback<T> callback) { String jsonRequest = ReflectionJsonUtils.toJson(data); RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonRequest); Request request = new Request.Builder() .url(url) .put(body) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "PUT request failed", e); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful() && callback != null) { String json = response.body().string(); Type responseType = new TypeToken<Information<T>>(){}.getType(); Information<T> info = gson.fromJson(json, responseType); callback.onSuccess(info); } } }); } public static <R> void delete(String url, ApiCallback<R> callback) { Request request = new Request.Builder() .url(url) .delete() .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "DELETE request failed", e); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful() && callback != null) { // 对于删除操作,通常返回空数据 callback.onSuccess(new Information<>(200, "Deleted", null)); } } }); } public static interface ApiCallback<T> { void onSuccess(Information<T> data); void onError(int statusCode, String error); } }package com.example.kucun2.entity.data; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; import android.os.Looper; import android.util.Log; import com.example.kucun2.entity.*; import com.example.kucun2.function.MyAppFnction; import com.example.kucun2.function.SafeLogger; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.reflect.TypeToken; import java.io.IOException; import java.lang.reflect.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; import okhttp3.*; /** * 核心数据管理中心 * 职责: * 1. 管理所有实体类的全局存储列表 * 2. 处理网络数据加载与本地持久化 * 3. 维护实体间关联关系 * 4. 管理数据同步状态 * * 优化点: * - 使用ConcurrentHashMap提升线程安全 * - 重构关联逻辑避免反射开销 * - 增强序列化/反序列化处理 * - 添加详细方法级注释 */ public class Data { // ====================== 实体存储区 ====================== // 所有实体列表使用线程安全的SynchronizedList // ====================== 静态数据列表声明 ====================== public static final SynchronizedList<Bancai> bancais = new SynchronizedList<>(Bancai.class); public static final SynchronizedList<Caizhi> caizhis = new SynchronizedList<>(Caizhi.class); public static final SynchronizedList<Mupi> mupis = new SynchronizedList<>(Mupi.class); public static final SynchronizedList<Chanpin> chanpins = new SynchronizedList<>(Chanpin.class); public static final SynchronizedList<Chanpin_Zujian> chanpin_zujians = new SynchronizedList<>(Chanpin_Zujian.class); public static final SynchronizedList<Dingdan> dingdans = new SynchronizedList<>(Dingdan.class); public static final SynchronizedList<Dingdan_Chanpin> dingdan_chanpins = new SynchronizedList<>(Dingdan_Chanpin.class); public static final SynchronizedList<Dingdan_chanpin_zujian> Dingdan_chanpin_zujians = new SynchronizedList<>(Dingdan_chanpin_zujian.class); public static final SynchronizedList<Kucun> kucuns = new SynchronizedList<>(Kucun.class); public static final SynchronizedList<Zujian> zujians = new SynchronizedList<>(Zujian.class); public static final SynchronizedList<User> users = new SynchronizedList<>(User.class); public static final SynchronizedList<Jinhuo> jinhuos = new SynchronizedList<>(Jinhuo.class); private static User user; // 实体类型与列表的映射表 <实体类, 对应的同步列表> public static final Map<Class, SynchronizedList<SynchronizableEntity>> dataCollectionMap = new ConcurrentHashMap<>();; private static final Gson gson = GsonFactory.createGson(); private static OkHttpClient client; private static final String TAG = "DataLoader"; // 静态初始化:建立实体类型与列表的映射关系 static { try { // 通过反射获取所有SynchronizedList字段 for (Field field : Data.class.getDeclaredFields()) { if (SynchronizedList.class.equals(field.getType())) { SynchronizedList<?> list = (SynchronizedList<?>) field.get(null); if (list != null) { // 将实体类型与列表关联 dataCollectionMap.put(list.getEntityType(), (SynchronizedList<SynchronizableEntity>) list); } } } } catch (IllegalAccessException e) { throw new RuntimeException("初始化dataCollectionMap失败", e); } } // ====================== 核心数据加载方法 ====================== /** * 从服务器加载全量数据 * @param context Android上下文 * @param callback 加载结果回调 */ public static void loadAllData(Context context, LoadDataCallback callback) { // 主线程检查 if (Looper.myLooper() != Looper.getMainLooper()) { throw new IllegalStateException("必须在主线程调用Data.loadAllData"); } ensurePreservedObjects(); // 确保存在预置对象 // 使用传入的 Context 获取主线程 Handler Handler mainHandler = new Handler(context.getMainLooper()); // 确保使用安全的客户端 if (client == null) { client = MyAppFnction.getClient(); } ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(() -> { SynchronizableEntity.setSyncEnabled(false); String url = MyAppFnction.getStringResource("string", "url") + MyAppFnction.getStringResource("string", "url_all"); Request request = new Request.Builder().url(url).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "Failed to load data", e); SynchronizableEntity.setSyncEnabled(true); mainHandler.post(() -> { if (callback != null) callback.onFailure(); }); } @Override public void onResponse(Call call, Response response) throws IOException { if (!response.isSuccessful()) { Log.e(TAG, "Unexpected response code: " + response.code()); SynchronizableEntity.setSyncEnabled(true); mainHandler.post(() -> { if (callback != null) callback.onFailure(); }); return; } String responseData = response.body().string(); SynchronizableEntity.setSyncEnabled(true); ensurePreservedObjects(); // 在主线程处理解析 mainHandler.post(() -> { parseAndAssignData(responseData, context, callback); }); } }); }); } // ====================== 数据处理私有方法 ====================== /** * 解析JSON数据并更新到实体列表 */ private static void parseAndAssignData(String jsonData, Context context, LoadDataCallback callback) { try { // 解析顶层响应结构 Type responseType = new TypeToken<Information<AllDataResponse>>() {}.getType(); Information<AllDataResponse> info = gson.fromJson(jsonData, responseType); Log.d(TAG, "parseAndAssignData: "+jsonData); // 验证响应有效性 if (info == null || info.getData() == null || info.getStatus() != 200) { throw new IllegalStateException("无效服务器响应"); } AllDataResponse allData = info.getData(); SafeLogger.d("data", "原始数据: " + gson.toJson(allData)); // 更新所有数据列表 updateAllLists(allData); automaticAssociation(); // 建立实体关联 setAllEntitiesState(SynchronizableEntity.SyncState.MODIFIED); // 设置状态 safeCallback(callback, true); // 成功回调 } catch (Exception e) { Log.e(TAG, "数据处理异常: " + e.getMessage()); safeCallback(callback, false); } finally { SynchronizableEntity.setSyncEnabled(true); // 重新启用同步 } } /** * 批量更新所有实体列表 */ private static void updateAllLists(AllDataResponse allData) { updateList(bancais, allData.bancais); updateList(caizhis, allData.caizhis); updateList(mupis, allData.mupis); updateList(chanpins, allData.chanpins); updateList(chanpin_zujians, allData.chanpin_zujians); updateList(dingdans, allData.dingdans); updateList(dingdan_chanpins, allData.dingdan_chanpins); updateList(Dingdan_chanpin_zujians, allData.Dingdan_chanpin_zujians); updateList(kucuns, allData.kucuns); updateList(zujians, allData.zujians); updateList(users, allData.users); updateList(jinhuos, allData.jinhuos); } /** * 安全更新单个列表(保留预置对象) */ private static <T extends SynchronizableEntity> void updateList( List<T> existingList, List<T> newList ) { if (newList == null) return; // 保留现有列表中的预置对象 List<T> preservedItems = existingList.stream() .filter(item -> item != null && item.isPreservedObject()) .collect(Collectors.toList()); // 清空后重新添加(预置对象 + 有效新数据) existingList.clear(); existingList.addAll(preservedItems); existingList.addAll(newList.stream() .filter(item -> item != null && item.getId() != null && item.getId() != -1) .collect(Collectors.toList()) ); } /** * 确保每个列表都有预置对象(用于表示空值/默认值) */ private static void ensurePreservedObjects() { // 为每个实体类型检查并添加预置对象 addIfMissing(bancais, Bancai.class); addIfMissing(caizhis, Caizhi.class); addIfMissing(mupis, Mupi.class); addIfMissing(chanpins, Chanpin.class); addIfMissing(chanpin_zujians, Chanpin_Zujian.class); addIfMissing(dingdans, Dingdan.class); addIfMissing(kucuns, Kucun.class); addIfMissing(zujians, Zujian.class); addIfMissing(Dingdan_chanpin_zujians, Dingdan_chanpin_zujian.class); addIfMissing(dingdan_chanpins, Dingdan_Chanpin.class); addIfMissing(jinhuos, Jinhuo.class); addIfMissing(users, User.class); } private static <T extends SynchronizableEntity> void addIfMissing( List<T> list, Class<T> clazz ) { if (!containsPreservedObject(list)) { list.add(createInstance(clazz)); } } /** * 检查列表是否包含预置对象 * * @param list 目标实体列表 * @return 是否包含预置对象 */ private static <T extends SynchronizableEntity> boolean containsPreservedObject(List<T> list) { return list.stream().anyMatch(item -> item != null && item.isPreservedObject() ); } /** * 自动建立实体间关联关系(通过反射实现) */ private static void automaticAssociation() { for (Class<?> entityClass : dataCollectionMap.keySet()) { try { associateEntities(dataCollectionMap.get(entityClass)); } catch (Exception e) { Log.e(TAG, entityClass.getSimpleName() + " 关联失败", e); } } } private static <T extends SynchronizableEntity> void associateEntities( SynchronizedList<T> list ) throws IllegalAccessException, ClassNotFoundException { for (T entity : list) { if (entity == null) continue; for (Field field : entity.getClass().getDeclaredFields()) { field.setAccessible(true); Class<?> fieldType = field.getType(); // 处理实体引用字段 if (SynchronizableEntity.class.isAssignableFrom(fieldType)) { associateSingleReference(entity, field); } // 处理实体列表字段 else if (List.class.isAssignableFrom(fieldType)) { associateReferenceList(entity, field); } // 处理基础类型字段 else { setDefaultPrimitiveValue(entity, field); } } } } // ====================== 关联辅助方法 ====================== private static void associateSingleReference( SynchronizableEntity entity, Field field ) throws IllegalAccessException { SynchronizableEntity ref = (SynchronizableEntity) field.get(entity); Class<?> targetType = field.getType(); // 查找目标实体 SynchronizableEntity target = findTargetEntity(ref, targetType); field.set(entity, target); } private static void associateReferenceList( SynchronizableEntity entity, Field field ) throws IllegalAccessException, ClassNotFoundException { // 获取列表泛型类型 Type genericType = field.getGenericType(); if (!(genericType instanceof ParameterizedType)) return; Class<?> itemType = Class.forName( ((ParameterizedType) genericType).getActualTypeArguments()[0].getTypeName() ); // 只处理实体列表 if (!SynchronizableEntity.class.isAssignableFrom(itemType)) return; List<SynchronizableEntity> refList = (List<SynchronizableEntity>) field.get(entity); if (refList == null) { refList = new ArrayList<>(); field.set(entity, refList); } // 清理空值并重建引用 refList.removeAll(Collections.singleton(null)); for (int i = 0; i < refList.size(); i++) { refList.set(i, findTargetEntity(refList.get(i), itemType)); } } /** * 查找关联实体(优先匹配ID,找不到则使用预置对象) */ private static SynchronizableEntity findTargetEntity( SynchronizableEntity ref, Class<?> targetType ) { SynchronizedList<SynchronizableEntity> targetList = dataCollectionMap.get(targetType); if (targetList == null) return null; // 无效引用时返回预置对象 if (ref == null || ref.getId() == null || ref.getId() < 0) { return targetList.stream() .filter(SynchronizableEntity::isPreservedObject) .findFirst().orElse(null); } // 按ID查找目标实体 return targetList.stream() .filter(e -> ref.getId().equals(e.getId())) .findFirst() .orElseGet(() -> targetList.stream() // 找不到时回退到预置对象 .filter(SynchronizableEntity::isPreservedObject) .findFirst().orElse(null) ); } // ====================== 工具方法 ====================== /** * 创建带默认值的实体实例(用作预置对象) */ public static <T> T createInstance(Class<T> clazz) { try { T instance = clazz.getDeclaredConstructor().newInstance(); // 设置基础字段默认值 for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); setDefaultFieldValue(instance, field); } // 设置特殊字段 clazz.getMethod("setId", Integer.class).invoke(instance, -1); clazz.getMethod("setState", SynchronizableEntity.SyncState.class) .invoke(instance, SynchronizableEntity.SyncState.PRESERVED); return instance; } catch (Exception e) { Log.e("Data", "创建实例失败: " + clazz.getName(), e); try { return clazz.newInstance(); // 回退创建 } catch (Exception ex) { throw new RuntimeException("无法创建实例", ex); } } } private static <T> void setDefaultFieldValue(T instance, Field field) throws IllegalAccessException { Class<?> type = field.getType(); if (type == String.class) field.set(instance, "无"); else if (type == Integer.class || type == int.class) field.set(instance, -1); else if (type == Double.class || type == double.class) field.set(instance, -1.0); else if (type == Boolean.class || type == boolean.class) field.set(instance, false); else if (type == Date.class) field.set(instance, new Date()); else if (SynchronizableEntity.class.isAssignableFrom(type)) { field.set(instance, getPreservedEntity((Class<?>) type)); } else if (List.class.isAssignableFrom(type)) { field.set(instance, new ArrayList<>()); } } private static SynchronizableEntity getPreservedEntity(Class<?> type) { return dataCollectionMap.get(type).stream() .filter(SynchronizableEntity::isPreservedObject) .findFirst().orElse(null); } private static void setDefaultPrimitiveValue( SynchronizableEntity entity, Field field ) throws IllegalAccessException { if (field.get(entity) != null) return; Class<?> type = field.getType(); if (type == String.class) field.set(entity, "无"); else if (type == Integer.class || type == int.class) field.set(entity, -1); else if (type == Double.class || type == double.class) field.set(entity, -1.0); else if (type == Boolean.class || type == boolean.class) field.set(entity, false); else if (type == Date.class) field.set(entity, new Date()); } /** * 主线程安全回调 */ private static void safeCallback(LoadDataCallback callback, boolean success) { new Handler(Looper.getMainLooper()).post(() -> { if (callback == null) return; if (success) callback.onSuccess(); else callback.onFailure(); }); } /** * 设置所有实体同步状态 */ private static void setAllEntitiesState(SynchronizableEntity.SyncState state) { dataCollectionMap.values().forEach(list -> list.forEach(entity -> { if (entity != null) entity.setState(state); }) ); } public static String exportToJson() { ExportData exportData = new ExportData(); exportData.bancais = new ArrayList<>(bancais); exportData.caizhis = new ArrayList<>(caizhis); // 初始化其他列表... Gson gson = new GsonBuilder() .setPrettyPrinting() .registerTypeAdapter(SynchronizableEntity.class, new EntitySerializer()) .create(); return gson.toJson(exportData); } public static void importFromJson(String json, Context context) { Gson gson = new GsonBuilder() .registerTypeAdapter(SynchronizableEntity.class, new EntityDeserializer()) .create(); Type exportType = new TypeToken<ExportData>(){}.getType(); ExportData importData = gson.fromJson(json, exportType); // 更新数据列表 updateList(bancais, importData.bancais); updateList(caizhis, importData.caizhis); // 更新其他列表... automaticAssociation(); setAllEntitiesState(SynchronizableEntity.SyncState.MODIFIED); // 保存到SharedPreferences saveToPreferences(context, json); } private static void saveToPreferences(Context context, String json) { SharedPreferences prefs = context.getSharedPreferences("DataStore", Context.MODE_PRIVATE); prefs.edit().putString("jsonData", json).apply(); } public static void loadFromPreferences(Context context) { SharedPreferences prefs = context.getSharedPreferences("DataStore", Context.MODE_PRIVATE); String json = prefs.getString("jsonData", null); if (json != null) { importFromJson(json, context); } } // ====================== 内部类/接口 ====================== public interface LoadDataCallback { void onSuccess(); void onFailure(); } /** JSON响应数据结构 */ public static class AllDataResponse { public List<Bancai> bancais; public List<Caizhi> caizhis; public List<Mupi> mupis; public List<Chanpin> chanpins; public List<Chanpin_Zujian> chanpin_zujians; public List<Dingdan> dingdans; public List<Dingdan_Chanpin> dingdan_chanpins; public List<Dingdan_chanpin_zujian> Dingdan_chanpin_zujians; public List<Kucun> kucuns; public List<Zujian> zujians; public List<User> users; public List<Jinhuo> jinhuos; } // 在Data.java中添加 public static class ExportData { public List<Bancai> bancais; public List<Caizhi> caizhis; public List<Mupi> mupis; public List<Chanpin> chanpins; public List<Chanpin_Zujian> chanpin_zujians; public List<Dingdan> dingdans; public List<Dingdan_Chanpin> dingdan_chanpins; public List<Dingdan_chanpin_zujian> Dingdan_chanpin_zujians; public List<Kucun> kucuns; public List<Zujian> zujians; public List<User> users; public List<Jinhuo> jinhuos; } private static class EntityDeserializer implements JsonDeserializer<SynchronizableEntity> { @Override public SynchronizableEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject obj = json.getAsJsonObject(); String entityType = obj.get("entityType").getAsString(); Integer id = obj.get("id").getAsInt(); // 创建临时实体(只包含ID) try { Class<?> clazz = Class.forName("com.example.kucun2.entity." + entityType); SynchronizableEntity entity = (SynchronizableEntity) clazz.newInstance(); entity.setId(id); return entity; } catch (Exception e) { return null; } } } private static class EntitySerializer implements JsonSerializer<SynchronizableEntity> { @Override public JsonElement serialize(SynchronizableEntity src, Type typeOfSrc, JsonSerializationContext context) { JsonObject obj = new JsonObject(); obj.addProperty("id", src.getId()); obj.addProperty("entityType", src.getClass().getSimpleName()); return obj; } } }package com.example.kucun2; import android.os.Bundle; import android.os.Looper; import android.view.View; import android.view.Menu; import com.example.kucun2.entity.data.ApiClient; import com.example.kucun2.entity.data.Data; import com.google.android.material.snackbar.Snackbar; import com.google.android.material.navigation.NavigationView; import androidx.navigation.NavController; import androidx.navigation.Navigation; import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.NavigationUI; import androidx.drawerlayout.widget.DrawerLayout; import androidx.appcompat.app.AppCompatActivity; import com.example.kucun2.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { private AppBarConfiguration mAppBarConfiguration; private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 启动数据加载 loadAppData(); } private void initUI() { if (Looper.myLooper() != Looper.getMainLooper()) { throw new IllegalStateException("Must be called on the main thread"); } ApiClient.init(this); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // ... 其他初始化代码 ... setSupportActionBar(binding.appBarMain.toolbar); binding.appBarMain.fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null) .setAnchorView(R.id.fab).show(); } }); DrawerLayout drawer = binding.drawerLayout; NavigationView navigationView = binding.navView; // Passing each menu ID as a set of Ids because each // menu should be considered as top level destinations. mAppBarConfiguration = new AppBarConfiguration.Builder( R.id.nav_home, R.id.nav_kucun, R.id.nav_add_jinhuo, R.id.nav_diandan) .setOpenableLayout(drawer) .build(); NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main); NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration); NavigationUI.setupWithNavController(navigationView, navController); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onSupportNavigateUp() { NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main); return NavigationUI.navigateUp(navController, mAppBarConfiguration) || super.onSupportNavigateUp(); } public interface OnDataLoadListener { void onDataLoaded(); void onDataError(); } private OnDataLoadListener dataLoadListener; public void setOnDataLoadListener(OnDataLoadListener listener) { this.dataLoadListener = listener; } private void loadAppData() { Data.loadAllData(getApplicationContext(), new Data.LoadDataCallback() { @Override public void onSuccess() { runOnUiThread(() -> { if (dataLoadListener != null) { runOnUiThread(dataLoadListener::onDataLoaded); } initUI(); }); } @Override public void onFailure() { runOnUiThread(() -> { if (dataLoadListener != null) { runOnUiThread(dataLoadListener::onDataError); } }); } }); } }

zip
资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 wget是Linux系统中一款非常实用的命令行下载工具,尤其在没有图形界面的环境下,它可以帮助用户轻松地从互联网上获取所需的文件,比如软件包、备份文件等,是Linux用户不可或缺的工具之一。 高稳定性:即使在带宽有限或网络不稳定的情况下,wget也能表现出色。如果下载因网络问题中断,它会自动重试,直到文件完整下载。 支持断点续传:下载过程中若被中断,wget可以从上次停止的位置继续下载,这对于下载大型文件非常有用,尤其是那些限制链接时间的服务器。 适应性强:无论是桌面系统还是服务器环境,wget都能很好地适应,是下载文件的首选工具之一。 -a <日志文件>:将下载过程中的信息记录到指定的日志文件中,便于后续查看或分析。 -A <后缀名>:指定要下载的文件类型,多个后缀名用逗号分隔,例如-A .jpg,.png,表示只下载JPG和PNG图片。 -b:让wget在后台运行,用户可以同时进行其他操作。 -B <连接地址>:设置基准地址,便于处理相对路径的链接。 -c:继续上次中断的下载任务,适合下载大文件。 -C <标志>:设置服务器数据块功能标志,on表示启用,off表示禁用,默认为on。 -d:以调试模式运行,便于排查问题。 -D <域名列表>:设置要遵循的域名列表,多个域名用逗号分隔。 -e <指令>:作为.wgetrc文件的一部分执行特定指令,可用于自定义配置。 -i <文件>:从指定文件中读取URL列表进行下载。 -l <目录列表>:设置要遵循的目录列表,多个目录用逗号分隔。 -L:仅遵循与当前页面相关的链接。 -r:递归下载,即下载当前页面及其所有子页面上的资源。 -nc:当文件已存在时,不会覆盖原有文件。 -nv:只显示更新和错误信息,隐藏详细下载过程。 -q:静默模式,不显示

最新推荐

recommend-type

三菱FX3U三轴伺服电机与威纶通触摸屏组合程序详解:轴点动、回零与定位控制及全流程解析

三菱FX3U三轴伺服电机与威纶通触摸屏的程序编写方法及其应用。主要内容涵盖伺服电机主控程序、触摸屏程序、轴点动、回零及定位程序、通讯模块程序以及威纶显示器程序的分析。通过对各个模块的深入探讨,帮助读者理解每个部分的功能和实现方式,确保机械运动控制的准确性、高效性和稳定性。此外,文章还提供了关于程序编写过程中可能遇到的问题及解决方案。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是对三菱FX3U三轴伺服电机和威纶通触摸屏有实际操作需求的专业人士。 使用场景及目标:适用于工业自动化项目中,旨在提高对三菱FX3U三轴伺服电机和威纶通触摸屏的理解和应用能力,掌握模块化编程技巧,解决实际工程中的编程难题。 其他说明:文中不仅讲解了各模块的具体实现细节,还强调了程序的安全性和可靠性,为项目的成功实施提供了有力的支持。
recommend-type

职业介绍与人才招聘综合管理系统-基于宏达数据库信息管理开发平台的专业人力资源服务软件-包含基本信息设置-用人单位管理-求职人员登记-数据查询-统计分析-报表生成-打印输出-权限控制.zip

cursor免费次数用完职业介绍与人才招聘综合管理系统_基于宏达数据库信息管理开发平台的专业人力资源服务软件_包含基本信息设置_用人单位管理_求职人员登记_数据查询_统计分析_报表生成_打印输出_权限控制.zip
recommend-type

基于Spark2x分布式计算框架的实时新闻大数据分析可视化系统-实现用户浏览日志采集与实时处理-新闻话题热度排名统计-时段流量峰值分析-新闻曝光量监控-数据可视化展示-采用Kaf.zip

基于Spark2x分布式计算框架的实时新闻大数据分析可视化系统_实现用户浏览日志采集与实时处理_新闻话题热度排名统计_时段流量峰值分析_新闻曝光量监控_数据可视化展示_采用Kaf.zip大数据实战项目
recommend-type

基于springboot小型哺乳类宠物诊所管理系统-4339s0c8【附万字论文+PPT+包部署+录制讲解视频】.zip

基于springboot小型哺乳类宠物诊所管理系统-4339s0c8【附万字论文+PPT+包部署+录制讲解视频】.zip
recommend-type

基于Simulink的风电永磁同步电机并网系统仿真模型与SVPWM控制机制探究

基于Simulink/Matlab构建的风电永磁同步电机并网系统的仿真模型。该模型主要涵盖了SVPWM控制、MPPT风能跟踪算法以及Crowbar电路的低压穿越功能。文中首先解释了机侧变流器的工作原理及其核心——MPPT算法的具体实现方法,采用了黄金分割法进行最大功率点跟踪,并提供了相应的Matlab函数代码。接着讨论了网侧变流器的电网电压定向控制和SVPWM模块的应用,强调了载波频率设置和死区补偿的重要性。对于Crowbar电路部分,则着重讲述了其触发逻辑和保护机制,确保在电网电压骤降时能够稳定运行。此外,还分享了一些仿真设置的小技巧,如选择合适的求解器和优化参数的方法。 适合人群:从事风电系统研究的技术人员、高校相关专业师生、对电力电子控制系统感兴趣的工程技术人员。 使用场景及目标:①为风电并网仿真提供可靠的模型支持;②深入理解SVPWM控制、MPPT算法和Crowbar电路的功能;③掌握风电系统关键组件的设计与优化方法。 其他说明:本文不仅提供了详细的理论解析和技术细节,还附带了具体的代码片段,便于读者实际操作和验证。
recommend-type

Pansophica开源项目:智能Web搜索代理的探索

Pansophica开源项目是一个相对较新且具有创新性的智能Web搜索代理,它突破了传统搜索引擎的界限,提供了一种全新的交互方式。首先,我们来探讨“智能Web搜索代理”这一概念。智能Web搜索代理是一个软件程序或服务,它可以根据用户的查询自动执行Web搜索,并尝试根据用户的兴趣、历史搜索记录或其他输入来提供个性化的搜索结果。 Pansophica所代表的不仅仅是搜索结果的展示,它还强调了一个交互式的体验,在动态和交互式虚拟现实中呈现搜索结果。这种呈现方式与现有的搜索体验有着根本的不同。目前的搜索引擎,如Google、Bing和Baidu等,多以静态文本和链接列表的形式展示结果。而Pansophica通过提供一个虚拟现实环境,使得搜索者可以“扭转”视角,进行“飞行”探索,以及“弹网”来浏览不同的内容。这种多维度的交互方式使得信息的浏览变得更加快速和直观,有望改变用户与网络信息互动的方式。 接着,我们关注Pansophica的“开源”属性。所谓开源,指的是软件的源代码可以被公众获取,任何个人或组织都可以自由地使用、学习、修改和分发这些代码。开源软件通常由社区进行开发和维护,这样的模式鼓励了协作创新并减少了重复性劳动,因为全世界的开发者都可以贡献自己的力量。Pansophica项目作为开源软件,意味着其他开发者可以访问和使用其源代码,进一步改进和扩展其功能,甚至可以为Pansophica构建新的应用或服务。 最后,文件名称“Pansophica-src-1.3”表明了我们讨论的特定版本的Pansophica开源代码。数字“1.3”很可能指的是该版本号,表明这是Pansophica项目的第1.3个公开版本。这个版本号对于开发者来说很重要,因为它可以帮助他们追踪更新的进度、比较版本间的差异以及选择最适合其项目的版本。 综合以上信息,Pansophica开源项目不仅在搜索代理领域引入了创新的交互方式,而且通过开源的方式,提供了技术共享和协作的可能性。对于IT行业来说,开源项目是推动技术发展的重要力量,它激发了社区的活力,促进了知识的传播和技术的进步。通过构建一个开源社区,Pansophica可以吸引来自世界各地的开发者和研究人员,共同探索如何将搜索技术与交互式虚拟现实技术结合起来,为用户带来更加丰富和有效的信息检索体验。同时,Pansophica的开源性质也使其更容易适应未来技术的发展,随着社区的不断贡献和反馈,这一平台有望在功能和性能上得到持续的优化和增强。
recommend-type

跨平台内容提取无忧:coze工作流应对社交媒体挑战

# 1. 社交媒体内容提取的必要性与挑战 ## 1.1 内容提取的必要性 在数字时代,社交媒体内容是信息与数据流动的主干道,公司、个人和研究者都在寻求从这些信息中提取价值。无论是为了市场趋势分析、品牌监控、消费者洞察还是公共舆论监测,有效的社交媒体内容提取变得至关重要。这不仅有助于企业做出数据驱动的决策,也能使个人更好地理
recommend-type

vrrp主设备发送的免费arp

<think>好的,我现在需要回答用户关于VRRP主设备发送免费ARP的目的和工作原理的问题。首先,我得回忆一下VRRP的基本概念和工作机制。VRRP,虚拟路由冗余协议,主要用于在局域网中提供默认网关的冗余备份,确保网络的高可用性。主设备(Master)负责转发流量,而备用设备(Backup)则在主设备故障时接管工作。 用户的问题集中在主设备发送免费ARP的目的和机制上。根据引用[2],免费ARP用于通知下游设备虚拟MAC地址的变更。当主设备被选举出来后,它需要让局域网内的其他设备知道虚拟IP对应的MAC地址已经指向自己,这样流量才会被正确路由到主设备。免费ARP的作用应该就是更新这些设备的
recommend-type

为Ghost博客平台打造的Meteor流星包装使用指南

从给定文件信息中,我们可以提炼出以下IT知识点: ### 标题知识点:流星Ghost软件包 1. **流星Ghost软件包的用途**:流星Ghost软件包是专为Ghost博客平台设计的流星(Meteor)应用程序。流星是一个开源的全栈JavaScript平台,用于开发高性能和易于编写的Web应用程序。Ghost是一个开源博客平台,它提供了一个简单且专业的写作环境。 2. **软件包的作用**:流星Ghost软件包允许用户在流星平台上轻松集成Ghost博客。这样做的好处是可以利用流星的实时特性以及易于开发和部署的应用程序框架,同时还能享受到Ghost博客系统的便利和美观。 ### 描述知识点:流星Ghost软件包的使用方法 1. **软件包安装方式**:用户可以通过流星的命令行工具添加名为`mrt:ghost`的软件包。`mrt`是流星的一个命令行工具,用于添加、管理以及配置软件包。 2. **初始化Ghost服务器**:描述中提供了如何在服务器启动时运行Ghost的基本代码示例。这段代码使用了JavaScript的Promise异步操作,`ghost().then(function (ghostServer) {...})`这行代码表示当Ghost服务器初始化完成后,会在Promise的回调函数中提供一个Ghost服务器实例。 3. **配置Ghost博客**:在`then`方法中,首先会获取到Ghost服务器的配置对象`config`,用户可以在此处进行自定义设置,例如修改主题、配置等。 4. **启动Ghost服务器**:在配置完成之后,通过调用`ghostServer.start()`来启动Ghost服务,使其能够处理博客相关的请求。 5. **Web浏览器导航**:一旦流星服务器启动并运行,用户便可以通过Web浏览器访问Ghost博客平台。 ### 标签知识点:JavaScript 1. **JavaScript作为流星Ghost软件包的开发语言**:标签指出流星Ghost软件包是使用JavaScript语言开发的。JavaScript是一种在浏览器端广泛使用的脚本语言,它也是流星平台的基础编程语言。 2. **流星和Ghost共同使用的语言**:JavaScript同样也是Ghost博客平台的开发语言。这表明流星Ghost软件包可以无缝集成,因为底层技术栈相同。 ### 压缩包子文件的文件名称列表知识点:meteor-ghost-master 1. **版本控制和软件包结构**:文件名称`meteor-ghost-master`暗示了该软件包可能托管在像GitHub这样的版本控制系统上。文件名中的`master`通常指的是主分支或主版本。 2. **软件包的目录结构**:通过文件名称可以推断出该软件包可能拥有一个标准的流星软件包结构,包含了初始化、配置、运行等必要的模块和文件。 3. **软件包的维护状态**:由于文件名没有包含特定的版本号,我们无法直接得知软件包的最新更新情况。通常,软件包维护者会将最新的版本代码放在`master`分支上。 ### 总结 流星Ghost软件包提供了一个有效的解决方案,使得流星平台的开发者能够在他们的应用中添加Ghost博客功能。软件包的使用简便,通过流星的命令行工具安装,并通过JavaScript代码配置和启动Ghost服务。通过流星Ghost软件包,开发者能够享受流星的实时特性以及Ghost博客系统的便利性。此外,软件包的命名和结构也暗示了其维护和版本控制的模式,有助于开发者更好地理解如何使用和维护这一软件包。
recommend-type

抖音标题生成自动化:用coze工作流释放创意

# 1. 抖音标题生成自动化的重要性 随着社交媒体平台的崛起,内容的吸引力很大程度上取决于标题的创意与精准性。抖音作为一个日活亿级的短视频平台,高质量的标题能够有效提高视频的点击率,增加内容的传播。但是,人工撰写标题不仅耗时耗力,而且很难做到快速响应热点,自动化标题生成工具应运而生。coze工作流,作为一种实现自动化生成抖音标题的工具,其重要性不言而喻。它能够利用大数据分析和机器学习技术,提高标题的吸引