- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在编写一个数独求解器应用程序。然而,由于某种未知原因,它不断崩溃。
当我尝试调试应用程序时,我没有得到具体的一行来告诉我代码中的哪些内容导致了应用程序崩溃。然而,我看到它遍历了整个solverActivity类而没有崩溃,并显示了正确的suoku板大约半秒,然后崩溃了。
我将错误消息解释为好像我试图发送不可序列化的对象(按钮)。但是,我在代码中找不到尝试这样做的地方。
我用谷歌搜索但没有找到任何对我有帮助的解决方案。这促使我写了这篇文章。
这是堆栈跟踪。
2020-03-08 09:40:19.559 15499-15499/com.example.sodukosolver E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.sodukosolver, PID: 15499 java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = [[Landroid.widget.Button;) at android.os.Parcel.writeSerializable(Parcel.java:1833) at android.os.Parcel.writeValue(Parcel.java:1780) at android.os.Parcel.writeArrayMapInternal(Parcel.java:928) at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1584) at android.os.Bundle.writeToParcel(Bundle.java:1253) at android.app.IActivityTaskManager$Stub$Proxy.activityStopped(IActivityTaskManager.java:4505) at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:145) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) Caused by: java.io.NotSerializableException: androidx.appcompat.widget.AppCompatButton at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1240) at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1434) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1230) at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1434) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1230) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354) at android.os.Parcel.writeSerializable(Parcel.java:1828) at android.os.Parcel.writeValue(Parcel.java:1780) at android.os.Parcel.writeArrayMapInternal(Parcel.java:928) at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1584) at android.os.Bundle.writeToParcel(Bundle.java:1253) at android.app.IActivityTaskManager$Stub$Proxy.activityStopped(IActivityTaskManager.java:4505) at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:145) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
这是我的 MainActivity,我认为它工作得很好(很抱歉没有遵循 CLEAN CODE :/)。
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import java.util.HashMap;
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
private Button[][] verticalButtons = new Button[9][9];
private Button[][] landscapeButtons = new Button[9][9];
private Button solveButton, clearButton;
private HashMap<String, Integer> solveMap = new HashMap<>();
private Spinner spinner;
private String number;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
spinner = findViewById(R.id.number_spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.numbers, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(this);
solveButton = findViewById(R.id.solve_button);
clearButton = findViewById(R.id.clear_button);
solveButton.setOnClickListener(v -> loadResult());
if(savedInstanceState != null && getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
solveMap = (HashMap<String, Integer>) savedInstanceState.getSerializable("solveMap");
verticalButtons = findButtons(verticalButtons,"button", false);
clearButton.setOnClickListener(v -> clearAllButtons(verticalButtons));
loadButtonValue(verticalButtons);
}
else if(savedInstanceState != null && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
solveMap = (HashMap<String, Integer>) savedInstanceState.getSerializable("solveMap");
landscapeButtons = findButtons(landscapeButtons,"buttons", false);
clearButton.setOnClickListener(v -> clearAllButtons(landscapeButtons));
loadButtonValue(landscapeButtons);
}
else if(savedInstanceState == null && getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
verticalButtons = findButtons(verticalButtons,"button", true);
clearButton.setOnClickListener(v -> clearAllButtons(verticalButtons));
}else{
landscapeButtons = findButtons(landscapeButtons,"buttons", true);
clearButton.setOnClickListener(v -> clearAllButtons(landscapeButtons));
}
}
/**
* This method finds the buttons of the board based after the orientation of the device
* @param sudokuButtons 2D Array of Buttons[9][9]
* @param orientation String referring to xml id, button = PORTRAIT(xml), buttons = LANDSCAPE(xml)
* @param boardIsEmpty boolean used to determine if code is being created for the first time or being recreated
* @return a 2D Array of buttons[9][9]
*/
private Button[][] findButtons(Button[][] sudokuButtons, String orientation, boolean boardIsEmpty){
for(int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++){
String buttonID = orientation + i + j;
int resId = getResources().getIdentifier(buttonID, "id", getPackageName());
sudokuButtons[i][j] = findViewById(resId);
sudokuButtons[i][j].setOnClickListener(v -> updateButtonValue(v));
if(boardIsEmpty) {
solveMap.put("key" + i + j , 0);
}
}
return sudokuButtons;
}
/**
* This method updates the values in a button after it has been clicked
* @param view
*/
private void updateButtonValue(View view){
Button button = findViewById(view.getId());
String buttonName = getResources().getResourceEntryName(view.getId());
String numberString = buttonName.replaceAll("\\D+","");
if(number.equals("Select a number")) {
button.setText("");
solveMap.put("key" + numberString, 0);
}
else {
button.setText(number);
solveMap.put("key" + numberString, Integer.valueOf(number));
}
}
/**
* This method recreates the board after the device's orientation has changed
* @param sudukoButtons Empty 2D Array of buttons
*/
private void loadButtonValue(Button[][] sudukoButtons) {
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++) {
String number = String.valueOf(solveMap.get("key" + i + j));
if (number.equals("0"))
sudukoButtons[i][j].setText("");
else
sudukoButtons[i][j].setText(number);
}
}
/**
* This method changes the activity and sends some parameters to the next activity
*/
private void loadResult(){
long time = System.currentTimeMillis();
int [][] resultBoard = new int[9][9];
resultBoard = populateBoard(resultBoard);
Intent intent = new Intent(this, SolverActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("board", resultBoard);
intent.putExtras(bundle);
intent.putExtra("start", time);
startActivity(intent);
}
/**
* This method retrieves all the values from the buttons and places them in a 2D Array of the type int
* @param resultBoard Empty 2D Array
* @return A populated 2D Array, which the user wants to have solved
*/
private int[][] populateBoard(int[][] resultBoard){
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
int number = solveMap.get("key" + i + j);
resultBoard[i][j] = number;
}
}
return resultBoard;
}
/**
* Clears all the buttons according the device orientation
* @param sudokuButtons 2D Array of Buttons which is linked to xml file (PORTRAIT or LANDSCAPE)
*/
private void clearAllButtons(Button[][] sudokuButtons){
solveMap.clear();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
sudokuButtons[i][j].setText("");
solveMap.put("key" + i + j, 0);
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("solveMap", solveMap);
outState.putSerializable("verticalButtons", verticalButtons);
outState.putSerializable("landscapeButtons", landscapeButtons);
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
this.number = parent.getItemAtPosition(position).toString();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
这是我的 SolverActivity,我认为它导致了问题(很抱歉 onCreate 时间太长,我计划在解决这个问题后重构该类)。
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
public class SolverActivity extends AppCompatActivity {
private Button[][] buttons = new Button [9][9];
private Button backButton;
private int[][] board, solvedBoard;
private TextView timeView;
private long test;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_solver);
timeView = findViewById(R.id.result_time);
backButton = findViewById(R.id.back_button);
backButton.setOnClickListener(v -> onBackPressed());
board = (int[][]) getIntent().getExtras().getSerializable("board");
long time = getIntent().getLongExtra("start", 0);
if(savedInstanceState == null) {
SudokuSolver sudokuSolver = new SudokuSolver(board);
if (sudokuSolver.solve())
solvedBoard = sudokuSolver.getBoard();
else
solvedBoard = new int[9][9];
}
else{
solvedBoard = (int[][]) savedInstanceState.getSerializable("solvedBoard");
}
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
String buttonId = "button" + i + j;
int resId = getResources().getIdentifier(buttonId, "id", getPackageName());
buttons[i][j] = findViewById(resId);
buttons[i][j].setText(String.valueOf(solvedBoard[i][j]));
}
}
if (savedInstanceState == null)
test = System.currentTimeMillis();
else
test = savedInstanceState.getLong("test");
long stop = test - time;
timeView.append(stop + "ms");
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("solvedBoard", solvedBoard);
outState.putLong("test", test);
}
}
最佳答案
我找到了导致我的应用崩溃的原因,如果其他人可能遇到类似的问题,我想分享我的解决方案。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("solveMap", solveMap);
// The two lines beneath caused the app to crash
outState.putSerializable("verticalButtons", verticalButtons);
outState.putSerializable("landscapeButtons", landscapeButtons);
}
我什至不知道,为什么我一开始就有这些,因为没有使用过。无论如何,因为我不需要它们,所以只是删除了这两行,使其看起来像这样。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("solveMap", solveMap);
}
我认为导致问题的原因是以这种方式保存按钮的二维数组。对于有类似问题的人,我建议您检查一下 OnsaveInstanceState 中的保存方式。
关于java.lang.RuntimeException : Parcelable encountered IOException writing serializable object (name = [[Landroid. widget.Button;),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60586168/
实现了Serializable接口(interface)的类的子类是否也实现了Serializable?也就是说子类的实例也可以序列化吗? 最佳答案 I wanted to ask whether t
当对象可序列化或不可序列化时,将数据对象保存到数据库有什么不同。 例如:我有一个名为 Book 的域类 class Book implements Serializable{ private int
我的理解是conflict serializable 隐含serializable。我不确定这如何让他们与众不同。可序列化是否意味着冲突可序列化? 最佳答案 冲突可序列化是可序列化的一个子集,因此仅仅
我正在阅读接口(interface) Serializable 的文档,我在其中找到以下几行: To allow subtypes of non-serializable classes to be
scala @Serializable 的 Action 方式与Java Serializable 不同吗? 我的意思是序列化对象的方式还是两者都使用相同的标准序列化? 最佳答案 Scala 可以编译
我遇到过使用这两种表示法中的任何一种的例子。我找不到关于它的任何信息,说明哪一个是常见的,为什么允许使用 2 个符号,以及两者之间是否存在任何细微差别。 有人有想法吗? 最佳答案 不,没有功能差异。
“可序列化”类中的字段应该是 transient 的或可序列化的,可以修复在另一个类中使用的任何实体/类,但当在甚至无法创建的 dto 类中声明 List/Map 时,就会发生这种情况也一样短暂。请让
我面临任务不可序列化的问题,我检查了其他答案并使我的调用和调用类可序列化。我的代码就像 - public class MultiClassification implements Serializab
我到处都读到 Java Serializable 比 Parcelable 慢得多。 Kotlin Serializable 也是这样吗?或者 Kotlin Serializable 和 Kotlin
描述: 我有一个 ArrayList,它接受任何实现 Serializable 的类。我什至可以将实现 Serializable 的类的实例添加到这个数组列表中,而不会出现任何编译错误。 Java 泛
我正在实现一个可序列化的类(因此它是一个使用 RMI 的值对象)。但我需要测试它。有没有办法轻松做到这一点? 澄清:我正在实现这个类,所以在类定义中粘贴 Serializable 很简单。我需要手动对
我尝试执行以下简单代码。 System.out.println() 不打印单词“Serialized:”。输出为true。 ArrayList arrayList = new ArrayList();
伙计们,我有一个最简单的类,我想成为 Parcelable。我正在按照以下方式进行: public class MyField implements Serializable, Parcelable
我的问题与this 非常相似除了这个问题我在 SonarLint V3 (squid:S1948) 中遇到过。 我的代码是: public class Page implements Serializ
考虑下面的类(class)。如果我对它运行 Findbugs,它会在第 5 行但不在第 7 行给我一个错误(“可序列化类中的非 transient 非可序列化实例字段”)。 1 public clas
当我在 Spark(由 java 编写)应用程序中使用 UDF 函数时,出现此错误。 org.apache.spark.SparkException:任务不可序列化 在 org.apache.spar
我正在使用KTOR框架在我的Android应用程序中发出http请求。我在运行项目时遇到错误。。插件:。依赖关系:。模型类:。接口调用:。我花了几个小时寻找解决方案。我遵循了许多线索,但都没有奏效。我
我发现有人回答了可线性化和可串行化之间的差异,但我没有发现有人说可串行化与顺序一致性相同或不同。 此外,我在不同的文章、书籍和网页中对上述术语的不同定义感到震惊,我把这一切都搞糊涂了。 有人可以解释可
我读过几个相关的问题,但没有一个是更有趣的情况。 这是我的问题,假设我有课 class A implements Serializable { private int a; priva
我注意到在 Spring-boot 中很多人创建模型/实体并实现 Serialiazable 接口(interface)。 public class ModelBase implements Seri
我是一名优秀的程序员,十分优秀!