Reputation: 990
I have a ListView where I load all the items from a MySQL DataBase in Android and these items are shown. As the list needs to be updated, in the activity I refresh it every 15 seconds with the Asynctask function and updating the ListView. There is also a scrollbar because there could be a lot of items and here is where the error happens. If I go up or down by means of the scrollbar it goes well. However, if I am using the scrollbar and at the same time the activity tries to access the database to load the updated items, the application stops.
Here is the log:
06-23 15:36:32.867: E/AndroidRuntime(7788): FATAL EXCEPTION: main
06-23 15:36:32.867: E/AndroidRuntime(7788): java.lang.IndexOutOfBoundsException: Invalid index 14, size is 0
06-23 15:36:32.867: E/AndroidRuntime(7788): at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
06-23 15:36:32.867: E/AndroidRuntime(7788): at java.util.ArrayList.get(ArrayList.java:304)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.SimpleAdapter.bindView(SimpleAdapter.java:147)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.SimpleAdapter.createViewFromResource(SimpleAdapter.java:126)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.SimpleAdapter.getView(SimpleAdapter.java:114)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.AbsListView.obtainView(AbsListView.java:2445)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.ListView.makeAndAddView(ListView.java:1769)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.ListView.fillUp(ListView.java:706)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.ListView.fillGap(ListView.java:645)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5530)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3509)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.AbsListView.onTouchEvent(AbsListView.java:3906)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.View.dispatchTouchEvent(View.java:7340)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2179)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1914)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2185)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1928)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2185)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1928)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2185)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1928)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2185)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1928)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2185)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1928)
06-23 15:36:32.867: E/AndroidRuntime(7788): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2113)
06-23 15:36:32.867: E/AndroidRuntime(7788): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1466)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.app.Activity.dispatchTouchEvent(Activity.java:2468)
06-23 15:36:32.867: E/AndroidRuntime(7788): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2061)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.View.dispatchPointerEvent(View.java:7525)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3368)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3300)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4392)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4370)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4474)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:163)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:4442)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:4493)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.Choreographer.doCallbacks(Choreographer.java:555)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.Choreographer.doFrame(Choreographer.java:523)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.os.Handler.handleCallback(Handler.java:615)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.os.Handler.dispatchMessage(Handler.java:92)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.os.Looper.loop(Looper.java:137)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.app.ActivityThread.main(ActivityThread.java:4895)
06-23 15:36:32.867: E/AndroidRuntime(7788): at java.lang.reflect.Method.invokeNative(Native Method)
06-23 15:36:32.867: E/AndroidRuntime(7788): at java.lang.reflect.Method.invoke(Method.java:511)
06-23 15:36:32.867: E/AndroidRuntime(7788): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
06-23 15:36:32.867: E/AndroidRuntime(7788): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
06-23 15:36:32.867: E/AndroidRuntime(7788): at dalvik.system.NativeStart.main(Native Method)
Thank you for the help
Edit: Here is the code that I use to refresh the Listview every 15 seconds: @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.all_candidatos);
StrictMode.ThreadPolicy policy = new StrictMode. ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy);
boolean isReachable = false;
try{
isReachable = InetAddress.getByName("192.168.1.41").isReachable(200);
} catch (Exception e){
Log.e("InetAddress", e.getMessage());
}finally {
if (isReachable) {
new CargarCandidatos().execute();
timer();
}else{
Toast.makeText(getApplicationContext(), R.string.errorserver, Toast.LENGTH_LONG).show();
}
}
setListAdapter(adapter);
candidatosList = new ArrayList<HashMap<String, String>>();
}
//
//
public void timer(){
new CountDownTimer(tiempo, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
candidatosList.clear();
new CargarCandidatos().execute();
timer();
}
}.start();}
class CargarCandidatos extends AsyncTask<String, Void, String> {
@Override
protected void onPreExecute() {
if(!isFinishing()){
super.onPreExecute();
pDialog = new ProgressDialog(Monitorizacion.this);
pDialog.setMessage("Monitorizando ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
}
protected String doInBackground(String... args) {
try {
monitorizar();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();}
return null;
}
protected void onPostExecute(String file_url) {
pDialog.dismiss();
runOnUiThread(new Runnable() {
public void run() {
adapter = new SimpleAdapter(
Monitorizacion.this, candidatosList,
R.layout.list_item, new String[] { TAG_NSERIE,
TAG_DNI, TAG_NOMBRE, TAG_TEST, TAG_PREGUNTA, TAG_BATERIA,TAG_CORRECTAS, TAG_ERRORES},
new int[] { R.id.id, R.id.dni, R.id.nombre, R.id.test, R.id.pregunta, R.id.bateria, R.id.correctas, R.id.fallos});
adapter.notifyDataSetChanged();
setListAdapter(adapter);
}
});
}
}
public void monitorizar() throws Exception{
try {
List<NameValuePair> params = new ArrayList<NameValuePair>();
JSONObject json = jParser.makeHttpRequest(url_candidatos, "GET", params);
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {
candidatos = json.getJSONArray(TAG_CANDIDATOS);
for (int i = 0; i < candidatos.length(); i++) {
JSONObject c = candidatos.getJSONObject(i);
String nserie = c.getString(TAG_NSERIE);
String dni = c.getString(TAG_DNI);
String nombre = c.getString(TAG_NOMBRE);
String test = c.getString(TAG_TEST);
String pregunta = c.getString(TAG_PREGUNTA);
String bateria = c.getString(TAG_BATERIA);
String correctas = c.getString(TAG_CORRECTAS);
String errores = c.getString(TAG_ERRORES);
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_NSERIE, nserie);
map.put(TAG_DNI, dni);
map.put(TAG_NOMBRE, nombre);
map.put(TAG_TEST, test);
map.put(TAG_PREGUNTA, pregunta);
map.put(TAG_BATERIA, bateria);
map.put(TAG_CORRECTAS, correctas);
map.put(TAG_ERRORES, errores);
candidatosList.add(map);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
Edit: The problem is that if I am scrolling the Listview up or down and at that time the asynctask function is called for accessing the database, the error happens and the app stops.
Michael Butscher Solution: From what I understood I solved with the piece of advise given by Michael Butscher:
public void timer(){
new CountDownTimer(tiempo, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
new CargarCandidatos().execute();
timer();
}
}.start();}
class CargarCandidatos extends AsyncTask<String, Void, String> {
@Override
protected void onPreExecute() {
if(!isFinishing()){
super.onPreExecute();
pDialog = new ProgressDialog(Monitorizacion.this);
pDialog.setMessage("Monitorizando ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
}
protected String doInBackground(String... args) {
try {
monitorizar();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();}
return null;
}
protected void onPostExecute(String file_url) {
pDialog.dismiss();
runOnUiThread(new Runnable() {
public void run() {
adapter = new SimpleAdapter(
Monitorizacion.this, candidatosList,
R.layout.list_item, new String[] { TAG_NSERIE,
TAG_DNI, TAG_NOMBRE, TAG_TEST, TAG_PREGUNTA, TAG_BATERIA,TAG_CORRECTAS, TAG_ERRORES},
new int[] { R.id.id, R.id.dni, R.id.nombre, R.id.test, R.id.pregunta, R.id.bateria, R.id.correctas, R.id.fallos});
adapter.notifyDataSetChanged();
setListAdapter(adapter);
}
});
}
}
public void monitorizar() throws Exception{
try {
List<NameValuePair> params = new ArrayList<NameValuePair>();
JSONObject json = jParser.makeHttpRequest(url_candidatos, "GET", params);
ArrayList<HashMap<String, String>> temp;
temp = new ArrayList<HashMap<String, String>>();
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {
candidatos = json.getJSONArray(TAG_CANDIDATOS);
for (int i = 0; i < candidatos.length(); i++) {
JSONObject c = candidatos.getJSONObject(i);
String nserie = c.getString(TAG_NSERIE);
String dni = c.getString(TAG_DNI);
String nombre = c.getString(TAG_NOMBRE);
String test = c.getString(TAG_TEST);
String pregunta = c.getString(TAG_PREGUNTA);
String bateria = c.getString(TAG_BATERIA);
String correctas = c.getString(TAG_CORRECTAS);
String errores = c.getString(TAG_ERRORES);
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_NSERIE, nserie);
map.put(TAG_DNI, dni);
map.put(TAG_NOMBRE, nombre);
map.put(TAG_TEST, test);
map.put(TAG_PREGUNTA, pregunta);
map.put(TAG_BATERIA, bateria);
map.put(TAG_CORRECTAS, correctas);
map.put(TAG_ERRORES, errores);
temp.add(map);
candidatosList = temp;
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
Upvotes: 0
Views: 153
Reputation: 10959
In onPostExecute()
you create an adapter which gets candidatosList
as data. The SimpleAdapter
now expects that this data is only changed if notifyDataSetChanged()
is called immediately afterwards (change and call should happen on main thread only).
In onFinish()
of your timer you call candidatosList.clear()
(onFinish()
runs on the main thread so this is ok) but you do not call notifyDataSetChanged()
.
Better approach:
Don't call candidatosList.clear()
at all, instead create a new ArrayList
(e.g. called "temp
") at begin of monitorizar()
, fill it with received data and as last step of monitorizar()
set candidatosList = temp
. To make this work under all circumstances, candidatosList
should be declared volatile
(because it is used by multiple threads).
Upvotes: 1