我的活动有问题。它在我第一次开始时效果很好但在此之后就崩溃了
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1842)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1860)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:650)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:609)
我尝试将此添加到我的活动但不起作用
@Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super(). Bug on API Level > 11.
}
当我使用commitAllowingStateLoss()
代替commit()
更改片段时,错误现在是活动已被销毁。我必须关闭该应用程序。我不知道为什么它只在第一次调用活动时运行。
这是我改变片段的功能
private void showWaitingFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
WaitingFragment fragment = new WaitingFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
private void showAnswerFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
AnswerFragment fragment = new AnswerFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
首先我在socket {i}上调用showWattingFragment
发出事件后调用showAnswerFragment
。
套接字的代码
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
Log.d("socket_log", "connected");
}
}).on("quizQuestionReady", new Emitter.Listener() {
@Override
public void call(Object... args) {
showWaitingFragment();
}
}).on("quizQuestionLoaded", new Emitter.Listener() {
@Override
public void call(Object... args) {
showAnswerFragment();
}
}).on("quizEnded", new Emitter.Listener() {
@Override
public void call(Object... args) {
showResultFragment();
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {}
});
socket.connect();
正如我之前所说的,第一次我开始活动,在我再次呼叫onBackPress()
或finish()
然后startActivity
之后无法正常工作/>
更新我的活动
public class StudentQuizActivity extends AppCompatActivity {
@BindView(R.id.quiz_content_frame)
FrameLayout _frame_content;
public Socket socket;
String quiz_code;
public SharedPreferences prefs;
ProgressDialog progressDialog;
int user_id;
String token;
public int currentQuestionIndex = -1;
public int currentQuestionIndexForShowing = 0;
public int countCorrect = 0;
public boolean no_answer = true;
public ArrayList<String> answers;
public ArrayList<String> correct_answers;
public ArrayList<Boolean> corrects;
public JSONObject quizConfig;
public JSONArray quizQuestions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_student_quiz);
prefs = new SecurePreferences(this);
quiz_code = prefs.getString(AppVariable.QUIZ_CODE, null);
user_id = prefs.getInt(AppVariable.USER_ID, 0);
token = prefs.getString(AppVariable.USER_TOKEN, null);
ButterKnife.bind(this);
this.setTitle("QUIZ");
// prepare spinner
progressDialog = new ProgressDialog(this, R.style.AppTheme_Dark_Dialog);
progressDialog.setIndeterminate(true);
progressDialog.setCanceledOnTouchOutside(false);
prefs.edit().putString(AppVariable.QUIZ_MESSAGE, "Waiting for the quiz to start").apply();
answers = new ArrayList<>();
correct_answers = new ArrayList<>();
corrects = new ArrayList<>();
setSocket();
new GetQuizTask().execute();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super(). Bug on API Level > 11.
}
//UI
private void showWaitingFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
WaitingFragment fragment = new WaitingFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
private void showAnswerFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
AnswerFragment fragment = new AnswerFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
private void showResultFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ResultFragment fragment = new ResultFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
public void showDetailFragment() {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
DetailFragment fragment = new DetailFragment();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
private class GetQuizTask extends AsyncTask<String, Void, Integer> {
private Exception exception;
private String strJsonResponse;
@Override
protected void onPreExecute() {
progressDialog.setMessage("Loading...");
progressDialog.show();
}
@Override
protected Integer doInBackground(String... params) {
int flag = 0;
try {
URL url = new URL(Network.API_GET_QUIZ);
//prepare json data
JSONObject jsonUserData = new JSONObject();
jsonUserData.put("token", token);
jsonUserData.put("quiz_code", quiz_code);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try {
connection.setReadTimeout(10000);
connection.setConnectTimeout(15000);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
connection.setDoInput(true);
connection.setDoOutput(true);
//write
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(jsonUserData.toString());
writer.flush();
//check http response code
int status = connection.getResponseCode();
switch (status){
case HttpURLConnection.HTTP_OK:
//read response
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line).append("\n");
}
bufferedReader.close();
strJsonResponse = sb.toString();
flag = HttpURLConnection.HTTP_OK;
default:
exception = new Exception(connection.getResponseMessage());
}
}
finally{
connection.disconnect();
}
}
catch(Exception e) {
exception = e;
}
return flag;
}
@Override
protected void onPostExecute(Integer status) {
if (status != HttpURLConnection.HTTP_OK){
displayToast(exception.getMessage());
}
else {
try{
JSONObject jsonObject = new JSONObject(strJsonResponse);
String result = jsonObject.getString("result");
if (result.equals("failure")){
String message = jsonObject.getString("message");
progressDialog.dismiss();
displayToast(message);
return;
}
quizConfig = jsonObject.getJSONObject("quiz");
quizQuestions = quizConfig.getJSONArray("questions");
prefs.edit().putInt(AppVariable.QUIZ_TOTAL, quizQuestions.length())
.putString(AppVariable.QUIZ_TITLE, quizConfig.getString("title")).apply();
progressDialog.dismiss();
showWaitingFragment();
return;
} catch (JSONException e) {
e.printStackTrace();
displayToast(e.getMessage());
}
}
progressDialog.dismiss();
}
}
//Socket
private void setSocket(){
if (Network.isOnline(this)){
try {
socket = IO.socket(Network.HOST);
} catch (URISyntaxException e) {
e.printStackTrace();
}
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
Log.d("socket_log", "connected");
}
}).on("quizQuestionReady", new Emitter.Listener() {
@Override
public void call(Object... args) {
currentQuestionIndexForShowing += 1;
prefs.edit().putString(AppVariable.QUIZ_MESSAGE, "Ready for the next question")
.putInt(AppVariable.QUIZ_INDEX, currentQuestionIndexForShowing).apply();
showWaitingFragment();
}
}).on("quizQuestionLoaded", new Emitter.Listener() {
@Override
public void call(Object... args) {
currentQuestionIndex += 1;
showAnswerFragment();
}
}).on("quizQuestionEnded", new Emitter.Listener() {
@Override
public void call(Object... args) {
}
}).on("quizEnded", new Emitter.Listener() {
@Override
public void call(Object... args) {
prefs.edit()
.putInt(AppVariable.QUIZ_INDEX, 0).apply();
showResultFragment();
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {}
});
socket.connect();
}
}
public void emitAnswer(String option){
JSONObject payload = new JSONObject();
try {
payload.put("quiz_code", quiz_code);
payload.put("question_index", currentQuestionIndex);
payload.put("option", option);
payload.put("student_id", user_id);
} catch (JSONException e) {
e.printStackTrace();
}
no_answer = false;
try {
JSONObject quizDetail = quizQuestions.getJSONObject(currentQuestionIndex);
String correct_option = quizDetail.getString("correct_option");
ArrayList<String> options = new ArrayList<>();
options.add(quizDetail.getString("option_a"));
options.add(quizDetail.getString("option_b"));
options.add(quizDetail.getString("option_c"));
options.add(quizDetail.getString("option_d"));
String[] keys = {"a", "b", "c", "d"};
for (int i = 0; i < 4; i++){
if (correct_option.equals(options.get(i))){
correct_option = keys[i];
break;
}
}
if (option.equals(correct_option)){
corrects.add(true);
countCorrect += 1;
}
else {
corrects.add(false);
}
correct_answers.add(correct_option);
} catch (JSONException e) {
e.printStackTrace();
}
answers.add(option);
socket.emit("answeredQuiz", payload);
}
}
答案 0 :(得分:1)
在代码中需要检查很多东西。让我们逐一看看。
filesCSV <- function(id = 1:332){
library(stringr)
# Append 0 ids in front
fileNames <- paste(str_pad(id, 3, pad = "0"),".csv", sep = "")
# Initially the data is NULL
the_data <- NULL
for(i in seq_along(id)
{
# Read the data in dat object
dat <- read.csv(fileNames[i], header = TRUE)
if(is.null(the_data) # For the first pass when dat is NULL
{
the_data <- dat
}else{ # For all other passes
theData <- rbind(theData, dat)
}
}
return(the_data)
}
这是一项API请求任务,可能需要很长时间。默认情况下,如果一切正常,GetQuizTask
将帮助您在AsyncTask
中处理,然后将结果发布到background
。
在UI thread
中,您隐式调用onPostExecute(Integer status)
,与showWaitingFragment()
相同。
这意味着您在this.showWaitingFragment()
内持有父参考。这可能会导致内存泄漏。示例:如果您的请求需要10秒才能完成,但在调用inner class
之前,如果您的活动被销毁或在10秒之前更改其状态会发生什么? (有很多事情可以让你改变活动,就像你打电话onPostExecute()
,旋转屏幕,系统必须清理内存,用户按finish()
按钮等...)。因此,当这些事情发生时,活动(或Home
中的this
)无法通过垃圾收集收集。这会导致内存泄漏。
还有一件事。如果您的活动从前台更改为后台(用户按this. showWaitingFragment()
按钮),则Home
需要在UI线程中执行onPostExecute
,现在无法完成,会发生什么然后?
这些错误会为您提供showFragment
。
解决方案:使用WeakPreference,如下所示:
IllegalStateException
显示片段有很多功能,可以像这样简化
private class GetQuizTask extends AsyncTask<String, Void, Integer> {
WeakReference<StudentQuizActivity> studentQuizActivity;
@Override
protected void onPreExecute() {
// do your work before the task execute..
}
@Override
protected Integer doInBackground(String... params) {
// do your work in background..
}
@Override
protected void onPostExecute(Integer status) {
try{
if (studentQuizActivity.get() != null) {
studentQuizActivity.get().showInfo();
}
} catch (Exception e) {
}
}
}
然后
private void showFragment(Fragment fragment) {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.quiz_content_frame, fragment);
fragmentTransaction.commit();
}
在showFragment(yourResultFragment);
showFragment(yourTransactionFragment);
使用dismiss
之前,请检查ProgressDialog
。因为用户可以在if (progressDialog.isShowing())
执行之前将其解雇。
请解密您的代码。不要把内心的一切都推到你的内心阶层。它很容易引发大量错误。还有一件事,如果没有特殊用例,请尝试使用静态内部类。请遵循此answers。
我无法检测到你的所有错误,因为我无法了解你的情况,但我希望这有帮助!仔细地重写您的代码,一个接一个。
答案 1 :(得分:0)
这很简单。
您应该使用commitAllowingStateLoss()而不是commit()
transaction.commitAllowingStateLoss();