0

when I run my app in Android Studio, everything run correctly. The ListView in drawer is correctly populated by run a RushSearch() query. But when I have created the apk and I installed on my smartphone to try run the app, the ListView in Drawer at the first run doesn't populated. If I close the app and run it again, everything is correct.

Why this anomaly?

The code for onCreate method on MainActivity.java class is this

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    callWebservice();

    // Layout principale col drawer
    setContentView(R.layout.activity_main_drawer);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    leftArrow = (ImageView) findViewById(R.id.left_arrow);
    titolo = (TextView) findViewById(R.id.titolo_id);

    ActionBarDrawerToggle actionBarDrawerToggle =
            new ActionBarDrawerToggle(this, drawerLayout, toolbar,
                    R.string.navigation_drawer_open, R.string.navigation_drawer_close);

    drawerLayout.setDrawerListener(actionBarDrawerToggle);
    actionBarDrawerToggle.syncState();

    drawerListView = (ListView) findViewById(R.id.drawer_listView);

    // SELECT * FROM Sections where Fk == 0;
    sectionsList = new RushSearch().whereEqual("Fk", 0).find(Sections.class);
    Log.d("ELEMENTI",""+sectionsList.size());
    drawerListViewAdapter = new DrawerListViewAdapter(sectionsList, getApplicationContext());

    // Adapter che si occupa di popolare il drawer
    drawerListView.setAdapter(drawerListViewAdapter);


    // Listner per il click su un elemento del drawer
    drawerListView.setOnItemClickListener(click);
}

The method callWebservice() is responsabile to take a JSON file from an url and its code is this

private void callWebservice() {

    String tag_json_obj = "GetItem";
    String url = String.format("http://digitalbox.getsandbox.com/item");
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {

            try {
                saveSections(response.getJSONArray("Sections"));

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

        }
    }, new Response.ErrorListener() {
        public void onErrorResponse(VolleyError error) {
            VolleyLog.d("Settings", "Error: " + error.getMessage());
        }
    }) {
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            HashMap<String, String> headers = new HashMap<String, String>();
            headers.put("Content-Type", "application/json");
            headers.put("Accept", "application/json");
            return headers;
        }
    };
    NetworkController.getInstance().addToRequestQueue(jsonObjectRequest, tag_json_obj);
}

private void saveSections(final JSONArray section) {

    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {


            int c = section.length();
            for (int i = 0; i < c; i++) {

                try {
                    JSONObject obj = section.getJSONObject(i);

                    Sections s = new RushSearch().whereEqual("ID", obj.getInt("ID")).findSingle(Sections.class);
                    if (s == null) {
                        s = new Sections();
                        s.setID(obj.getInt("ID"));
                    }

                    if (!obj.isNull("Fk"))
                        s.setFk(obj.getInt("Fk"));

                    s.setTitle(obj.getString("Title"));

                    if (!obj.isNull("CategoryColor"))
                        s.setCategoryColor(obj.getString("CategoryColor"));

                    s.setPos(obj.getInt("Pos"));
                    s.setLanguageId(obj.getInt("LanguageId"));
                    s.setUnavailableForSend(obj.getBoolean("UnavailableForSend"));

                    s.save();

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

            Log.d("sections", "DB updated");


        }
    });
    t.setPriority(Thread.MIN_PRIORITY);
    t.start();
}

If I run the app with Android Studio, in an AVD smartphone, I have this log

    11-30 15:21:53.520 2170-2170/? I/art: Not late-enabling -Xcheck:jni (already on)
11-30 15:21:53.520 2170-2170/? I/art: Late-enabling JIT
11-30 15:21:53.558 2170-2170/? I/art: JIT created with code_cache_capacity=2MB compile_threshold=1000
11-30 15:21:53.685 2170-2170/rawpepper.it.digitalbox W/System: ClassLoader referenced unknown path: /data/app/rawpepper.it.digitalbox-2/lib/x86
11-30 15:21:54.099 2170-2170/rawpepper.it.digitalbox W/art: Before Android 4.1, method int android.support.v7.internal.widget.ListViewCompat.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView
11-30 15:21:54.469 2170-2170/rawpepper.it.digitalbox D/ELEMENT: 13
11-30 15:21:54.486 2170-2210/rawpepper.it.digitalbox D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
11-30 15:21:54.592 2170-2210/rawpepper.it.digitalbox I/OpenGLRenderer: Initialized EGL, version 1.4
11-30 15:21:54.719 2170-2210/rawpepper.it.digitalbox W/EGL_emulation: eglSurfaceAttrib not implemented
11-30 15:21:54.719 2170-2210/rawpepper.it.digitalbox W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xad6fc2e0, error=EGL_SUCCESS
11-30 15:21:57.542 2170-2204/rawpepper.it.digitalbox D/Volley: [117] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://digitalbox.getsandbox.com/item 0x95b78f5f NORMAL 1> [lifetime=3034], [size=196862], [rc=200], [retryCount=0]
11-30 15:21:57.691 2170-2180/rawpepper.it.digitalbox W/art: Suspending all threads took: 25.964ms
11-30 15:21:57.909 2170-2405/rawpepper.it.digitalbox D/sections: DB updated

that tells me that the number of elements in sectionList array are 13 (sixth row), that is correct. app run with Android Studio If I create the apk and I install it on my smartphone, and I plug this on pc to check the log when I run the app, I have this log

    11-30 15:35:01.765 17183-17183/rawpepper.it.digitalbox I/art: Late-enabling -Xcheck:jni
11-30 15:35:01.883 17183-17183/rawpepper.it.digitalbox W/System: ClassLoader referenced unknown path: /data/app/rawpepper.it.digitalbox-2/lib/arm
11-30 15:35:02.357 17183-17183/rawpepper.it.digitalbox W/art: Before Android 4.1, method int android.support.v7.internal.widget.ListViewCompat.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView
11-30 15:35:03.235 17183-17183/rawpepper.it.digitalbox D/ELEMENT: 0
11-30 15:35:03.249 17183-17260/rawpepper.it.digitalbox D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
11-30 15:35:03.304 17183-17260/rawpepper.it.digitalbox I/Adreno-EGL: <qeglDrvAPI_eglInitialize:379>: QUALCOMM Build: 09/02/15, 76f806e, Ibddc658e36
11-30 15:35:03.306 17183-17260/rawpepper.it.digitalbox I/OpenGLRenderer: Initialized EGL, version 1.4
11-30 15:35:05.976 17183-17321/rawpepper.it.digitalbox D/sections: DB updated

that tells me that the elements in sectionList array are 0, but if I close and run it again, everything is correct.

Dennis A. Boanini
  • 477
  • 1
  • 5
  • 19
  • Without reading past the 3rd line of code, I'm guessing that `callWebservice();` is used to populate the drawer. So you need to wait for the response and load it then – codeMagic Nov 30 '15 at 14:45
  • the drawer is populated in onCreate method with this row of code `sectionsList = new RushSearch().whereEqual("Fk", 0).find(Sections.class); Log.d("ELEMENTI",""+sectionsList.size()); drawerListViewAdapter = new DrawerListViewAdapter(sectionsList, getApplicationContext());` – Dennis A. Boanini Nov 30 '15 at 15:00
  • yes but you're not sure that the information you're looking for is stored. The call to the webservice is asynchronous so it's possible that you try to read data that is not already received from the webservice – baki Nov 30 '15 at 15:20
  • Ok, and how I can correct this? – Dennis A. Boanini Nov 30 '15 at 15:22
  • just try to avoid calling a webservice to initialize that list. If the internet connection of the user is slow, he will always have a problem when starting the application. Think about default values when the information is not received yet. – baki Nov 30 '15 at 15:26
  • I'm sorry but i do not understand . I have this problem even if I'm am connected with Wi-Fi. And I don't understand why at the first run I have this problem, but during the next run I don't have this problem. And I don't understand why if I run the application with an AVD I don't have this problem – Dennis A. Boanini Nov 30 '15 at 15:37
  • No, I use Android studio. Build -> create apk – Dennis A. Boanini Nov 30 '15 at 21:42
  • Sorry I reread. Proguard is not your issues. You just need to reset up your draw after the save call. – Stuart Campbell Nov 30 '15 at 21:44

4 Answers4

0

You need to set up the drawer after the data is downloaded. For example by calling saveDate() when downloading a new section and setUpDraw() in onCreate().

private void saveData(Sections newSections) {
    newSections.save()
    setUpDraw()
}

private void setUpDraw() {

    drawerListView = (ListView) findViewById(R.id.drawer_listView);
    sectionsList = new RushSearch().whereEqual("Fk", 0).find(Sections.class);
    drawerListViewAdapter = new DrawerListViewAdapter(sectionsList, context); // You don't want application context
    drawerListView.setAdapter(drawerListViewAdapter);
    drawerListView.setOnItemClickListener(click);
}
Stuart Campbell
  • 1,141
  • 11
  • 13
  • uhm...I don't understand the utility of `saveData()` method. I have the `saveSections()` method... – Dennis A. Boanini Nov 30 '15 at 22:19
  • Point was just to call setUpDraw() after saving. I just didn't want to copy all your code. Also my implementation of setUpDraw() is unlikely to be complete, I leave it up to you to fill in the blanks. – Stuart Campbell Dec 01 '15 at 11:17
0

I think you should call this part of your code:

// SELECT * FROM Sections where Fk == 0;
sectionsList = new RushSearch().whereEqual("Fk", 0).find(Sections.class);
Log.d("ELEMENTI",""+sectionsList.size());
drawerListViewAdapter = new DrawerListViewAdapter(sectionsList, getApplicationContext());

// Adapter che si occupa di popolare il drawer
drawerListView.setAdapter(drawerListViewAdapter);

After the saveSections() method completes. Something like this:

private void callWebservice() {

String tag_json_obj = "GetItem";
String url = String.format("http://digitalbox.getsandbox.com/item");
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
    @Override
    public void onResponse(JSONObject response) {
        try {
            saveSections(response.getJSONArray("Sections"));
// SELECT * FROM Sections where Fk == 0;
sectionsList = new RushSearch().whereEqual("Fk", 0).find(Sections.class);
Log.d("ELEMENTI",""+sectionsList.size());
drawerListViewAdapter = new DrawerListViewAdapter(sectionsList, getApplicationContext());

// Adapter che si occupa di popolare il drawer
drawerListView.setAdapter(drawerListViewAdapter);
        } catch (JSONException e) {
            e.printStackTrace();
        }

    }
}, new Response.ErrorListener() {
    public void onErrorResponse(VolleyError error) {
        VolleyLog.d("Settings", "Error: " + error.getMessage());
    }
}) {
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        HashMap<String, String> headers = new HashMap<String, String>();
        headers.put("Content-Type", "application/json");
        headers.put("Accept", "application/json");
        return headers;
    }
};
NetworkController.getInstance().addToRequestQueue(jsonObjectRequest, tag_json_obj);

}

Suncatcher
  • 60
  • 1
  • 7
  • I tried with your solutions but I have the same problem. The listView in Drawer not populates at the first run. – Dennis A. Boanini Nov 30 '15 at 23:04
  • After the saveSections() method, your sectionsList is populated? What does your logcat prints? – Suncatcher Dec 01 '15 at 14:37
  • If I place `Log.d(numberOfElement_tag, "" + sectionsList.size());` after the call at the `saveSections()` method (after the row `saveSections(response.getJSONArray("Sections"));` in `callWebservice()` ), logcat tell me `12-01 15:52:00.237 23332-23332/rawpepper.it.digitalbox D/Number of element in sectionList: 0` (If I install apk on my smartphone, if I run the application in AVD in Android Studio everything is ok and the number of elements in sectionList is 13) – Dennis A. Boanini Dec 01 '15 at 14:56
  • Does your Thread get called the first time? It's really weird man – Suncatcher Dec 01 '15 at 15:02
  • How I can check if the Thread is called the first time? The thing that I don't understand is why if I install apk on smartphone the listView in drawer is not populated but if I run the application in avd everything is OK? – Dennis A. Boanini Dec 01 '15 at 15:06
  • I don't understand too. But, maybe the issue arises because of your thread. I'm not sure. Why don't you try using an asynctask to save your data? – Suncatcher Dec 01 '15 at 15:14
  • Look , your thread I think it's executed after you setup your adapter. Put your logic inside an asynctask, and override the method onPostExecute. There you can call your adapter. I bet your code this time will work. – Suncatcher Dec 01 '15 at 15:16
  • Threads not always execute the way we expect. Also you have set min priority. To ensure your adapter get called the first time, put your logic inside an asynctask. – Suncatcher Dec 01 '15 at 15:17
  • So I have to delete `Thread t = new Thread(new Runnable() { @Override public void run() { ... }` in `saveSections()` method ? – Dennis A. Boanini Dec 01 '15 at 15:24
  • Yes. Create an inner class that extends asynctask. Put the login inside your run method into the doInBackground method from asynctask. Then override the onPostExecuteMethod and there setup your adapter. – Suncatcher Dec 01 '15 at 15:29
  • Sorry but I'm not sure I understand what I have to put inside the `doInBackground()` method...I don't have any login.. – Dennis A. Boanini Dec 01 '15 at 15:35
0

I have modified my code, now I have this code for the onCreate() method

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        callWebservice();

//        setContentView(R.layout.activity_main);

        // Layout principale col drawer
        setContentView(R.layout.activity_main_drawer);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        leftArrow = (ImageView) findViewById(R.id.left_arrow);
        titolo = (TextView) findViewById(R.id.titolo_id);

        ActionBarDrawerToggle actionBarDrawerToggle =
                new ActionBarDrawerToggle(this, drawerLayout, toolbar,
                        R.string.navigation_drawer_open, R.string.navigation_drawer_close);

        drawerLayout.setDrawerListener(actionBarDrawerToggle);
        actionBarDrawerToggle.syncState();

        drawerListView = (ListView) findViewById(R.id.drawer_listView);
        setupDrawer();

    }

where the setupDrawer() method is

private void setupDrawer() {
        // SELECT * FROM Sections where Fk == 0;
        sectionsList = new RushSearch().whereEqual("Fk", 0).find(Sections.class);
        Log.d("ELEMENT", "" + sectionsList.size());
        drawerListViewAdapter = new DrawerListViewAdapter(sectionsList, getApplicationContext());

        // Adapter che si occupa di popolare il drawer
        drawerListView.setAdapter(drawerListViewAdapter);

        // Listner per il click su un elemento del drawer
        drawerListView.setOnItemClickListener(click);
    }

If I call this method from onCreate() or from callWebservice() after saveSections(response.getJSONArray("Sections")); in try-catch, I have the same problem.

Dennis A. Boanini
  • 477
  • 1
  • 5
  • 19
0

Ok Man. Try this:

private void callWebservice() {
    String tag_json_obj = "GetItem";
    String url = String.format("http://digitalbox.getsandbox.com/item");
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {

            try {
                new SaveData().execute(response.getJSONArray("Sections"));
            } catch (JSONException e) {
                e.printStackTrace();
            }

        }
    }, new Response.ErrorListener() {
        public void onErrorResponse(VolleyError error) {
            VolleyLog.d("Settings", "Error: " + error.getMessage());
        }
    }) {
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            HashMap<String, String> headers = new HashMap<String, String>();
            headers.put("Content-Type", "application/json");
            headers.put("Accept", "application/json");
            return headers;
        }
    };
    NetworkController.getInstance().addToRequestQueue(jsonObjectRequest, tag_json_obj);
}

Then add this inner class inside your activity:

private final class SaveData extends AsyncTask<JSONArray, Void, Void> {
    protected Void doInBackground(JSONArray... params) {
        int c = section.length();
        for (int i = 0; i < c; i++) {

            try {
                JSONObject obj = section.getJSONObject(i);

                Sections s = new RushSearch().whereEqual("ID", obj.getInt("ID")).findSingle(Sections.class);
                if (s == null) {
                    s = new Sections();
                    s.setID(obj.getInt("ID"));
                }

                if (!obj.isNull("Fk"))
                    s.setFk(obj.getInt("Fk"));

                s.setTitle(obj.getString("Title"));

                if (!obj.isNull("CategoryColor"))
                    s.setCategoryColor(obj.getString("CategoryColor"));

                s.setPos(obj.getInt("Pos"));
                s.setLanguageId(obj.getInt("LanguageId"));
                s.setUnavailableForSend(obj.getBoolean("UnavailableForSend"));

                s.save();

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

        Log.d("sections", "DB updated");
        return null;
    }

    public void onPostExecute(Void result) {
        sectionsList = new RushSearch().whereEqual("Fk", 0).find(Sections.class);
        Log.d("ELEMENTI",""+sectionsList.size());
        drawerListViewAdapter = new DrawerListViewAdapter(sectionsList, getApplicationContext());
    }
}

I hope this helps!

Dennis A. Boanini
  • 477
  • 1
  • 5
  • 19
Suncatcher
  • 60
  • 1
  • 7
  • I have error in `int c = params.length();` (Method call expected) and in `JSONObject obj = section.getJSONObject(i);` (cannot resolve method getJSONObject(int)) – Dennis A. Boanini Dec 01 '15 at 15:56
  • Man, you have to replace section with params[0] – Suncatcher Dec 01 '15 at 15:57
  • I'm your nightmare , but I have the same problem.. :( – Dennis A. Boanini Dec 01 '15 at 16:03
  • What does your logcat say? – Suncatcher Dec 01 '15 at 16:04
  • you had to correct this: int c = params[0].length(); ... params[0].getJSONObject(i); – Suncatcher Dec 01 '15 at 16:05
  • I have this: `new SaveData().execute(response.getJSONArray("Sections")); Log.d(numberOfElement_tag, "" + sectionsList.size());` after had installed apk on my smartphone I run the app, but logcat tells me `12-01 17:07:34.106 11709-11709/rawpepper.it.digitalbox D/Number of element in sectionList: 0`. All of this is very strange. – Dennis A. Boanini Dec 01 '15 at 16:08
  • Do you have any repo or some other way to see your project to help you? – Suncatcher Dec 01 '15 at 16:09
  • this, is the zip of my project: https://www.dropbox.com/s/hlf7ph24y73iyby/DigitalBox.zip?dl=0, try to run in AVD and install the apk in your smartphone – Dennis A. Boanini Dec 01 '15 at 16:20
  • Ok Man. It was my fault. Correct the signature of the onPostExecute method to this: public void onPostExecute(Void result) – Suncatcher Dec 01 '15 at 16:47
  • Oh Man, you're my savior. Thank you so much!. Now, the last courtesy: can you write a few word on where it was the problem in my code, and how it has been correct? so I learn my mistake and the correction eith some link for reference. PS: Please forgive me for my bad english – Dennis A. Boanini Dec 01 '15 at 17:08
  • Well, first of all you were calling your setadapter method after callservice(). That's a mistake because nothing assures you that already have the results of your request. Second, you were using a thread setted with min.priority. Remember that your smarthphones has a lot of threads running. So your app schedules your thread. It's better to use an asynctask, because the onPostExecute method assures you that you already have the results in your db. my email is jcieza90@gmail.com Add me for whatever doubts you have. – Suncatcher Dec 01 '15 at 17:16