ITKeyword,专注技术干货聚合推荐

注册 | 登录

解决android - How do I load an image into imageview from URL that I have gotten from JSON parse?

itPublisher 分享于

2021腾讯云限时秒杀,爆款1核2G云服务器298元/3年!(领取2860元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1062

2021阿里云最低价产品入口+领取代金券(老用户3折起),
入口地址https://www.aliyun.com/minisite/goods

I've looked at a few answers on here but they all ask different things. As a result I came up with the code below. I parse my JSON using an AsyncTask I have access to it in two places. The end of doInBackground(); and onPostExecute();

I tried the following code in both and got two different errors:

The code:

try {
   ImageView one = (ImageView)findViewById(R.id.one);
   String getImage = bookDet.get(0).image;
   Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(getImage).getContent());
   one.setImageBitmap(bitmap); 
} catch (MalformedURLException e) {
   e.printStackTrace();
} catch (IOException e) {
   e.printStackTrace();
}

BookDet is the ArrayList that holds the data, it has been converted to a string and put there.

The error when I try it doInBackground():

E/AndroidRuntime(14007): FATAL EXCEPTION: AsyncTask #2
E/AndroidRuntime(14007): java.lang.RuntimeException: An error occured while executing doInBackground()
E/AndroidRuntime(14007):    at android.os.AsyncTask$3.done(AsyncTask.java:299)
E/AndroidRuntime(14007):    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
E/AndroidRuntime(14007):    at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
E/AndroidRuntime(14007):    at java.util.concurrent.FutureTask.run(FutureTask.java:239)
E/AndroidRuntime(14007):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
E/AndroidRuntime(14007):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
E/AndroidRuntime(14007):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
E/AndroidRuntime(14007):    at java.lang.Thread.run(Thread.java:856)
E/AndroidRuntime(14007): Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

That's only part of it but the last line seems to be the key. There's only one AsyncTask so yeah.

Error when I do it in onPostExecute:

E/AndroidRuntime(16801): FATAL EXCEPTION: main
E/AndroidRuntime(16801): android.os.NetworkOnMainThreadException
E/AndroidRuntime(16801):    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1117)
E/AndroidRuntime(16801):    at java.net.InetAddress.lookupHostByName(InetAddress.java:385)
E/AndroidRuntime(16801):    at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
E/AndroidRuntime(16801):    at java.net.InetAddress.getAllByName(InetAddress.java:214)
E/AndroidRuntime(16801):    at libcore.net.http.HttpConnection.<init>(HttpConnection.java:70)
E/AndroidRuntime(16801):    at libcore.net.http.HttpConnection.<init>(HttpConnection.java:50)
E/AndroidRuntime(16801):    at libcore.net.http.HttpConnection$Address.connect(HttpConnection.java:340)
E/AndroidRuntime(16801):    at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:87)
E/AndroidRuntime(16801):    at libcore.net.http.HttpConnection.connect(HttpConnection.java:128)
E/AndroidRuntime(16801):    at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:316)
E/AndroidRuntime(16801):    at libcore.net.http.HttpEngine.connect(HttpEngine.java:311)
E/AndroidRuntime(16801):    at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
E/AndroidRuntime(16801):    at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
E/AndroidRuntime(16801):    at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:81)
E/AndroidRuntime(16801):    at java.net.URLConnection.getContent(URLConnection.java:190)
E/AndroidRuntime(16801):    at java.net.URL.getContent(URL.java:447)

So I can't do it in the main thread...?

The best I can do at the moment is have a TextView that pulls that url to a string and that shows up just fine but that's obviously useless.

Any ideas? How do I get the image to show up from a parsed set of data that was done Asynchronously?

Appreciate anyones help. Thanks.

android json asynchronous android-asynctask imageview
|
  this question
asked Oct 17 '13 at 12:24 RED_ 1,406 3 24 51

 | 

4 Answers
4

解决方法

I recommend you a different way that works like a charm: Android Query.

You can download that jar file from here: http://code.google.com/p/android-query/downloads/list

AQuery androidAQuery=new AQuery(this);

As an example:

androidAQuery.id(YOUR IMAGEVIEW).image(YOUR IMAGE TO LOAD, true, true, getDeviceWidth(), ANY DEFAULT IMAGE YOU WANT TO SHOW);

Using above code you can directly show your Image through url. Now below code is to get Bitmap Directly from the url:

androidAQuery.ajax(YOUR IMAGE URL,Bitmap.class,0,new AjaxCallback<Bitmap>(){
                        @Override
                        public void callback(String url, Bitmap object, AjaxStatus status) {
                            super.callback(url, object, status);

                            //You will get Bitmap from object.
                        }

});

This library is provided by Android itself, so use it and see the result whatever you want.

It's very fast and accurate, and using this you can find many more features like Animation when loading; getting a bitmap, if needed; etc.


|
  this answer
answered Oct 17 '13 at 12:59 Pratik Dasa 4,807 3 16 33      So I can just chuck this in my onPostExecute then and it'll work? I don't know the Image url, it's in a string called from JSON. –  RED_ Oct 17 '13 at 13:03      no need to call this in onPostExecute(), just fetch yur image url from Json and pass it here in Android Query. It will download and display your image. –  Pratik Dasa Oct 17 '13 at 13:04      Wait I don't understand. In onPostExecute I am putting the rest of my JSON data into TextViews. It has to be somewhere in my AsyncTask because thats' the only place I can have access to the imageurl, in the form of a string. –  RED_ Oct 17 '13 at 13:06      yeah then execute android query code there, you can use it. After getting your parsed data use it. I have given you 2 demo code, one for download and display image and another one is to get Bitmap from url. –  Pratik Dasa Oct 17 '13 at 13:10      The only trouble I seem to be having with this is that AjaxStatus doesn't seem to import and getDeviceWidth(), can I replace that with something else? –  RED_ Oct 17 '13 at 13:22  |  show more comments

You should get the file asynchronously and then set it for your imageview.

I have used a lot this lightweight library to ease all the operations of making async HTTP calls: http://loopj.com/android-async-http/.

Example:

AsyncHttpClient client = new AsyncHttpClient();
String[] allowedContentTypes = new String[] { "image/png", "image/jpeg" };
client.get("http://example.com/file.png", new BinaryHttpResponseHandler(allowedContentTypes) {
    @Override
    public void onSuccess(byte[] fileData)
    {
         Bitmap bmp = BitmapFactory.decodeByteArray(fileData, 0, fileData.length);

         if(imageView != null)
         {
             imageView.setImageBitmap(bmp);
         }
    }
});

Where imageView is a reference of your ImageView that you have previously got with:

imageView = (ImageView) view.findViewById(R.id.YOUR_IMAGEVIEW_ID);

Hope it helps.


|
  this answer
answered Oct 17 '13 at 12:34 fasteque 2,852 7 20 43      Is there a way I can do this without a library? What's the gist of it? Could I start a new AsyncTask under the other one and just pull the data again but only pull the image url or via the other one's onPostExecute? –  RED_ Oct 17 '13 at 12:39      Of course there is, but here with 1 minute of integration and very few lines of code you have a very stable and robust solution (this library is used by Instagram and Pinterest by the way). Then, if this is the only place in your app where you need to do an async HTTP call, I can understand you don't want to integrate a library, so yes, use an AsyncTask as explained here: stackoverflow.com/questions/13085951/… –  fasteque Oct 17 '13 at 12:42      Cool, I'll give it go. That one has the URL already though and I won't get mine until I parse a chunk of data together. Hopefully it still works and I don't get the same error as above. In fact looking at that, I don't think it will work. –  RED_ Oct 17 '13 at 12:48      Sure, remember to have set this permission in your manifest: <uses-permission android:name="android.permission.INTERNET" /> –  fasteque Oct 17 '13 at 12:50      Damn, still get a force close. –  RED_ Oct 17 '13 at 12:56  |  show more comments

you have to download the image in doBackground() and then set the result of doBackground as a Bitmap you have just downloaded. In onPostExecute(Bitmap bmp), you can set it to the desired imageView. Do not forget to change parameters of AsyncTask:

AsyncTask<SomeObject, Integer, Bitmap>

Code should look like this.

public class DownloadFilesTask extends AsyncTask<SomeObject, Integer, Bitmap> {
    protected Long doInBackground(SomeObject object) {

        //do the networking and parse json here

        try {
            String getImage = bookDet.get(0).image;
            Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(getImage).getContent()); 
            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
        return null;
    }

    protected void onPostExecute(Bitmap bmp) {

        //set the bitmap to image here

        ImageView one = (ImageView)findViewById(R.id.one);
        one.setImageBitmap(bmp);
    }
}

|
  this answer
answered Oct 17 '13 at 13:09 Alex 458 3 8      My current AsyncTask is like this: public class HttpTask extends AsyncTask<Void, Void, ArrayList<BookDetail>> {} So do you reckon start a new one or I can just fill in the Voids of this one? –  RED_ Oct 17 '13 at 13:11      The first spot (first Void) is a spot for input parameter of doBackgorund(), the 2nd is a spot for progress change and the 3rd spot is for onBackgroud output and onPostExecute input. So you can create new AsycTask and start this one for this situation. For aech situation you can have different AssyncTask –  Alex Oct 17 '13 at 13:20      Thanks for the but the answer below is easier since I only have to add one line of code. I think I can get away with using a small google provided library. I would have doubled my code with this. Shame a whole new AsyncTask is needed for this type of stuff but it makes sense why. –  RED_ Oct 17 '13 at 13:37

 | 

You can use droidQuery to greatly simplify this:

ImageView one = (ImageView)findViewById(R.id.one);
String getImage = bookDet.get(0).image;
$.with(one).image(getImage);

This will lazy load the image from the URL, and handle all asynchronous calls and data parsing.


|
  this answer
answered Oct 20 '13 at 16:12 Phil 22.4k 15 89 138

 | 


相关阅读排行


相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。