4

I'm writing an Android application which will occasionally need to download a json string of around 1MB and containing around 1000 elements, and parse each of these into an SQLite database, which I use to populate a ListActivity.

Even though the downloading and parsing isn't something that needs to be done on every interaction with the app (only on first run or when the user chooses to refresh the data), I'm still concerned that the parsing part is taking too long, at around two to three minutes - it seems like an eternity in phone app terms!

I am using this code... :-

            public class CustomerAsyncTask extends AsyncTask<String, Integer, String> {
            private Context context;
            private String url_string;
            private String usedMethod;
            private String identifier;
            List<NameValuePair> parameter;
            private boolean runInBackground;
            AsynTaskListener listener;
            private Bitmap bm = null;

            public ProgressDialog pDialog;
            public String entityUtil;
            int index = 0;
            public static int retry = 0;

            private String jsonString = "";

            private String DialogString = "";

            // use for AsyncTask web services-----------------
            public CustomerAsyncTask(Context ctx, String url, String usedMethod,
                    String identifier, boolean runInBackground, String DialogString,
                    List<NameValuePair> parameter, AsynTaskListener callack) {
                this.context = ctx;
                this.url_string = url;
                this.usedMethod = usedMethod;
                this.identifier = identifier;
                this.parameter = parameter;
                this.runInBackground = runInBackground;
                this.listener = callack;
                this.DialogString = DialogString;
            }

            public CustomerAsyncTask(Context ctx, String url, String usedMethod,
                    String identifier, boolean runInBackground,
                    List<NameValuePair> parameter, AsynTaskListener callack, Bitmap bm) {
                this.context = ctx;
                this.url_string = url;
                this.usedMethod = usedMethod;
                this.identifier = identifier;
                this.parameter = parameter;
                this.runInBackground = runInBackground;
                this.listener = callack;
                this.bm = bm;

            }

            @Override
            protected void onPreExecute() {
                // TODO Auto-generated method stub
                super.onPreExecute();
                if (runInBackground)
                    initProgressDialog(DialogString);
            }

            @Override
            protected void onProgressUpdate(Integer... values) {
                // TODO Auto-generated method stub
                super.onProgressUpdate(values);
            }

            @SuppressWarnings("deprecation")
            @Override
            protected String doInBackground(String... params) {
                HttpParams httpParameters = new BasicHttpParams();
                int timeoutConnection = 10000; // mili second
                HttpConnectionParams.setConnectionTimeout(httpParameters,
                        timeoutConnection);
                int timeoutSocket = 10000;
                HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
                DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
                try {
                    HttpResponse response = null;
                    if (usedMethod.equals(GlobalConst.POST)) {
                        HttpPost httppost = new HttpPost(this.url_string);
                        httppost.setHeader("Content-Type",
                                "application/x-www-form-urlencoded");
                        // Customer Login MObile
                        if (identifier.equals("Customer_Login")) {
                            if (params.length > 0) {
                                parameter = new ArrayList<NameValuePair>();
                                parameter.add(new BasicNameValuePair("cus_mob",
                                        params[0]));
                            }
                            httppost.setEntity(new UrlEncodedFormEntity(parameter));

                            // Customer Verify Code
                        } else if (identifier.equals("Customer_mob_verify")) {
                            if (params.length > 0) {
                                parameter = new ArrayList<NameValuePair>();
                                parameter.add(new BasicNameValuePair("cus_verify",
                                        params[0]));
                                parameter.add(new BasicNameValuePair("cus_mobile",
                                        params[1]));
                            }
                            httppost.setEntity(new UrlEncodedFormEntity(parameter));
                        } else if (identifier.equals("Dashboard")) {
                            if (params.length > 0) {
                                parameter = new ArrayList<NameValuePair>();
                                parameter.add(new BasicNameValuePair("cus_id",
                                        params[0]));
                            }
                            httppost.setEntity(new UrlEncodedFormEntity(parameter));
                        }
                        response = (HttpResponse) httpClient.execute(httppost);

                    } else if (usedMethod.equals(GlobalConst.GET)) {

                        HttpGet httpput = new HttpGet(this.url_string);
                        httpput.setHeader("Content-Type",
                                "application/x-www-form-urlencoded");
                        response = (HttpResponse) httpClient.execute(httpput);
                    }

                    // Buffer Reader------------------------
                    InputStream inputStream = null;
                    String result = null;
                    try {
                        HttpEntity entity1 = response.getEntity();
                        inputStream = entity1.getContent();
                        BufferedReader reader = new BufferedReader(
                                new InputStreamReader(inputStream, "UTF-8"), 8);
                        StringBuilder sb = new StringBuilder();
                        String line = null;
                        while ((line = reader.readLine()) != null) {
                            sb.append(line + "\n");
                        }
                        result = sb.toString();
                    } catch (Exception e) {
                    } finally {
                        try {
                            if (inputStream != null)
                                inputStream.close();
                        } catch (Exception squish) {
                        }
                    }
                    jsonString = result;
                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                    return AsyncResultConst.CONNEERROR;
                } catch (IOException e) {
                    e.printStackTrace();
                    return AsyncResultConst.CONNEERROR;
                } catch (Exception e1) {
                    e1.printStackTrace();
                    return AsyncResultConst.EXCEPTION;
                } finally {
                    httpClient.getConnectionManager().shutdown();
                }
                return AsyncResultConst.SUCCESS;
            }

            @Override
            protected void onPostExecute(String result) {
                // TODO Auto-generated method stub
                if (runInBackground)
                    pDialog.dismiss();
                if (result.equals(AsyncResultConst.SUCCESS)) {
                    listener.onRecieveResult(identifier, jsonString);
                } else if (result.equals(AsyncResultConst.PARSINGERROR)) {
                    // showAlertMessage(context, "Error", "Parsing Error", null);
                    listener.onRecieveException(identifier, result);
                } else {
                    if (retry < 0) {
                        retry++;
                        new CustomerAsyncTask(context, url_string, usedMethod,
                                identifier, runInBackground, DialogString, parameter,
                                listener).execute("");
                    } else {
                        // showAlertMessage(context, "Error", "Connection Error", null);
                        listener.onRecieveException(identifier, result);
                    }
                }
                super.onPostExecute(result);
            }

            private void initProgressDialog(String loadingText) {
                pDialog = new ProgressDialog(this.context);
                pDialog.setMessage(loadingText);
                pDialog.setCancelable(false);
                pDialog.show();
            }
        }
Michele La Ferla
  • 6,775
  • 11
  • 53
  • 79
Rahul
  • 374
  • 4
  • 14
  • show us your solution maybe. 3mins sounds like impossible – Marcin Mikołajczyk Sep 01 '14 at 13:03
  • If you're controlling the data, you might want to consider downloading in parts, so you can gradually populate your database. – stealthjong Sep 01 '14 at 13:04
  • Use Traceview, log statements, etc. to determine *exactly* where your problem is. Also note that your code is not doing any parsing, so if you have already determined that parsing is your problem, then this code will not illustrate that. And bear in mind that HttpClient is not recommended by Google. – CommonsWare Sep 01 '14 at 13:29
  • 1
    Have you measured server response get time and json parse time? Any parsing delays will be insignificant in comparison to time needed to retrieve data from server. What time it takes to get the response from elsewhere (e.g. in Fiddler) If server processes request slowly, it cannot be helped. Does webservice accept OData params to split data in parts? There're way too many questions to answer – Alexander Zhak Sep 01 '14 at 13:39

5 Answers5

2

Don't use Async-task in such case, use native java thread here.

 new Thread(new Runnable() {
        public void run() {

             // Do your work .....

        }
    }).start();  

When need to update UI. Yes! Android won't allow you to do that. so... solution is: USE Handler for that :)

 Handler handler = new Handler(); 

 handler.post(new Runnable() {
      @Override
      public void run() {

           // Do Update your UI     

       }    
 });

Use AsyncTask for:

  1. Simple network operations which do not require downloading a lot of
  2. data Disk-bound tasks that might take more than a few milliseconds

Use Java threads for:

  1. Network operations which involve moderate to large amounts of data (either uploading or downloading)
  2. High-CPU tasks which need to be run in the background
  3. Any task where you want to control the CPU usage relative to the GUI thread
Mohsin
  • 1,586
  • 1
  • 22
  • 44
  • "these technique are quiet slow as compare to simple java thread" -- please edit your question to provide proof of this claim. – CommonsWare Sep 01 '14 at 13:26
  • bro! you can check this; already discussed many places http://stackoverflow.com/a/18480297/3819810... There are some ref links as well, you can check in detail :) – Mohsin Sep 01 '14 at 13:32
  • 1
    That answer does not say that `AsyncTask` is slow compared "to simple java thread". Please edit your question to provide proof of your claim that `AsyncTask` (which mostly is a "simple java thread") is slower than a "simple java thread". – CommonsWare Sep 01 '14 at 13:34
  • ok got the point. yes! saying slow isn't a good. edit done :) – Mohsin Sep 01 '14 at 13:39
0

Try to use Jackson Library to manage your JSON. It is really efficient. You can find it here : http://mvnrepository.com/artifact/org.codehaus.jackson/jackson-jaxrs

I am using it for a 400KB file is less than 1 second.

If you want a tuto this one looks good http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/

Eliott Roynette
  • 716
  • 8
  • 21
0

You could use Google's GSON as well.

esoxjem
  • 153
  • 1
  • 9
0

This is how is read JSON into my listview in my app. The result is processed to my app in an average of 3 seconds on Wi-Fi and 5 seconds on 3G:

public class CoreTeamFragment extends ListFragment { ArrayList> membersList; private String url_all_leaders = //URL goes here private ProgressDialog pDialog;

JSONParser jParser = new JSONParser();

// JSON Node names
private static final String CONNECTION_STATUS = "success";
private static final String TABLE_TEAM = "CoreTeam";
private static final String pid = "pid";
private static final String COL_NAME = "CoreTeam_Name";
private static final String COL_DESC = "CoreTeam_Desc";
private static final String COL_PIC = "CoreTeam_Picture";

JSONArray CoreTeam = null;

public static final String ARG_SECTION_NUMBER = "section_number";

public CoreTeamFragment() {
}

public void onStart() {
    super.onStart();

    membersList = new ArrayList<HashMap<String, String>>();
    new LoadAllMembers().execute();

    // selecting single ListView item
    ListView lv = getListView();

    // Lauching the Event details screen on selecting a single event
    lv.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {
            // getting values from selected ListItem
            String ID = ((TextView) view.findViewById(R.id.leader_id))
                    .getText().toString();

            Intent intent = new Intent(view.getContext(),
                    CoreTeamDetails.class);
            intent.putExtra(pid, ID);
            view.getContext().startActivity(intent);
        }
    });
}

public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_coreteam,
            container, false);

    return rootView;
}

class LoadAllMembers extends AsyncTask<String, String, String> {

    /**
     * Before starting background thread Show Progress Dialog
     * */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(getActivity());
        pDialog.setMessage("Just a moment...");
        pDialog.setIndeterminate(true);
        pDialog.setCancelable(true);
        pDialog.show();
    }

    protected String doInBackground(String... args) {
        // Building Parameters
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        // getting JSON string from URL
        JSONObject json = jParser.makeHttpRequest(url_all_leaders,
                "GET", params);

        try {
            // Checking for SUCCESS TAG
            int success = json.getInt(CONNECTION_STATUS);

            if (success == 1) {
                // products found
                // Getting Array of Products
                CoreTeam = json.getJSONArray(TABLE_TEAM);
                // looping through All Contacts
                for (int i = 0; i < CoreTeam.length(); i++) {
                    JSONObject ct = CoreTeam.getJSONObject(i);

                    // Storing each json item in variable
                    String id = ct.getString(pid);
                    String name = ct.getString(COL_NAME);
                    String desc = ct.getString(COL_DESC);
                    String pic = ct.getString(COL_PIC);

                    // creating new HashMap
                    HashMap<String, String> map = new HashMap<String, String>();

                    // adding each child node to HashMap key => value
                    map.put(pid, id);
                    map.put(COL_NAME, name);
                    map.put(COL_DESC, desc);
                    map.put(COL_PIC, pic);

                    // adding HashList to ArrayList
                    membersList.add(map);

                }
            } else {
                // Options are not available or server is down.
                // Dismiss the loading dialog and display an alert
                // onPostExecute
                pDialog.dismiss();
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return null;
    }

    protected void onPostExecute(String file_url) {
        // dismiss the dialog after getting all products
        pDialog.dismiss();
        // updating UI from Background Thread
        getActivity().runOnUiThread(new Runnable() {
            public void run() {
                ListAdapter adapter = new SimpleAdapter(
                        getActivity(),
                        membersList,
                        R.layout.coreteam_item,
                        new String[] { pid, COL_NAME, COL_DESC, COL_PIC },
                        new int[] { R.id.leader_id, R.id.leaderName,
                                R.id.photo });
                setListAdapter(adapter);
            }
        });
    }
}

}

Michele La Ferla
  • 6,775
  • 11
  • 53
  • 79
0

Use Volley or Retrofit lib.

Those lib are increasing the speed.

Volley:

JsonObjectRequest channels = new JsonObjectRequest(Method.POST,
                Constants.getaccountstatement + Constants.key, statement_object,
                new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject arg0) { 
}, new Response.ErrorListener()
        {
            @Override
            public void onErrorResponse(VolleyError e) {
                Toast.makeText(context, "Error", Toast.LENGTH_SHORT).show();
}