0

In my program, I have a listview that displays various customer information from SQL database and a button that will clear all customer entry from the database. My problem is:

  1. When the database is empty, the app will crash.
  2. When there is new customer entry, the listview is not updated. I have tried notifyDataSetChanged() and notifyDataSetInvalidated(), but the listview is still not updating.

My main program:

package attendance.emily.example.com.attendance;


import android.os.AsyncTask;
import android.os.StrictMode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;

import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import org.json.JSONArray;

import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;



public class MainActivity extends AppCompatActivity {

    Button cleardata;
    TextView textview3, displayUser, displayTimeout, displayTimein, textview7;
    ListView lv;
    ArrayAdapter<String> adapter;

    String address = "http://192.168.0.100:80/gps/get_logout.php";


    InputStream is = null;

    String line = null;

    String result = null;

    String data[];






    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        lv = (ListView) findViewById(R.id.listView1);


        cleardata = (Button) findViewById(R.id.button);
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

        StrictMode.setThreadPolicy(policy);

        StrictMode.setThreadPolicy((new StrictMode.ThreadPolicy.Builder().permitNetwork().build()));
        getdata3();


        adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data);
        lv.setAdapter(adapter);





        cleardata.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                String link = "http://192.168.0.100:80/gps/delete.php"; //using this IP for Genymotion emulator
                new updateData().execute(link);
                Toast.makeText(MainActivity.this, "Executed", Toast.LENGTH_LONG).show();
            }
        });




    }

    public class updateData extends AsyncTask<String, String, String> {

        @Override
        protected String doInBackground(String... params) {
            HttpURLConnection conn = null;

            try {
                URL url;
                url = new URL(params[0]);
                conn = (HttpURLConnection) url.openConnection();
                if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    InputStream is = conn.getInputStream();
                } else {
                    InputStream err = conn.getErrorStream();
                }
                return "Done";
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (conn != null) {
                    conn.disconnect();
                }
            }
            return null;
        }

    }



private void getdata3()
{
    try{
        URL url = new URL(address);
        HttpURLConnection con = (HttpURLConnection)url.openConnection();
        con.setRequestMethod("GET");
        is = new BufferedInputStream(con.getInputStream());



    } catch(Exception e){
        e.printStackTrace();
    }

    try{
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        while ((line=br.readLine()) != null){
            sb.append(line+"\n");

        }

        is.close();
        result = sb.toString();





    } catch(Exception e){
        e.printStackTrace();
    }

    try {
        String a="";
        String p="";
        String z="";
        JSONArray ja = new JSONArray(result);
        JSONObject jo = null;




        data=new String[ja.length()];


        for (int i=0; i<ja.length(); i++ ){
            jo = ja.getJSONObject(i);
           a =jo.getString("user");
            p = jo.getString("MIN(timein)");
            z = jo.getString("MAX(timeout)");


            data[i] = "User: "+ a + "\n" +"Time In: " + p + "\n" + "Time Out: " + z+"\n"   ;



        }

    }
    catch(Exception e){
        e.printStackTrace();
    }

}










}

Error :

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: attendance.emily.example.com.attendance, PID: 11833
                  java.lang.RuntimeException: Unable to start activity ComponentInfo{attendance.emily.example.com.attendance/attendance.emily.example.com.attendance.MainActivity}: java.lang.NullPointerException: storage == null
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2596)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2653)
                      at android.app.ActivityThread.access$800(ActivityThread.java:156)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1355)
                      at android.os.Handler.dispatchMessage(Handler.java:102)
                      at android.os.Looper.loop(Looper.java:157)
                      at android.app.ActivityThread.main(ActivityThread.java:5872)
                      at java.lang.reflect.Method.invokeNative(Native Method)
                      at java.lang.reflect.Method.invoke(Method.java:515)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:674)
                      at dalvik.system.NativeStart.main(Native Method)
                   Caused by: java.lang.NullPointerException: storage == null
                      at java.util.Arrays$ArrayList.<init>(Arrays.java:38)
                      at java.util.Arrays.asList(Arrays.java:155)
                      at android.widget.ArrayAdapter.<init>(ArrayAdapter.java:128)
                      at attendance.emily.example.com.attendance.MainActivity.onCreate(MainActivity.java:73)
                      at android.app.Activity.performCreate(Activity.java:5312)
                      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1111)
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2552)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2653) 
                      at android.app.ActivityThread.access$800(ActivityThread.java:156) 
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1355) 
                      at android.os.Handler.dispatchMessage(Handler.java:102) 
                      at android.os.Looper.loop(Looper.java:157) 
                      at android.app.ActivityThread.main(ActivityThread.java:5872) 
                      at java.lang.reflect.Method.invokeNative(Native Method) 
                      at java.lang.reflect.Method.invoke(Method.java:515) 
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:674) 
                      at dalvik.system.NativeStart.main(Native Method) 

Any advice on how i can solve my problem?

Emilyy Lim
  • 89
  • 1
  • 1
  • 14
  • A `LogCat` would help on that crash. Also, I dont see a `onPostExecute()` in your `AsyncTask`? This is where I would have expected the list to be populated. – TheLettuceMaster Jan 12 '17 at 17:27
  • @KickingLettuce Hi i am new to android and i am following tutorials on youtube on how to create listview to display database information, the youtuber does not create onPostExecute() at all. Sorry about that, what do i have to write in the onPostExecute()? And i have updated my logcat. – Emilyy Lim Jan 12 '17 at 17:38
  • Basically the results of the `doInBackground()` are passed as a parameter to`onPostExecute()`. Although I often `return null` (in`doInBackground()`) so i have that (`onPostExecute()`) as a `void` function. The point is, it runs (`onPostExecute()`) after the background 'getting data' thread is completed. So if you populate an `Array` or `ArrayList<>` in the background, you can make it a class parameter (or just pass it) and use it in `onPostExecute()` and populate your `adapter` with it. Link: https://developer.android.com/reference/android/os/AsyncTask.html – TheLettuceMaster Jan 12 '17 at 17:44
  • @KickingLettuce I have added, protected void onPostExecute(String s) { adapter.notifyDataSetChanged(); super.onPostExecute(s); } – Emilyy Lim Jan 12 '17 at 18:07
  • That is fine, as long as it is done AFTER you have updated the adapter and added the new info. I would recommend using an ArrayList instead of an Array also. It is easier when you want to add new data. – TheLettuceMaster Jan 12 '17 at 18:36
  • @KickingLettuce Sorry I have search on stackoverflow for quite long and i cannot get a solution to my problem.... most of the answers they provided me is using notifyDataSetChanged() , but i tried several times and it still did not work. Please help. – Emilyy Lim Jan 13 '17 at 10:44
  • I have been thinking, in your situation you do not need the `onPostExecute()` if this is a silent update to the background. – TheLettuceMaster Jan 13 '17 at 21:48

1 Answers1

0

Before you call adapter.notifyDataSetChanged();, you must update the adapter (or the data it holds), something like this:

String s = "new item";
adapter.add(s);

Then

adapter.notifyDataSetChanged(); 

However, a better way:

Since you are using a String[] you can not add items to it. I recommend using ArrayList<String> list = new ArrayList<String>(); then populate your adapter with it as you do now.

adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);

Then when you want to add a new item, do this:

list.add(s);
adapter.notifyDataSetChanged(); 

So if you want to show a new list item, update the list first, then call notifyDataSetChanged(). Sidenote: You can also update existing rows in the same way, but you would have to get the position, usually passed in from onClick methods.

Here is another great questions on this with good answers

Community
  • 1
  • 1
TheLettuceMaster
  • 15,594
  • 48
  • 153
  • 259