I'm working on implementing a website's API in an Android app. There's a part of this API which gives me an array, which contains an array of image URLs. Now, I can iterate through the arrays just fine, and I have written an AsyncTask that transforms image URLs into drawables. But I don't have a good way to get those drawables into the ImageView (which I am creating programatically in the loop):
void createPhotoPost(JSONObject postData, LinearLayout myPostHolder) {
try {
ImageView myImage = new ImageView(myContext);
JSONArray photosArray = new JSONArray(postData.getString("photos"));
for(int i = 0; i < photosArray.length(); i++) {
JSONObject thisPhoto = photosArray.getJSONObject(i);
JSONArray sizesArray = new JSONArray(thisPhoto.getString("alt_sizes"));
JSONObject largest = sizesArray.getJSONObject(0);
new GetPhotoSet(this).execute(largest.getString("url"));
}
myPostHolder.addView(myImage);
} catch (Exception e) {
e.printStackTrace();
}
}
The function I posted above is called from within another loop. As you can see in my code above, the ImageView myImage needs to eventually contain the drawable that is returned by the execute call of GetPhotoSet.execute. Any ideas? Thanks!
Additional details: Since the method where the data is returned by the AsyncTask is outside of the loop where I declared the ImageView myImage, it doesn't know that myImage exists, and it can't reference it (and there are presumably a handful of myImages by this point, from different iterations of the loop)
Nick, that's what onPostExecute() is for. Create your ImageView in onPostExecute() and add it to your Activity from there. If you are looping over a series of images, you can also use publishProgress() to do this. In your example you should move the entire loop to your task's doInBackground().
Related
I currently have an arraylist as follows:
private void loadImages() {
images = new ArrayList<>();
images.add(getResources().getDrawable(R.drawable.imag1));
images.add(getResources().getDrawable(R.drawable.imag2));
images.add(getResources().getDrawable(R.drawable.imag3));
}
I want to be able to convert a url into these drawables such that:
drawable1 = "http.someimage.com/image.png"
drawable2 = "http.someimage.com/newimage.png"
followed by
private void loadImages() {
images = new ArrayList<>();
images.add(getResources().getDrawable(drawable1));
images.add(getResources().getDrawable(drawable2));
...etc }
Is there any easy way to go around this? I definitely want to stick to drawables ,but I cant find any way to convert a url to drawable
Any ideas? Thanks!
If you have a URL of the picture you need to download it first.
You can't "convert" a URL into a drawable.
you need something like this:
URL url = new URL("http.someimage.com/image.png");
Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
Then if you need to add the image into an ImageView object you can call the method .setImageBitmap(bmp).
Otherwise there are ways to extract a Drawable object from the Bitmap
you can check this previous answer. then once you have the drawable you can add it to your arraylist.
Hope I got your question right
P.S.: be sure not to do this on main thread since it is a network operation! use a thread or an asynctask
I have an array of ParseObjects that are being displayed in a list view. Three text views are loaded into my custom cell, and then there's an image in a ParseFile that should also be loaded. The code I have gets the first cell to load correctly, but in every other cell the image doesn't load. Here's my code:
this.origImage = (ParseFile) posts.get(position).get("image");
try {
Log.d("MyMessage", "Gonna convert image");
this.imageData = this.origImage.getData();
this.options = new BitmapFactory.Options();
this.options.inDither = true;
this.options.inPreferredConfig = Bitmap.Config.ARGB_8888;
this.options.inSampleSize = 8;
this.notConvertedYet = BitmapFactory.decodeByteArray(this.imageData, 0, this.imageData.length, this.options);
if (this.notConvertedYet != null)
this.myBitmap = rotateImage(90, this.notConvertedYet);
else
this.myBitmap = this.notConvertedYet;
mHolder.picImageView.setImageBitmap(this.myBitmap);
Log.d("MyMessage", "Converted image");
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
What is happening that's messing it up?
when its bound to a list adapter, what does the
posts.get(position).get("image");
do actually? Is the parse SDK calling a series of AsyncTasks for the network Http GET on the actual URL in parse's file CDN?
You may have to find out more about what its doing because , as is, it may not be very efficient as used by the Adapter.getView()...
Any image loader framework like Volley, like Universal Image Loader, like AQuery will work like an api where you make a call providing the ImageView and the CDN URL for the image as parms. The framework will handle multithreading, pooled Parse.com connections , memCache and fileCache for all images. When using parse to store bitmaps in the file CDN you can still use any of the image loading frameworks.
AQuery sample in an adapter...
ImageView thumbnail=(ImageView)vi.findViewById(R.id.imageView1); // thumb image
mAquery.id(thumbnail).width(110).image($thumbUrl_CDN,
true, true, 0, R.drawable.default_video, null, 0, mAspectRatio);
Your code looks ok.. maybe the reason all the imageViews are black is that the adapter did not have time to get the files loaded across the network and the loop statement did not block the UI thread??
My application generates ListFragments based on user type (determined by the DeviceID) and then fetch images from a web server. These images will then be displayed as a list.
My question is how can I cache those images as well as fragments (generated dynamically) to be displayed in offline mode. For instance when user opens the application without having an active internet connection, it should display the images within the fragments generated dynamically last time.
At the moment my app just download the images from a web service each time.
code for generating fragments dynamically in the MainActivity each time when the application loads.
//generating the views based on JSON data
try {
JSONObject resultObject = new JSONObject(result.toString());
boolean success = resultObject.getBoolean("success");
JSONArray jArray = resultObject.getJSONArray("data");
if (success == true) {
//save menu
for (int i = 0; i < jArray.length(); i++) {
postObject = jArray.getJSONObject(i);
if (postObject.has("ev_count")) {
categoriesSet.put("Events", "Events");
mTabsAdapter.addTab(bar.newTab().setText("Events"), EventsFragment.class, null);
}
if (postObject.has("pl_count")) {
categoriesSet.put("Places", "Places");
mTabsAdapter.addTab(bar.newTab().setText("Places"), PlacesFragment.class, null);
}
if (postObject.has("gn_count")) {
categoriesSet.put("General", "General");
mTabsAdapter.addTab(bar.newTab().setText("General"), GeneralFragment.class, null);
}
}
}
//saving values to the shared preferences (hashmap as a string)
categoriesPreferences = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = categoriesPreferences.edit();
editor.putString("categories", categoriesSet.toString());
editor.commit();
}catch (JSONException e) {
Log.e("ALLOCATE_DAT_ERROR", e.toString());
}
I would just advice to use some image downloading library which also often handles caching for you..
Here is a short list of some of them:
Volley - directly from google, its more like a whole networking stack, but it allows you to easily download Images (see NetworkImageView) and also to cache them (you need to provide a cache implemtantion - google will help you)
Picasso - nice library from square with very straightforward API - I would advice you to go with it, it might be the easiest way to go
Universal Image Loader - another option, it has really a lot of options and is also easy to use
Here is a simple sample code which should advice you how to use volley to load and cache images.
NetworkImageView mage = (NetworkImageView) view.findViewById(...);
image.setImageUrl("http://someurl.com/image.png",mImageLoader);
You need an ImageLoader instance then..
public ImageLoader getImageLoader() {
if (mImageLoader == null) {
mImageLoader = new ImageLoader(getImageRequestQueue(), new DiskBitmapCache(getCacheDir(), 50 * 1024 * 1024));
}
return mImageLoader;
}
imageRequestQueue is standard queue you should have already initialised somewhere in your app if already using volley for networking stuff
As a DiskCache you can use this
I'm downloading files with my app via an API (this is working perfectly). Later in my app I'm doing a call to my database to get the file info: id, name, location and return it as a HashMap:
HashMap<Integer, ArrayList<String>> imgTitle;
I take the returned HashMap, extract the ArrayList and use that to populate some buttons. the array list holds the filename and file location. When the page loads the names display correctly but the images don't always load or one loads. If I go back and reenter the activity (via a button press) I'll get different images showing up. I've sent my array to the log and the file location is present and correct for all arrays. Why are only some image showing?
for (Map.Entry<Integer, ArrayList<String>> e : imgTitle.entrySet()) {
...
ArrayList<String> catList = e.getValue();
final String catTitle = catList.get(0);
File indexImage = new File(catList.get(1));
// add images
ImageButton imgButton = new ImageButton(this);
imgButton.setImageURI(Uri.fromFile(indexImage));
...
}
The above is inside a method called on the onCreate. My assumption is maybe the setImageURI is too slow? Any ideas?
Prior to using the setImageURI I used
imgButton.setImageResource(R.drawable.test_vehicle);
as a placeholder it was working fine. However, now I have to use a file that was downloaded and saved locally.
You could try to decode a Bitmap from a stream, like this:
File indexImage = new File(catList.get(1));
InputStream imageStream = new FileInputStream(indexImage);
Bitmap backgroundImage = null;
try {
backgroundImage = BitmapFactory.decodeStream(imageStream);
}
catch(Exception e) {
e.printStackTrace();
}
finally {
try {
//Dispose of the temporary resources
imageStream.close();
imageStream = null //So that the stream is deleted on next GC
}
catch(IOException e) {
e.printStackTrace();
}
}
if (backgroundImage != null) {
ImageButton imgButton = new ImageButton(this);
imgButton.setImageBitmap(backgroundImage);
backgroundImage.recycle();
}
Note: This is pure speculation, I haven't tested any of this. It's simply the first solution that came to my mind
Okay, so I have a JSON array of image URLs. I want to load them into a horizontal scrolling view. This is the way I've gone about it, but nothing gets displayed where the ScrollView should go:
public void run() {
JSONArray photosArray;
caption = new WebView(thisContext);
imageScroller = new HorizontalScrollView(thisContext);
imagesHolder = new LinearLayout(thisContext);
imagesHolder.setOrientation(LinearLayout.HORIZONTAL);
try {
photosArray = new JSONArray(postData.getString("photos"));
for(int i = 0; i < photosArray.length(); i++) {
WebView iV = new WebView(thisContext);
JSONObject thisPhoto = photosArray.getJSONObject(i);
JSONArray sizesArray = new JSONArray(thisPhoto.getString("alt_sizes"));
JSONObject largest = sizesArray.getJSONObject(0);
iV.loadData("<img src=\""+largest.getString("url")+"\" />", "text/html", null);
imagesHolder.addView(iV);
}
imageScroller.addView(imagesHolder);
myPostHolder.addView(imageScroller);
caption.loadData(postData.getString("caption"),"text/html",null);
myPostHolder.addView(caption);
} catch (Exception e) {
e.printStackTrace();
}
}
Note that this is done in a runnable class. Thanks a lot
There are two rules in the Android single thread model.
Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread
So I don't think you can add views to a viewgroup outside of the main thread. Please see: http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html for a fuller explanation.
Also, you need to make sure you are actually setting the contentview and you may need to call invalidate() on the viewgroup to cause a redraw.
And, you probably should be using a GridView..can't see why you'd use a webview for this.