Katherine99
Katherine99

Reputation: 990

Database error in ListView: app has stopped

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

Answers (1)

Michael Butscher
Michael Butscher

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

Related Questions