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??
Related
I am learning Android dev. and am developping a Hearthstone app using a Hearthstone API for fun.
My users can search for specific cards and now I wish to implement a Card Displayer that displays cards by their type, and lets the user swipe right or left to display the next one in my JSONArray. My API request gives me one and each JSONObject has an img attribute with the cards image URL.
Therefore, when the user swipes I am doing the following:
// Swipe right -> number - 1 (Previous page)
// Swipe left -> number + 1 (Next page)
public void displayCardNumber(int number) {
APIRequests apiRequests = new APIRequests();
try {
// Gets the JSONObject at 'number' and retrieves its img URL.
JSONObject card = (JSONObject) cardsArray.get(number);
String currentImageURL = (String) card.get("img");
// Here is where my problem is.
Bitmap bitmap = apiRequests.getImageBitmap(currentImageURL);
if (bitmap != null) {
setNewImage(bitmap);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
But apiRequest.getImageBitmap(URL) is where I have a problem.
I must download the image in order to display it, but not only does the following block of code not work when I download more than one image, I must also find an efficient way of displaying my cards (that requires background download perhaps?).
// Returns the image's bitmap using the URL
protected Bitmap getImageBitmap(String currentImageURL) {
try {
Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(currentImageURL).getContent());
return bitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
Why can't I download more than 1 image? Is my way of getting my Bitmap false?
Thank you.
Use Glide https://github.com/bumptech/glide .This is faster.
Bitmap theBitmap = Glide.
with(this).
load(imgUrl). //image url as string
asBitmap().
into(100, 100). // Width and height
get();
You can also use it with another way like this:
Glide.with(context).load(url) // image url
.thumbnail(0.5f)
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(imgId) // If no image found the imgId is the default image id for the imageView
.into(imageView); // imageView to show the image
I have found a solution,
In order to load my image and display it I now use a library called Android Universal Image Loader that lets me do the following:
// Load image, decode it to Bitmap and display Bitmap in ImageView
ImageLoader imageLoader = ImageLoader.getInstance();
ImageView i = (ImageView)view.findViewById(R.id.cardDisplay);
imageLoader.displayImage(currentImageURL, i);
I retrieve the correct URL in my AsyncTask's doInBackground and display it with the library's method.
Question 1: Is it possible to download image file without giving the reference to ImageView?
Question 2: Can i download each file in a separage instance of aQuery or do i have to download the file sequentially? e.g, waiting for the callback of current file download and then trigger the next file download call? Below is my code
// Ad is my custom model class
// adList is my list of Ads having URL's to the ads hosted somewhere
// imageView is an invisible imageView as downloading does not start if i don't give any reference to any imageView resource
for (String adUrl : adList) {
if (adUrl.length() > 0) {
AQuery aQuery = new AQuery(DownloadAdActivity.this);
BitmapAjaxCallback callback = new BitmapAjaxCallback();
callBack.url(adUrl);
callBack.fallback(R.id.placeHolderResource);
callBack.fileCache(true);
callBack.memCache(true);
aQuery.id(imageView).image(callBack);
}
}
I need to download 20/30 images when the app starts first time, so far i am doing it by giving a hidden imageView reference and trigging the aQuery sequentially after each image has downloaded. I tried to generate 20/30 request in a loop but only the last aQuery trigger call works which cancels the previous image download call.
Please guide me:
1- How to cache images without giving any reference to the imageView
2- How to download images in parallel manner, not in sequential manner through AQuery.
1) You can use ajax call without ImageView reference to download image.
androidQuery.ajax("url", Bitmap.class, 0, new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap bitmap, AjaxStatus status) {
super.callback(url, bitmap, status);
}
});
2) By default you can download 4 images concurrently. But you can change as per your requirement like this
AjaxCallback.setNetworkLimit(8);
You can use Picasso
It will make all the downloads and also the caching for the images.
Anyway if the images are quite small you should prepare a "zip" file and dl all of them with an AsyncTask / Thread and unzip them. Opening and closing the connections to the server are "very expensive" operations in time consuming.
Here is method to obtain bitmap from url using AQuery
static Bitmap myBitmap = null;
public static Bitmap getBitmapFromURL(String src) {
try {
Log.i(TAG, "Image Url is : " + src);
AQuery androidQuery = new AQuery(ChatApplication.getInstance());
androidQuery.ajax(src, Bitmap.class, 0, new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap bitmap, AjaxStatus status) {
super.callback(url, bitmap, status);
if (bitmap != null)
myBitmap = bitmap;
}
});
} catch (Exception e) {
Log.i(TAG, "Error due to " + e);
}
return myBitmap;
}
AQuery aq = new AQuery(context);
aq.ajax(url_of_image, Bitmap.class, new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap object, AjaxStatus status) {
}
});
Im sorry for replying late,But this is best library I have ever came across.
Yes,You can download. Bitmap object will give you the image.
You can create multiple instances of Aquery if you want to download or pass the each URL after one download finishes,you can use any loop for that.
I have an app where I have one banner in the top with News, when I want to put other news I need to open the code and change the resource .jpg and the Link. There is a way to change the banner and the Link (or at least the banner) without modifing the code? Idk maybe uploading it to a webpage or something like this.
thanks
My suggestion would be to upload a banner.jpg to a server that your app can access and dynamically load. This would prevent having to update your app every time you want to change the banner, and makes it cleaner (no excessive Google Play updates). To do actually load the image you can use this code:
ImageView image1 = (ImageView) findViewById(R.id.mybanner);
new Thread(new Runnable(){//create a new thread so we can do network operations
#Override
public void run() {//main thread function
try {//attempt to do network stuff
URL url = new URL("http://your-hosting-site.com/banner.jpg");//create aURL object with the path to your banner
HttpURLConnection con = (HttpURLConnection) url.openConnection();//create the connection object from the url
con.setReadTimeout(15000);
con.setConnectTimeout(15000);
con.setRequestMethod("GET");
con.setDoInput(true);
con.connect();//connect to the server
InputStream is = con.getInputStream();//get the stream so we can read the image
Drawable d = Drawable.createFromStream(is, "MyBanner");//create a drawable from the image
Bitmap bmp = ((BitmapDrawable) d).getBitmap();//create a bitmap from the drawable
final Drawable dS = new BitmapDrawable(Bitmap.createScaledBitmap(bmp, 192, 192, true));//scale it to whatever size you need
con.disconnect();//disconnect now that we're done
runOnUiThread(new Runnable(){//run UI update code on the main thread
#Override
public void run() {
image1.setImageDrawable(dS);//set the imageview to the banner we downloaded
}
});
} catch (MalformedURLException e) {//catch url error
e.printStackTrace();
} catch (IOException e) {//catch io error when downloading
e.printStackTrace();
}
}
}).start();//run the thread
Change "http://your-hosting-site.com/banner.jpg" (line 6) to wherever you uploaded the .jpg, R.id.mybanner (line 1) to the id of your ImageView, and "MyBanner" (line 14) to whatever you want to call the image.
You might want to save your banner to the phone and only check after X days/hours for an update to save data, but that is up to you.
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
The problem
Hi there,
I'm developing an application where the user specifies some pictures and how long they are going to be on the screen.So sometimes he wants to create something like a small animation or viewing the images for a small amount of time.The problem is that after some time the images are not previewed when they should and we have a few ms of error.In the application that i'm developing time matters so I would like some help on what the problem might be.
The code
So let me explain how it works.I take the pictures from my web app and then I save them in a HashMap
Bitmap image = ImageOperations(url,String.valueOf(frameNum) + ".jpg");
ImageMap.put(String.valueOf(frameNum), image);
where the mathod ImageOperations is like that:
private Bitmap ImageOperations(String url, String saveFilename) {
try {
Display display = getWindowManager().getDefaultDisplay();
InputStream is = (InputStream) this.fetch(url);
Bitmap theImage = BitmapFactory.decodeStream(is);
if (theImage.getHeight() >= 700 || theImage.getWidth() >= 700) {
theImage = Bitmap.createScaledBitmap(theImage,
display.getWidth(), display.getHeight() - 140, true);
}
return theImage;
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
So later I run a thread that updates the UI when the user specified.The method that updates it is this one.
public void setPictures(int NumOfFrame) {
if (frameArray.get(NumOfFrame - 1).frame_pic.contains("n/a") != true) {
ImagePlace.setImageBitmap(ImageMap.get(String.valueOf(NumOfFrame)));
} else {
ImagePlace.setImageDrawable(null);
}
}
After we update the image we put the thread for sleep and when runs again it updates the thread.Is there something that creates the problem?Does it have to do with Garbage collection?
Thank you in advance
Probably the issue is in increasing heap size when it loads additional images. I would suggest You to do some profiling so things will be much clearer and You'll get full picture of timings for the app.
First you are missing a null check at here:
ImageMap.get(String.valueOf(NumOfFrame))
And you do not recycle the old bitmap at here:
theImage.recycle(); // missing line
theImage = Bitmap.createScaledBitmap(theImage,
display.getWidth(), display.getHeight() - 140, true);
It may lead to outofmemory exceptions, with is most likely from your description of the problem.
Also I am not sure if BitmapFactory.decodeStream throw exception when he fails. You need to add a null point check there too.