Reputation: 65
I am making an android application and i take from database everymoment players who are online.Every player take a place in ListView, is an item list.The list refresh as i expected but when i click on an item list my application crashes.I see in the android monitor an IllegalStateException and i dont know why.I think that because i use the listview when i change the content and when i press the button at the same time.Can you help me someone or suggest something else to do? In the code below i download from database the data and after that i put it in the list.
public void onclickRefreshfunction() {
num = -1;
runOnUiThread(new Runnable() {
@Override
public void run() {
if (lock == 1) {
lock = 0;
ArrayAdapter<String> adapter = new ArrayAdapter<String>(OnLinePlayerActivity.this,
android.R.layout.simple_list_item_1, android.R.id.text1, list_of_onlineplayer);
adapter.clear();
adapter.notifyDataSetChanged();
list_of_levels.clear();
list_of_onlineplayer.clear();
list_of_usernames.clear();
Response.Listener<String> responseListener = new Response.Listener<String>() {
@Override
public void onResponse(final String response) {
try {
JSONObject jsonResponse = new JSONObject(response);
JSONArray usernamearray = jsonResponse.getJSONArray("list_of_usernames");
JSONArray levelarray = jsonResponse.getJSONArray("list_of_levels");
for (int i = 0; i < usernamearray.length(); i++) {
String name = usernamearray.getString(i);
if (name.equals(username)) {
num = i;
continue;
}
list_of_usernames.add(name);
}
for (int i = 0; i < levelarray.length(); i++) {
String level = levelarray.getString(i);
if (i == num) {
continue;
}
list_of_levels.add(level);
}
for (int i = 0; i < list_of_usernames.size(); i++) {
list_of_onlineplayer.add(" Παίκτης "+list_of_usernames.get(i) + " επίπεδο " + list_of_levels.get(i));
}
listView = (ListView) findViewById(R.id.list);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(OnLinePlayerActivity.this,
android.R.layout.simple_list_item_1, android.R.id.text1, list_of_onlineplayer);
listView.setAdapter(adapter);
lock = 1;
} catch (JSONException e) {
e.printStackTrace();
}
}
};
Response.ErrorListener error = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.w("error with volley", "error");
onclickRefreshfunction();
}
};
OnlineRequest onlineRequest = new OnlineRequest(responseListener , error);
// RequestQueue queue = Volley.newRequestQueue(OnLinePlayerActivity.this);
// queue.add(onlineRequest);
Mysingleton.getmInstance(getApplicationContext()).addToRequestque(onlineRequest);
}
}
});
}
Here is the message from android monitor
12-03 10:50:46.371 17346-17346/? E/MessageQueue-JNI: java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131558534, class android.widget.ListView) with Adapter(class android.widget.ArrayAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1566)
at android.widget.AbsListView.onTouchUp(AbsListView.java:4814)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:4610)
at android.view.View.dispatchTouchEvent(View.java:8135)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2425)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2149)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2295)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1622)
at android.app.Activity.dispatchTouchEvent(Activity.java:2565)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2243)
at android.view.View.dispatchPointerEvent(View.java:8343)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4769)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4635)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4193)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4247)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4216)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4327)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4224)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4384)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4193)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4247)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4216)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4224)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4193)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6567)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6484)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6455)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6420)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6647)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java
12-03 10:50:46.381 17346-17346/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.sakis.loginregister, PID: 17346
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131558534, class android.widget.ListView) with Adapter(class android.widget.ArrayAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1566)
at android.widget.AbsListView.onTouchUp(AbsListView.java:4814)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:4610)
at android.view.View.dispatchTouchEvent(View.java:8135)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2425)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2149)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2431)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2164)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2295)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1622)
at android.app.Activity.dispatchTouchEvent(Activity.java:2565)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2243)
at android.view.View.dispatchPointerEvent(View.java:8343)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4769)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4635)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4193)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4247)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4216)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4327)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4224)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4384)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4193)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4247)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4216)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4224)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4193)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6567)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6484)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6455)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6420)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6647)
at a
at a
I think that maybe is a problem of critical section i am not sure.So i need your help to understand how listview working.
Upvotes: 0
Views: 56
Reputation: 945
First of all, you are being distracted by runOnUIThread(), the response listeners might be called on a different thread, depending on your Mysingleton's OnlineRequest handler. Second, you are creating an unused ArrayAdapter at top lines of your code. Third, You do not need to create a new ArrayAdapter each time, just change the list content and call notifyDataSetChanged()
I think the below code should fix your problem:
public void onclickRefreshfunction() {
num = -1;
if (lock == 1) {
lock = 0;
Response.Listener<String> responseListener = new Response.Listener<String>() {
@Override
public void onResponse(final String response) {
list_of_levels.clear();
list_of_onlineplayer.clear();
list_of_usernames.clear();
try {
JSONObject jsonResponse = new JSONObject(response);
JSONArray usernamearray = jsonResponse.getJSONArray("list_of_usernames");
JSONArray levelarray = jsonResponse.getJSONArray("list_of_levels");
for (int i = 0; i < usernamearray.length(); i++) {
String name = usernamearray.getString(i);
if (name.equals(username)) {
num = i;
continue;
}
list_of_usernames.add(name);
}
for (int i = 0; i < levelarray.length(); i++) {
String level = levelarray.getString(i);
if (i == num) {
continue;
}
list_of_levels.add(level);
}
for (int i = 0; i < list_of_usernames.size(); i++) {
list_of_onlineplayer.add(" Παίκτης "+list_of_usernames.get(i) + " επίπεδο " + list_of_levels.get(i));
}
runOnUiThread(new Runnable() {
@Override
public void run() {
listView = (ListView) findViewById(R.id.list);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(OnLinePlayerActivity.this,
android.R.layout.simple_list_item_1, android.R.id.text1, list_of_onlineplayer);
listView.setAdapter(adapter);
}
});
lock = 1;
} catch (JSONException e) {
e.printStackTrace();
}
}
};
Response.ErrorListener error = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.w("error with volley", "error");
onclickRefreshfunction();
}
};
OnlineRequest onlineRequest = new OnlineRequest(responseListener , error);
// RequestQueue queue = Volley.newRequestQueue(OnLinePlayerActivity.this);
// queue.add(onlineRequest);
Mysingleton.getmInstance(getApplicationContext()).addToRequestque(onlineRequest);
}
}
Upvotes: 1
Reputation: 1847
Put runOnUiThread inside your response Leinster where you setting list view and adapter
Upvotes: 0
Reputation: 2065
Once you have modified the list, i.e. by removing or editing its content you need to call "notifyDataSetChanged()" on the adapter to notify your adapter of the changes. In your code you are calling notifyDataSetChanged outside the response method.
Upvotes: 0