SearchableSpinner弹窗未关闭按Home键重启APP崩溃求助
解决SearchableSpinner后台恢复崩溃问题
问题根源
崩溃核心原因是com.toptoche.searchablespinnerlibrary.SearchableSpinner类实现了Serializable接口,但内部持有PopupWindow、Context等无法序列化的对象。当APP打开弹窗时进入后台,系统尝试序列化Activity状态时,会触发这些非序列化对象的写入异常,抛出BadParcelableException。
解决方案
方案1:后台前自动关闭弹窗(最简单有效)
在Activity进入后台时强制关闭Spinner弹窗,避免序列化时持有弹窗引用:
@Override protected void onPause() { super.onPause(); if (niceSpinner_word1 != null && niceSpinner_word1.isPopupShowing()) { niceSpinner_word1.dismissPopup(); } }
该方法无需修改库源码,直接在业务代码中处理,可快速解决问题。
方案2:修改库源码修复序列化问题
若需保留弹窗在后台恢复时的状态,可修改库中SearchableSpinner类的实现:
将类中无法序列化的成员(如PopupWindow、Context、View相关引用)用transient关键字标记,序列化时忽略这些字段:
public class SearchableSpinner extends AppCompatSpinner implements Serializable { private transient PopupWindow mPopupWindow; private transient Context mContext; // 其他非序列化成员都添加transient标记 }
若依赖远程库,需fork原仓库修改后,改为依赖自己的fork版本。
方案3:替换为自定义搜索弹窗
放弃使用问题库,用DialogFragment实现带搜索功能的选择弹窗,完全控制状态管理:
// 自定义带搜索的选择弹窗 public class SearchSelectDialog extends DialogFragment { private RecyclerView recyclerView; private EditText searchEt; private List<String> dataList; private SearchSelectAdapter adapter; private OnItemSelectedListener listener; public interface OnItemSelectedListener { void onItemSelected(String item); } @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_search_select, null); recyclerView = view.findViewById(R.id.recycler_view); searchEt = view.findViewById(R.id.search_et); // 初始化列表和搜索逻辑 dataList = getArguments().getStringArrayList("data"); adapter = new SearchSelectAdapter(dataList); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(adapter); searchEt.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { adapter.filter(s.toString()); } @Override public void afterTextChanged(Editable s) {} }); adapter.setOnItemClickListener(item -> { if (listener != null) { listener.onItemSelected(item); } dismiss(); }); AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setView(view) .setTitle("select word from spinner") .setNegativeButton("close", (dialog, which) -> dismiss()); return builder.create(); } // 设置选择回调 public void setOnItemSelectedListener(OnItemSelectedListener listener) { this.listener = listener; } }
使用时在Activity中调用:
// 打开自定义搜索弹窗 SearchSelectDialog dialog = new SearchSelectDialog(); Bundle args = new Bundle(); args.putStringArrayList("data", new ArrayList<>(dataset1)); dialog.setArguments(args); dialog.setOnItemSelectedListener(item -> { refword1 = item; }); dialog.show(getSupportFragmentManager(), "search_select");
内容的提问来源于stack exchange,提问作者Mahdi H
相关产品推荐
相关产品推荐

