Android AsyncTask sending message to a Handler on a dead thread - java

I am trying to make a program that should work something like a catalog - I have a JSON array that I loop through and parse the JSON objects into a string containing the image link, and two strings for descriptions for each object. Now, when downloading the images from the internet with the link, I run into a problem at the same image every time, image number 93. I checked the link, and it's working, just the same as the others.
This happens:
W/MessageQueue: Handler (android.os.Handler) {f95f6fe} sending message to a Handler on a dead thread
java.lang.IllegalStateException: Handler (android.os.Handler) {f95f6fe} sending message to a Handler on a dead thread
at android.os.MessageQueue.enqueueMessage(MessageQueue.java:543)
at android.os.Handler.enqueueMessage(Handler.java:643)
at android.os.Handler.sendMessageAtTime(Handler.java:612)
at android.os.Handler.sendMessageDelayed(Handler.java:582)
at android.os.Handler.post(Handler.java:338)
at android.os.ResultReceiver$MyResultReceiver.send(ResultReceiver.java:57)
at com.android.internal.os.IResultReceiver$Stub.onTransact(IResultReceiver.java:58)
at android.os.Binder.execTransact(Binder.java:565)
This is how my AsyncTask looks:
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
This is how I call the AsyncTask:
new DownloadImageTask(imgProductPicture).execute(pictureLink);
layoutTest.addView(NewImgView);
In my code I make sure that no more than 5 of these are called at a time, and they all load without issue until reaching the object indexed 92. The object itself is fine, but the app shuts off at this point always. Does anyone have an idea why? I've tried downloading less images at a time (one by one) and it still fails at the same point. I'd appreciate any help.

AsyncTask uses handler of the main thread, to callback onPostExecute(). If the main thread is dead when to callback, system throws the exception. To avoid this, you have to keep the main thread alive until all the work completes.

I solved the problem by creating a new handler/runnable every time I called the DownloadImageTask. Thanks to all who have tried to help.

Related

Should JSON be downloaded in background?

After user press the button it fires up weather function. But it doesn't log any JSON data or any error. Should it be done in background? I've used gson libary to download JSON.
Edit: I edited my code but user must enter a city which is pasted to the link. So is it possible to run in background process when the button is tapped?
public class MainActivity extends AppCompatActivity {
public class Download extends AsyncTask<String,Void,String>{
#Override
protected String doInBackground(String... strings) {
try {
URL url = new URL("api.openweathermap.org/data/2.5/weather?q="+strings[0]+"&APPID=****");
URLConnection request = url.openConnection();
request.connect();
JsonParser jp=new JsonParser();
JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent()));
JsonObject rootobj = root.getAsJsonObject();
String weather = rootobj.getAsString();
Log.i("weather:",weather);
}
catch (Exception e){
e.printStackTrace();;
}
return null;
}
}
public void weather(View view){
TextView textView=(TextView) findViewById(R.id.editText);
String city=textView.getText().toString();
Download download=new Download();
download.execute(city);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
All io operation should be executed in background , because all this operations are time consuming . which means you will block your main thread if you donot execute these codes in background and may cause Android Not Respond exception. IO operation in ui thread generally lead to bad user experience . so i strongly advice you do this in background.
You should definitely load your data in the background. The Main Thread i.e. the UI Thread is the thread that renders the UI components so no heavy operation should be done there. If heavy operation is done in the UI Thread, it will freeze the UI.
You should look at the AsyncTask class to perform your loading in the background.
Here is some good tutorials:
https://alvinalexander.com/android/asynctask-examples-parameters-callbacks-executing-canceling
https://www.journaldev.com/9708/android-asynctask-example-tutorial
https://www.tutorialspoint.com/android-asynctask-example-and-explanation

Fail whe i try to connect my app to webServices

Actully i working in a app, but i have problems to connect my Web services, i have this code:
try{
HttpServices post = new HttpServices ("http://sotem.com.mx/WebServices/controller.php");
post.add("funcion", "test");
System.out.println("Si lo mande///////////////////Jhgfdsa");
String respuesta = post.getRespueta();
System.out.println(respuesta);
Toast.makeText(getApplicationContext(),"Cool: "+respuesta, Toast.LENGTH_SHORT).show();
}catch (Exception ex) {
Toast.makeText(getApplicationContext(),"error: "+ex.toString(), Toast.LENGTH_SHORT).show();
}
but i can make connection, i try to make other thinks, but i can make the thread, i'am new in this part, the app launcher this error:
android os network on main thread exception
It is not okay to do the Network Operation on main thread.. You can use AsyncTask to perform such operations and handle the result in onPostExecute method.
class YourNetworkingTasks extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
try{
HttpServices post = new HttpServices ("http://sotem.com.mx/WebServices/controller.php");
post.add("funcion", "test");
String respuesta = post.getRespueta();
Log.d("Output", respuesta);
// DON'T DO ANY UI CHANGES LIKE TOAST FROM BACKGROUND THREAD.. Toast.makeText(getApplicationContext(),"Cool: "+respuesta, Toast.LENGTH_SHORT).show();
}catch (Exception ex) {
// DON'T DO ANY UI CHANGES LIKE TOAST FROM BACKGROUND THREAD.. Toast.makeText(getApplicationContext(),"error: "+ex.toString(), Toast.LENGTH_SHORT).show();
}
return null;
}
protected void onPostExecute(RSSFeed feed) {
// TODO: YOU CAN MAKE U.I. Changes Like Display text in TextView, TOAST HERE.
// TODO: do something with the result
}
}
And write new YourNetworkingTasks().execute(); to run that code in background thread.
Please also not that since you are using http and not https you may get Network Security Exception and may not get any output due to recent security change in android.

Android, Glide Image Loading Library: NullPointerException, ProviderInfo

Just getting into the Glide image loading library for Android. Currently working with some code from here:
https://github.com/bumptech/glide/issues/459
My full project is here is you want to look at it:
https://github.com/mhurwicz/glide02
I'm getting the following exception when I run the app in the emulator in Android Studio:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
This is the key statement in MainActivity:
new ShareTask(this).execute("http://thelink");
(thelink is actually goo.gl/gEgYUd -- couldn't leave that in above because stackoverflow doesn't allow URL shorteners. )
Here is my code for the ShareTask class
class ShareTask extends AsyncTask<String, Void, File> {
private final Context context;
public ShareTask(Context context) {
this.context = context;
}
#Override protected File doInBackground(String... params) {
String url = params[0]; // should be easy to extend to share multiple images at once
try {
return Glide
.with(context)
.load(url)
.downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get() // needs to be called on background thread
;
} catch (Exception ex) {
Log.w("SHARE", "Sharing " + url + " failed", ex);
return null;
}
}
#Override protected void onPostExecute(File result) {
if (result == null) { return; }
Uri uri = FileProvider.getUriForFile(context, context.getPackageName(), result);
share(uri); // startActivity probably needs UI thread
}
private void share(Uri result) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_SUBJECT, "Shared image");
intent.putExtra(Intent.EXTRA_TEXT, "Look what I found!");
intent.putExtra(Intent.EXTRA_STREAM, result);
context.startActivity(Intent.createChooser(intent, "Share image"));
}
}
Using debug, it seems I may be running into trouble at the get() statement. For one thing, the width and the height are very large negative numbers. (See the code highlighted in green below.) Then the get() statement returns null. (See the code highlighted in red below.)
Thanks in advance for any help you can provide!
The NPE is coming from FileProvider.getUriForFile because you're passing in the wrong authority. You declared android:authorities="com.example.fileprovider" in the manifest, but you're using the package name at the call. This fails to resolve the info in FileProvider.parsePathStrategy. Match those two strings up and you'll be good to go.
The easiest fix is to use android:authorities="${applicationId}", this leads to 0 hardcoded strings, so you can keep using context.getPackageName().
Regarding your concerns during debug:
Target.SIZE_ORIGINAL is declared to be MIN_VALUE, hence the large number
it's not returning null, IDEA is just confused about where it is in the method, that return null; shouldn't be executed if it fails in the FileProvider code.
doGet(null): null is the timeout here, it's guarded properly in code
I've run the app and weirdly I got a log line saying
W/SHARE: Sharing http://... failed
but not a stack trace, which is weird, because ex cannot be null in a catch!

Image retrieval is slow

I'm grabbing thumbnail images from a web server in an AsynTask for each class I create as it's created. For this particular issue, I'm displaying the thumbnail and some text properties in a ListView.
The problem is that it's very slow. I considered saving each image to the device the first time it's needed and then each other time, I could just pull it from a database. I'm not sure if this is ideal or not because the image may or may not be updated on the server. In my opinion, I think it's best to always grab the images on the fly just in case there are new ones to grab.
I'd like some suggestions from all you fine folks about this.
Note: I've also tried getting the images in a ListView adapter but 1) it gets each image each and every time the ListView is scrolled and 2) it's incredibly buggy because as each image downloads, I can watch the images appear in the wrong listview item and then it magically corrects itself after a while. This wasn't at all ideal so that's why I moved the code to the class.
I'd appreciate any advice that's thrown my way.
Here's the getter for the image that lives in the class. This works fine after the image is downloaded the first time but not so well during that initial run.
public Bitmap GetThumbnail_xlarge() throws Exception {
if(_thumbnail_xlarge == null ) {
if( _thumbnailBasePath != null) {
try {new DownloadImageTask(_thumbnail_xlarge).execute(_thumbnailBasePath + "/portrait_xlarge." + _thumbnailExtension); }
catch (Exception e) {} //TODO: The extension could be incorrect. Do nothing for now.
}
else{ throw new Exception("You must set the thumbnail path before getting the image"); }
}
return _thumbnail_xlarge;
}
And, here is the class that does the work. Please note that this is a private class inside of the class where the image property lives:
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
Bitmap bmImage;
public DownloadImageTask(Bitmap bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) { _thumbnail_xlarge = result; }
}
I can't think of anything else that might be pertinent at this time. Please ask me for more information if necessary and thanks in advance!
It's incredibly useful to save images locally for later use. This called caching by the way. It's useful, as you are saving resources and you can reduce network requests which are using plenty of them.
If the images are big you can use the WebP format. WebP is an image format which is "lossless and lossy compression for images on the web. WebP lossless images are 26% smaller in size compared to PNGs. WebP lossy images are 25-34% smaller in size compared to JPEG images at equivalent SSIM index."
More info regarding WebP format you can find here: https://developers.google.com/speed/webp/?csw=1
Also if you want to load images smoothly on a ListView you have to use the ViewHolder pattern. More info here: http://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder

NullPointerException on JSONArray initialized in background thread

I'm writing an android app I use a background thread to pull a JSONArray from a web service. I then need to interact with that JSONArray inside the main activity. Here's what I'm doing now:
public class MainActivity extends Activity {
JSONArray stories;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new getAll().execute();
// try {
System.out.println("stories.length());
// } catch (JSONException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
//}
}
And the background thread:
private class getAll extends AsyncTask <Void, Void, JSONArray> {
private static final String url = "http://10.0.2.2:8080/CalibServer/webresources/storypkg.story/";
#Override
protected JSONArray doInBackground(Void... params) {
//set up client and prepare request object to accept a json object
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
httpget.addHeader("accept", "application/json");
HttpResponse response;
String resprint = new String();
try {
response = httpclient.execute(httpget);
// Get the response entity
HttpEntity entity = response.getEntity();
if (entity != null) {
// get entity contents and convert it to string
InputStream instream = entity.getContent();
String result= convertStreamToString(instream);
resprint = result;
// construct a JSON object with result
stories =new JSONArray(result);
// Closing the input stream will trigger connection release
instream.close();
}
}
catch (ClientProtocolException e) {System.out.println("CPE"); e.printStackTrace();}
catch (IOException e) {System.out.println("IOE"); e.printStackTrace();}
catch (JSONException e) { System.out.println("JSONe"); e.printStackTrace();}
System.out.println("FUCKYEAHBG: " + resprint);
// stories = object;
return stories;
}
My problem is that I'm getting a NullPointerException at the call to
System.out.println("stories.length());
It's acting like a didn't initialize the stories array, but should't that have been taken care of by the background thread (at the line: stories =new JSONArray(result); ) before that call is ever made?
I have a feeling this is because of the threading - perhaps there is another step I have to take to update the main activity after the AsyncTask runs?
You're initializing the variable in a background thread. That means that the line
System.out.println(stories.length());
is executed in parallel with the code initializing the variable. That thus means that there is a huge chance that the background thread has not had the time to initialize the variable yet when this line is executed.
Your code is similar to the following situation: you have an empty cup in front of you, and ask someone to go make some coffee and to fill your cup. And immediately after asking, you start drinking. There will be no coffee inside the cup, obviously.
Re-read the android documentation on how to execute asynchronous tasks.
You can't rely on stories to be initialized when a separate Thread that runs parallel to the UI Thread initializes and updates stories.
perhaps there is another step I have to take to update the main
activity after the AsyncTask runs?
onPostExecute() of the AsyncTask. Do whatever UI updates you need there. Since getAll is already a private inner class, you have full access to the Activity. You already return stories off to that (unoverriden) method, so this should be a minor change.
#Override
protected void onPostExecute (JSONArray stories)
{
//use the now initialized stories
}

Categories