0

I am creating an android app that depends on data that the app gets from the database. To get this data I have the following class (this class gets data from the database in JSON, translates it and returns it):

public class Json {
    public String jsonResult;

    private Activity activity;
    private String url = "http://json.example.org/json.php";
    private String db, query;

    public Json(Activity activity) {
            this.activity = activity;
        }

    public String accessWebService(String db, String query) {
        JsonReadTask task = new JsonReadTask();

        this.db = db;
        this.query = query;

        task.execute(new String[] { url });

        try {
            task.get();
        } catch (InterruptedException e) {
            Toast.makeText(activity.getApplicationContext(), "FATAL ERROR: The thread got interrupted",
                    Toast.LENGTH_LONG).show();
        } catch (ExecutionException e) {
            Toast.makeText(activity.getApplicationContext(), "FATAL ERROR: The thread wasn't able to execute",
                    Toast.LENGTH_LONG).show();
        }
        return jsonResult;
    }

    // Async Task to access the web
    private class JsonReadTask extends AsyncTask<String, Void, String> {

        private final ProgressDialog dialog = new ProgressDialog(activity);

        protected String doInBackground(String... params) {
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost(params[0]);
            try {
                // add post data
                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
                nameValuePairs.add(new BasicNameValuePair("db", db));
                nameValuePairs.add(new BasicNameValuePair("query", query));
                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                HttpResponse response = httpclient.execute(httppost);
                jsonResult = inputStreamToString(response.getEntity().getContent()).toString();
                if (jsonResult.isEmpty()) {
                    Toast.makeText(activity.getApplicationContext(),
                            "Error, connection is up but didn't receive data. That's strange...", Toast.LENGTH_LONG)
                            .show();
                    this.cancel(true);
                }

            } catch (ClientProtocolException e) {
                // Toast.makeText(activity.getApplicationContext(),
                // "Error, Client Protocol Exception in JSON task",
                // Toast.LENGTH_LONG).show();
                Log.i("Json", "Error, Client Protocol Exception in JSON task");
                this.cancel(true);
            } catch (IOException e) {
                // Toast.makeText(activity.getApplicationContext(),
                // "Error, Please check your internet connection",
                // Toast.LENGTH_LONG).show();
                Log.i("Json", "Error, Please check your internet connection");
                this.cancel(true);
            }
            return null;
        }

        private StringBuilder inputStreamToString(InputStream is) {
            String rLine = "";
            StringBuilder answer = new StringBuilder();
            BufferedReader rd = new BufferedReader(new InputStreamReader(is));

            try {
                while ((rLine = rd.readLine()) != null) {
                    answer.append(rLine);
                }
            } catch (IOException e) {
                Toast.makeText(activity.getApplicationContext(), "Error..." + e.toString(), Toast.LENGTH_LONG).show();
            }
            return answer;
        }
    }// end async task
}

I noticed that my app freezes while accessing the database. After some googling, I found out it was the .get() method in the accessWebService() method caused this. I tried to implement a progressDialog like so (I also deleted the .get() method):

private final ProgressDialog dialog = new ProgressDialog(activity);

protected void onPreExecute() {
    super.onPreExecute();
    this.dialog.setMessage("Loading...");
    this.dialog.setCancelable(false);
    this.dialog.show();
}

protected void onPostExecute(String result) {
    if (this.dialog.isShowing()) {
        this.dialog.dismiss();
    }
}

but the dialog didn't show up and I got NullPointerException because the app only works when there is data:

result = json.accessWebService(db, query);

(maybe an important thing to mention: I also use this method in for loops)

So now my question is: How can I change my app so that I get a ProgressDialog while accessing the database and without getting NullPointerException? I fear that I have to rearchitect my whole app and if I have to do this, how do I do this? I hope you guys understand my question and have a fix for this because I really need help. Thanks in advance.

P.S. Sorry if my English is not that good, I'm not a native speaker.

Zain Aftab
  • 703
  • 7
  • 21
Quitlox
  • 46
  • 5

3 Answers3

3

... I found out it was the .get() method in the accessWebService() method caused this. I tried to implement a progressDialog...

That is right. get() is a blocking call and simply adding a ProgressDialog won't fix it. You need to remove .get() and that will probably fix the issue of your ProgressDialog not showing.

An AsyncTask must be executed on the main Thread so make sure you are doing that.

Another problem you have is Toast.LENGTH_LONG).show(); runs on the UI and you have it in doInBackground() which cannot happen. You need to send the result to onPostExecute() and you can display your Toast there if need. This could also be done in onProgressUpdate().

codeMagic
  • 44,549
  • 13
  • 77
  • 93
  • yes sorry i didn't mentioned it in my question but i did remove the .get() method. And about the second thing (Toast), unfortunatly that didn't help either. (this wasn't the problem because the toasts only got made when there was an error) – Quitlox Nov 06 '13 at 13:50
  • If you need to get a response and do something when the task has finished, you can [see this SO answer](http://stackoverflow.com/questions/18517400/inner-class-can-access-but-not-update-values-asynctask/18517648#18517648) about using an `interface` – codeMagic Nov 06 '13 at 13:54
  • that could be usefull but i have one problem. I use the json.accessWebService(db, query); multiple times in one class and everytime it gets different data. I also use the method in forloops. With that in mind, how am i going to use that kind of mechanism? – Quitlox Nov 06 '13 at 14:21
  • @Quitlox I would have to see what you are doing to know for sure but maybe that won't work for you. Its good if you need something to happen when your task finishes instead of using `.get()` because it won't block the `UI`. You simply add the `interface` to your `Activity` then call it in `onPostExecute()` so it can return the data or some response so the `Activity` can take appropriate action, if needed. – codeMagic Nov 06 '13 at 14:38
  • well actualy, maybe I can use it. I have to change a lot in my code but I maybe it would work. Thanks for the effort. – Quitlox Nov 06 '13 at 14:57
  • Does that fix your problems or are you still getting `null`? If so, where at and where is it called from? – codeMagic Nov 06 '13 at 15:02
0

This null pointer exception happens because of result value was null. put the condition before

if(result != null ) {

   // CODE FOR PARSING 
} else {

   return;
}
RajaReddy PolamReddy
  • 22,428
  • 19
  • 115
  • 166
  • yes but if i do that, the app cant continue because it has no data. – Quitlox Nov 06 '13 at 13:37
  • it will continue if u use return in else block, look at my updated answer now. – RajaReddy PolamReddy Nov 06 '13 at 13:39
  • tnx for answering and indeed, if i do that i see the loading dialog and the app doesn't crash. but since it only checks the result once (when its empty, it checks it too early because the AsyncTask isn't ready at that moment), the result is null. So the app can't do anything because it needs the data. Any suggestions? – Quitlox Nov 06 '13 at 14:47
0

You can start showing progress bar before asyncTask is started and finish showing when asyncTask is finished.

Pass handler to asyncTask and sendMessage onPostExecute method. Then handle message on UI thread and hide progress bar

For example there is handler field in UI (mainActivity). There you should handle hiding progress bar:

public Handler refreshChannelsHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case EPGManager.ERROR_MESSAGE:
                //do some stuff
                break;
            case EPGManager.SUCCESS_MESSAGE:
                //do some stuff
                break;
        }
        super.handleMessage(msg);
    }
};

Then you can call asyncTask with your handler

epgManager.loadChannels(refreshChannelsHandler);

AsyncTask is inside the method so it looks like this:

public void loadChannels(Handler handler) {
    AsyncTask task = new AsyncTask() {
        @Override
        protected Object doInBackground(Object[] params) {
            try {
                //do AsyncTask Job
            } catch (Exception e) {
                return new LoadingResult((Handler) params[0], false);
            }
            return new LoadingResult((Handler) params[0], false);
        }

        @Override
        protected void onPostExecute(Object o) {
            super.onPostExecute(o);
            LoadingResult loadingResult = ((LoadingResult)o);
            sendMessageToHandler(loadingResult.handler, loadingResult.isSuccess);              
        }
    };
    task.execute(handler);
}

Here is method:

private void sendMessageToHandler(Handler handler, boolean isSuccess) {
    handler.sendEmptyMessage(isSuccess ? SUCCESS_MESSAGE : ERROR_MESSAGE);
}

And finally inner class

private class LoadingResult {
    private Handler handler;
    private boolean isSuccess;

    public LoadingResult(Handler handler, boolean isSuccess) {

        this.handler = handler;
        this.isSuccess = isSuccess;
    }

    public Handler getHandler() {
        return handler;
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

    public boolean isSuccess() {
        return isSuccess;
    }

    public void setSuccess(boolean isSuccess) {
        this.isSuccess = isSuccess;
    }
}

Ow, and don't forget constants

public static final int SUCCESS_MESSAGE = 1;
public static final int ERROR_MESSAGE = -1;

Hope it helps :)

Ragaisis
  • 2,700
  • 1
  • 26
  • 41
  • What is the point of using a `Handler` here? `AsyncTask` already has methods that run on the `UI` (all but `doInBackground()`) – codeMagic Nov 06 '13 at 13:55
  • Well in my case there is project structure and UI is in different package. All asyncTasks are in Engine package that has no access to UI package. Only UI package can call Engine package methods, so passing a Handler helps me to get answer of finished AsyncTask in clean and legal way and still have my project structure :) – Ragaisis Nov 06 '13 at 14:00