Progress Bar not showing while waiting for Future to complete - android

I'm writing some code to discover the different ways of handling asynchronisity in Android, and I've already done AsyncTask, now I've had some luck with futures in the past, but this time it's bugging me a bit...
The code itself works fine, except for the fact that the (spinning) progressbar only shows up after the download operation has completed... despite the fact that I tell the code to display it before...
here's the code:
public void startDownload(final String url) {
bar.setVisibility(View.VISIBLE); // progress bar should appear here
ExecutorService pool = Executors.newCachedThreadPool();
Gson gson = new Gson();
Future<String> promise = pool.submit(new Callable<String>() {
#Override
public String call() throws Exception {
String response = "";
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while((s = buffer.readLine()) != null) response += s;
} catch (IOException ioe) {
ioe.printStackTrace();
}
return response;
}
});
while(promise.isDone() == false) {
// wait
}
bar.setVisibility(View.GONE); // and disappear here
try {
GitHubStatus status = gson.fromJson(promise.get(), GitHubStatus.class);
statusText.setText(status.getStatus());
bodyText.setText(status.getBody());
dateText.setText(status.getCreationDate());
} catch (ExecutionException ee) {
ee.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
// instead it briefly appears here, and then disappears again
}
For those who don't know; futures execute themselves, and thus you don't need to call a "run"or "start" method to start it
I've tried to put a Log.v("DEBUG: ", "Loading..."); in the loop that waits for it to finish, and it does print the message just fine, many times at that
I've tried without the loop, that doesn't work either, and I've even tried with a ProgressDialog that doesn't work either...
I understand that I can't update the UI thread while the UI thread is busy, but I only set the visibility before and after any of the work in the UI thread is being done, so what's wrong here? Why isn't it working?

Try following:
public void startDownload(final String url) {
bar.setVisibility(View.VISIBLE); // progress bar should appear here
ExecutorService pool = Executors.newCachedThreadPool();
Gson gson = new Gson();
Future<String> promise = pool.submit(new Callable<String>() {
#Override
public String call() throws Exception {
String response = "";
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while((s = buffer.readLine()) != null) response += s;
} catch (IOException ioe) {
ioe.printStackTrace();
}
runOnUiThread(new Runnable()
{
public void run()
{
bar.setVisibility(View.GONE); // and disappear here
try {
GitHubStatus status = gson.fromJson(promise.get(), GitHubStatus.class);
statusText.setText(status.getStatus());
bodyText.setText(status.getBody());
dateText.setText(status.getCreationDate());
} catch (ExecutionException ee) {
ee.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
});
return response;
}
});
}
Because of
while(promise.isDone() == false) {
// wait
}
You are blocking UIThread.

FutureTask can be used to run asynchronous tasks. However, it's get() method and isDone() method will block when called.
Thus, when you try to show a ProgressBar on the UI thread that has just been blocked by FutureTask, it won't show, till probably after the FutureTask is done.
In your case, your start the ProgressBar before initiating the FutureTask call, which is correct, but once FutureTask starts, running of the ProgressBar is blocked.
To solve this, you can run a FutureTask inside an AsyncTask:
Use the onPreExecute() method of the AsyncTask to show the ProgressBar`.
Use the onProgressUpdate() method of the AsyncTask to update the progress on the ProgressBar.
Use the onPostExecute() method of the AsyncTask to hide the ProgressBar; in a worst case scenario, you can call runOnUiThread() inside the FutureTask's Callable/Runnable, to hide the ProgressBar.

Related

how can i run Webservice code in Thread?

I wanna get some data from server with this code :
public class Webservice {
public static String readUrl(String url, ArrayList<NameValuePair> params) {
try {
HttpClient client = new DefaultHttpClient();
HttpPost method = new HttpPost(url);
if (params != null) {
method.setEntity(new UrlEncodedFormEntity(params));
}
HttpResponse response = client.execute(method);
InputStream inputStream = response.getEntity().getContent();
String result = convertInputStreamToString(inputStream);
return result;
}
catch (ClientProtocolException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static String convertInputStreamToString(InputStream inputStream) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder builder = new StringBuilder();
String line = "";
while ((line = reader.readLine()) != null) {
builder.append(line);
}
return builder.toString();
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
but there is some delay and pause in the application , so i wanna run this code in the Thread , but when i tried to do it , i got some error , for example i couldn't return the result or ...
Take a look at AsyncTask:
Network operations can involve unpredictable delays. To prevent this
from causing a poor user experience, always perform network operations
on a separate thread from the UI. The AsyncTask class provides one of
the simplest ways to fire off a new task from the UI thread. For more
discussion of this topic, see the blog post Multithreading For
Performance.
In the following snippet, the myClickHandler() method invokes new
DownloadWebpageTask().execute(stringUrl). The DownloadWebpageTask
class is a subclass of AsyncTask.
public class HttpExampleActivity extends Activity {
private static final String DEBUG_TAG = "HttpExample";
private EditText urlText;
private TextView textView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
urlText = (EditText) findViewById(R.id.myUrl);
textView = (TextView) findViewById(R.id.myText);
}
// When user clicks button, calls AsyncTask.
// Before attempting to fetch the URL, makes sure that there is a network connection.
public void myClickHandler(View view) {
// Gets the URL from the UI's text field.
String stringUrl = urlText.getText().toString();
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
new DownloadWebpageTask().execute(stringUrl);
} else {
textView.setText("No network connection available.");
}
}
// Uses AsyncTask to create a task away from the main UI thread. This task takes a
// URL string and uses it to create an HttpUrlConnection. Once the connection
// has been established, the AsyncTask downloads the contents of the webpage as
// an InputStream. Finally, the InputStream is converted into a string, which is
// displayed in the UI by the AsyncTask's onPostExecute method.
private class DownloadWebpageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
// params comes from the execute() call: params[0] is the url.
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(String result) {
textView.setText(result);
}
}
... }

How to implement long-running network uploads in Android not using AsyncTask and not using libraries

What is the native Android way to implement long running network operations (like uploading a bunch of photos) without having to use libraries like RoboSpice?
I've read numerous topics on stackoverflow suggesting that asynctask is not suitable for long running operations as it is closely tied to an activity's lifecycle, might lead to memory leaks and since android 3.2 there is only one thread for all asynctasks for an app. (not sure about this last one)
How do I replace my asynctask with something else?
Now, I've heard of handlers, executors, services and what not, but how exactly do I implement them in my code and which one to choose?
Here is an example of the asynctask I use
I have removed a lot of code, just so you can see the basic structure
public class UploadPhotosToServer extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... args) {
HashMap<String, String> params = new HashMap<String, String>();
try {
if(uploadImageToServer(id, path, params)) {
success = true;
} else {
success = false;
}
} catch (Exception e) {
e.printStackTrace();
success = false;
}
return success;
}
public boolean uploadImageToServer(int imageId, String imagePath, HashMap<String, String> params) throws Exception {
try {
JSONObject json = jsonParser.uploadImageToServer(imagePath, params);
JSONObject message = json.getJSONObject("message");
String serverResponse = message.getString("success");
if (serverResponse.contentEquals("true") {
return true;
} else {
return false;
}
} catch (JSONException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
and here is jsonParser.uploadImageToServer
public JSONObject uploadImageToServer(String imagePath, HashMap<String, String> params) throws Exception {
HttpResponse response;
MultipartEntityBuilder multipartEntity;
HttpPost postRequest;
HttpContext localContext;
Bitmap bitmap;
try {
// Set the http handlers
httpClient = new DefaultHttpClient();
localContext = new BasicHttpContext();
postRequest = new HttpPost(SERVER + "images");
// Send the package
multipartEntity = MultipartEntityBuilder.create();
multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.addPart("file", new FileBody(new File(imagePath)));
for (Map.Entry<String, String> entry : params.entrySet()) {
multipartEntity.addTextBody(entry.getKey(), entry.getValue());
}
postRequest.setEntity(multipartEntity.build());
// Get the response. we will deal with it in onPostExecute.
response = httpClient.execute(postRequest, localContext);
HttpEntity httpEntity = response.getEntity();
inputStream = httpEntity.getContent();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
json = sb.toString();
inputStream.close();
reader.close();
} catch (ClientProtocolException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
// Try parsing the string to a JSON object
try {
jsonObject = new JSONObject(json);
} catch (JSONException e) {
e.printStackTrace();
}
// Return JSON String
return jsonObject;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I think for a set of uploads I would consider implementing an IntentService. As explained at the link it will process a list of intents in a worker thread until that list is exhausted at which point the service will shutdown again.
The implementation of an IntentService is very simple. An example based on the example you give above;
public class ImageUploadIntentService extends IntentService {
public ImageUploadIntentService() {
super("ImageUploadIntentService");
}
#Override
public void onCreate() {
// Not a required implementation but you might want to setup any dependencies
// here that can be reused with each intent that the service is about to
// receive.
super.onCreate();
}
#Override
public void onHandleIntent(Intent intent) {
// Process your intent, this presumably will include data such as the local
// path of the image that you want to upload.
try {
uploadImageToServer(intent.getExtra("image_to_upload"), params);
} catch (Exception e) {
// Oh :( Consider updating any internal state here so we know the state
// of play for later
}
}
public JSONObject uploadImageToServer(String imagePath, HashMap<String, String> params) throws Exception {
// All of your upload code
}
}
Then to call the service it is as simple as;
Intent intent = new Intent(this, ImageUploadIntentService.class)
.putExtra("image_to_upload", mImagePath);
startService(intent);
This does leave us with the issue of indicating the progress of your upload queue. We can solve this by using a ResultReceiver. A result receiver is Parcelable so we can send it with the intent in order to listen out for results we might be interested in. You can handle the ResultReceiver with either an Activity and suitable piece of progress dialog, or if you want a persistent notification with a progress bar then you could use a Service to host the receiver.
It is a little more involved than using an AsyncTask, but it does give you a little more flexibility and is not as attached to the Activity lifecycle. Another gotcha with the IntentService it will still only make you one worker thread so image uploads could not happen concurrently. But I might consider breaking your Bitmap JPEG compression to it's own IntentService then you could have the compression happening on the next image in the queue while the first is being uploaded.

Android app background thread behavior

I have a basic app that uses a background thread to post values to our server. The code is below. When I run the code, in debugging or normally, the following line throws a NullException (though when debugging, the value of the backgroundThread variable is set). Every subsequent run through works fine. I'm new to Android development and am unsure what is causing this discrepancy. I've included the activity function and the server post function.
backgroundThread.start();
This line is what throws the NullException. Any ideas on what is causing the problem? Thanks for any help you can provide.
--UPDATE
#jonas452 & #Rudi
I changed the code to use asynctask and am struggling with the return value. postResult is always null, and breakpoints in the postTo function never run it seems. Probably a dumb error but I'm not sure what is amiss.
--UPDATE
I worked out the issue. The AsyncTask was setup correctly, but because it's asynchronous, postResult was not immediately available. I moved my check into the onPostExecute function of the AsyncTask and everything works fine.
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
try {
//retrieve scan result
IntentResult scanningResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (scanningResult != null) {
//we have a result
final String scanContent = scanningResult.getContents();
String scanFormat = scanningResult.getFormatName();
scan_format.setText("FORMAT: " + scanFormat);
scan_content.setText("CONTENT: " + scanContent);
error.setText(null);
output.setText(null);
neonetpost post = new neonetpost();
post.execute(scanContent);
/*
Thread backgroundThread = new Thread(new Runnable() {
#Override
public void run() {
postResult = postTo(scanContent);
}
});
backgroundThread.start();
*/
if(postResult.indexOf("ERROR: ")>-1)
error.setText(postResult);
else
output.setText(postResult);
}
else{
Toast toast = Toast.makeText(getApplicationContext(),
"No scan data received!", Toast.LENGTH_SHORT);
toast.show();
}
} catch (Exception e) {
// TODO Auto-generated catch block
error.setText("ERROR: " + e.getMessage());
}
}
public class neonetpost extends AsyncTask<String,String,String>
{
#Override
protected void onPreExecute() {
}
protected void onPostExecute(String result) {
}
protected String doInBackground(String... params) {
return postTo(params[0], params[1]);
}
public String postTo(String operation) {
return postTo(operation, "E:1");
}
public String postTo(String operation, String employee)
{
try {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://domain.com/page.php");
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("operation", operation));
nameValuePairs.add(new BasicNameValuePair("employee", employee));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
// According to the JAVA API, InputStream constructor do nothing.
//So we can't initialize InputStream although it is not an interface
InputStream inputStream = response.getEntity().getContent();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuilder stringBuilder = new StringBuilder();
String bufferedStrChunk = null;
while((bufferedStrChunk = bufferedReader.readLine()) != null){
stringBuilder.append(bufferedStrChunk);
}
postResult = stringBuilder.toString();
} catch (Exception e) {
// TODO Auto-generated catch block
postResult = "ERROR: " + e.getMessage();
}
return postResult;
}
}
Don't use Java Threads, use the AsyncTask class.
Here is a good tutorial:
http://www.compiletimeerror.com/2013/01/why-and-how-to-use-asynctask.html
the line that gives you NPE is if(postResult.indexOf("ERROR: ")>-1). You made the assumption that calling
backgroundThread.start();
made the UI Thread wait, till backgroundThread finished its execution and assign a value to postResult, but Thread are executed asynchronously. and backgroundThread.start();
makes the system spawn a new thread. When this is executed is up to the scheduler

BufferedReader with InputStreamReader fed with a finished HTTPResponse causes NetworkOnMainThreadException

I have some code that converts my HTTPResponse Object into a JSONObject, which works fine most of the time:
public static JSONObject httpResponseToJson(HttpResponse response) {
if (response != null) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(),
"UTF-8"));
String json = reader.readLine();
if (json != null) {
JSONObject jsonObject = new JSONObject(json);
printStatus(jsonObject);
return jsonObject;
}
} catch (JSONException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
However, sometimes it throws a the Android NetworkOnMainThread exception. I cannot figure out why, because the response is already finished and there should not be any more network IO involved in that call. For test reasons, if I allow NetworkOnMainThread, this method works fine all the time.
Note that all the HTTPResponse is fetched with an AsyncTask and this is working fine.
I am very interested in any suggestions.
Reading the response from a HttpResponse object also involves a Network Operation. Simply process that also in the doInBackground() method and modify your AsyncTask to pass to the onPostExecute() the real result once processed.
its mean you are performing some network operation on main thread.The point here is Unless the stream is not closed, you are still performing network operation so move that part into doInBackGround() too.

setText from a parsed JSON object with AsyncTask [duplicate]

This question already has answers here:
AsyncTask Android example
(21 answers)
Closed 9 years ago.
Im making an android program that parses JSON texts from a source code of a webpage in the internet. It is working in android 2.2 but I need it now to be on android 3.0, which needs to be on the AsyncTask. I have a background about AsyncTask but I'm so confused where to put this and that. Thanks in advance everyone :)
Here is my method in the MainActivity class:
private void jsonStuffs() {
//JSON PARSER & HOME PAGE TEXTVIEWS
client = new DefaultHttpClient();
GetMethodEx test = new GetMethodEx();
String returned;
try {
returned = test.getInternetData();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try{
String jsonStr = test.getInternetData(); //go to GetMethodEx
JSONObject obj = new JSONObject(jsonStr);
//////////////////////find temperature in the JSON in the webpage
String temperature = obj.getString("temperature");
TextView tvTemp = (TextView)findViewById(R.id.textView);
tvTemp.setText(temperature);
}
//catch (JSONException e) {
// e.printStackTrace();
//}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The GetMethodEx class is this (this will find the link of the webpage then convert it's source code to text format):
public class GetMethodEx extends Activity {
public String getInternetData() throws Exception{
BufferedReader in = null;
String data = null;
//
try{
HttpClient client = new DefaultHttpClient();
URI website = new URI("http://nhjkv.comuf.com/json_only.php");
HttpGet request = new HttpGet();
request.setURI(website);
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String l = "";
String nl = System.getProperty("line.separator");
while ((l = in.readLine()) !=null){
sb.append(l + nl);
}
in.close();
data = sb.toString();
return data;
}finally {
if (in !=null){
try{
in.close();
return data;
} catch (Exception e){
e.printStackTrace();
}
}
}
}
}
You can do something like this (this code is just for illustration, change it as needed)
class MyAsyncTask extends AsyncTask<String, Void, JSONObject> {
protected void onPreExecute() {
// You can set your activity to show busy indicator
//setProgressBarIndeterminateVisibility(true);
}
protected JSONObject doInBackground(String... args) {
return jsonStuffs();
}
protected void onPostExecute(final JSONObject jsonObj) {
String temperature = jsonObj.getString("temperature");
TextView tvTemp = (TextView)findViewById(R.id.textView);
tvTemp.setText(temperature);
// Stop busy indicator
//setProgressBarIndeterminateVisibility(false);
}
To call this task use new MyAsyncTask().execute(); (you can pass String parameters to execute if needed)
You can change your jsonStuffs() to return JSONObject
e.g.
private JSONObject jsonStuffs() {
// ...
String jsonStr = test.getInternetData(); //go to GetMethodEx
return new JSONObject(jsonStr);
// ...
}
It is working in android 2.2 but I need it now to be on android 3.0,
which needs to be on the AsyncTask.
=> Yes it gives NetworkOnMainThreadException in 3.0 if you make web call without implementing inside Thread such as AsyncTask.
I have a background about AsyncTask but I'm so confused where to put
this and that.
=> Simply include web call logic inside doInBackground() method of the AsyncTask, in your case call getInternetData() inside doInBackground().
FYI, you can't update UI straight way while doing long running task inside the doInBackground(). Yes if you want to update UI then do follow any of the below:
Update UI from the onPostExecute() method.
or implement runOnUiThread() inside the doInBackround()

Categories

Resources