Android: Bitmap doesn't get added to ArrayList<Bitmap> - java

I create a Bitmap using Android Query like this:
ArrayList<Bitmap> bitmapArray = new ArrayList<Bitmap>();
aq = new AQuery(HomeCategoryActivity.this);
aq.ajax(currentUrl,Bitmap.class,0,new AjaxCallback<Bitmap>(){
#Override
public void callback(String url, Bitmap object, AjaxStatus status) {
if(object != null)
{
bitmapArray.add(object);
}
}
});
But when I Log.d the size of the arraylist, it returns 0. The Bitmap is NOT NULL, I checked by setting it as an image resource. It simply doesn't get added to the arraylist. What do you think is wrong?

Related

Issues with Microsoft API

So Im having trouble using Microsoft's Emotion API for Android. I have no issues with regards to running the Face API; Im able to get the face rectangles but I am not able to get it working on the emotion api. I am taking images using the builtin Android camera itself. Here is the code I am using:
private void detectAndFrame(final Bitmap imageBitmap)
{
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
ByteArrayInputStream inputStream =
new ByteArrayInputStream(outputStream.toByteArray());
AsyncTask<InputStream, String, List<RecognizeResult>> detectTask =
new AsyncTask<InputStream, String, List<RecognizeResult>>() {
#Override
protected List<RecognizeResult> doInBackground(InputStream... params) {
try {
Log.e("i","Detecting...");
faces = faceServiceClient.detect(
params[0],
true, // returnFaceId
false, // returnFaceLandmarks
null // returnFaceAttributes: a string like "age, gender"
);
if (faces == null)
{
Log.e("i","Detection Finished. Nothing detected");
return null;
}
Log.e("i",
String.format("Detection Finished. %d face(s) detected",
faces.length));
ImageView imageView = (ImageView)findViewById(R.id.imageView);
InputStream stream = params[0];
com.microsoft.projectoxford.emotion.contract.FaceRectangle[] rects = new com.microsoft.projectoxford.emotion.contract.FaceRectangle[faces.length];
for (int i = 0; i < faces.length; i++) {
com.microsoft.projectoxford.face.contract.FaceRectangle rect = faces[i].faceRectangle;
rects[i] = new com.microsoft.projectoxford.emotion.contract.FaceRectangle(rect.left, rect.top, rect.width, rect.height);
}
List<RecognizeResult> result;
result = client.recognizeImage(stream, rects);
return result;
} catch (Exception e) {
Log.e("e", e.getMessage());
Log.e("e", "Detection failed");
return null;
}
}
#Override
protected void onPreExecute() {
//TODO: show progress dialog
}
#Override
protected void onProgressUpdate(String... progress) {
//TODO: update progress
}
#Override
protected void onPostExecute(List<RecognizeResult> result) {
ImageView imageView = (ImageView)findViewById(R.id.imageView);
imageView.setImageBitmap(drawFaceRectanglesOnBitmap(imageBitmap, faces));
MediaStore.Images.Media.insertImage(getContentResolver(), imageBitmap, "AnImage" ,"Another image");
if (result == null) return;
for (RecognizeResult res: result) {
Scores scores = res.scores;
Log.e("Anger: ", ((Double)scores.anger).toString());
Log.e("Neutral: ", ((Double)scores.neutral).toString());
Log.e("Happy: ", ((Double)scores.happiness).toString());
}
}
};
detectTask.execute(inputStream);
}
I keep getting the error Post Request 400, indicating some sort of issue with the JSON or the face rectangles. But I'm not sure where to start debugging this issue.
You're using the stream twice, so the second time around you're already at the end of the stream. So either you can reset the stream, or, simply call the emotion API without rectangles (ie skip the call to the face API.) The emotion API will determine the face rectangles for you.

Cannot Retrieve Query from Current User - Parse (Android)

I'm trying to retrieve an image from the current user to display as a profile picture.
I can quite easily get it to work by inserting a specific object ID after query.getInBackground() What I want to do is to pull the "profilePicture" of the user currently logged in, hence current User, and not just one specific user. How can I fix this?
progressDialog = ProgressDialog.show(GalleryActivity.this, "",
"Downloading Image...", true);
// Locate the class table named "ImageUpload" in Parse.com
ParseQuery<ParseUser> query = ParseUser.getQuery();
// Locate the objectId from the class
ParseUser currentUser = ParseUser.getCurrentUser();
query.getInBackground(String.valueOf(ParseUser.getCurrentUser()),
new GetCallback<ParseUser>() {
public void done(ParseUser object,
ParseException e) {
// TODO Auto-generated method stub
// Locate the column named "ImageName" and set
// the string
ParseFile fileObject = (ParseFile) object
.get("profilePicture");
fileObject
.getDataInBackground(new GetDataCallback() {
public void done(byte[] data,
ParseException e) {
if (e == null) {
Log.d("test",
"We've got data in data.");
// Decode the Byte[] into
// Bitmap
Bitmap bmp = BitmapFactory
.decodeByteArray(
data, 0,
data.length);
// Get the ImageView from
// main.xml
ImageView image = (ImageView) findViewById(R.id.galleryProfilePic);
// Set the Bitmap into the
// ImageView
Bitmap resized = Bitmap.createScaledBitmap(bmp, 300, 300, true);
Bitmap conv_bm = getRoundedRectBitmap(resized, 300);
image.setImageBitmap(conv_bm);
// Close progress dialog
progressDialog.dismiss();
} else {
Log.d("test",
"There was a problem downloading the data.");
ImageView image = (ImageView) findViewById(R.id.galleryProfilePic);
image.setImageResource(R.drawable.ic_default_profile_picture);
}
}
});
}
});
I actually got this working by passing the object ID of the current user as a string into the query to replace the static object ID:
String currentUser = ParseUser.getCurrentUser().getObjectId();
query.getInBackground(currentUser,
new GetCallback<ParseUser>() {

Why aren't my images downloading into ImageViews?

I'm pretty new to native Android development. What my app is currently doing:
Download a JSON of image urls from our server
Add an ImageView to a ListView for each image
I've gotten the JSON and am now working on using an ImageAdapter (extends BaseAdapter) to populate the ListView, but I'm running into an error:
I'm getting println needs a message during creation of the InputStream in my OpenHttpGETConnection function.
Here's my code (in order of highest to lowest with unnecessary code removed):
Once JSON Is loaded my onPostExecute code'll run to start the adapter:
private class DownloadImagesTextTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls){
return getImages(urls[0]);
}
#Override
protected void onPostExecute(String result){
JSONArray images = null;
images = new JSONArray(result);
// TURN images into array of imageviews
ListView listView = (ListView) findViewById(R.id.list);
#here----> listView.setAdapter(new ImageAdapter(getBaseContext(), images));
Log.d("DownloadTextTask", images.toString());
}
}
Here's my ImageAdapter code:
public class ImageAdapter extends BaseAdapter {
private Context context;
private JSONArray images;
public ImageAdapter(Context c, JSONArray i){
context = c;
images = i;
}
// returns an imageview view
public View getView(int position, View convertView, ViewGroup parent){
ImageView imageView = new ImageView(context);
try {
String url = "http://www.example.com/" + images.get(position);
#here----> imageView.setImageBitmap(getImageBitmap(url));
} catch (Exception e){
Log.d("LoadImage", e.getLocalizedMessage());
}
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
return imageView;
}
}
Here's my getImageBitmap function:
private Bitmap getImageBitmap(String url){
Bitmap bitmap = null;
InputStream in = null;
try {
#here----> in = OpenHttpGETConnection(url);
} catch (Exception e) {
#i_get
#this ----> Log.wtf("OpenGET", e.getMessage() + ": " + url );
#error
}
bitmap = BitmapFactory.decodeStream(in);
in.close();
return bitmap;
}
And finally, here's my OpenHttpGETConnection function:
public static InputStream OpenHttpGETConnection(String url){
InputStream inputStream = null;
HttpClient httpClient = null;
HttpResponse httpResponse = null;
httpClient = new DefaultHttpClient();
httpResponse = httpClient.execute(new HttpGet(url));
inputStream = httpResponse.getEntity().getContent();
return inputStream;
}
And here's the pertaining LogCat line: (Happens for 3 images that came through the JSON file)
A/OpenGETīš• println needs a message: http://www.example.com/image1.jpg
The weird thing is, I use the same OpenHttpGETConnection when I load my JSON data, so I'm pretty sure that's returning a correct InputStream object. Are there some caveats when using it for text vs. binary data (jpg)?
Thanks in advance!
First of all in the adapter, in the getView() method, you're not recycling the items. Have a look on the ViewHolder pattern (http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html).
Then, getImageBitmap() seems to be executed on the same thread, I wonder why it doesn't crash. I guess there you download the actual image. It should be done asynchronously, and you should send a reference of the ImageView and when the download is finished you should load it into it. Of course you'll have to care about if when you put the bitmap inside the ImageView you have the good ImageView on the screen (because it might have been recycled).
To get rid of all these concerns you could just use Picasso library (http://square.github.io/picasso/) and that will do all this for you.

How to use AsyncTask to update a global variable

What I want to do: I am putting rows into a ListView using a custom "Location" adapter. I am trying to add a Bitmap into a row of the ListView. This Bitmap is coming from a URL. So, I have a global variable public static Bitmap bitmap and want to update this variable using an AsyncTask. Here is my code:
try {
String s = "";
JSONArray jArray = new JSONArray(result);
for (int i = 0; i < jArray.length(); i++) {
final JSONObject json = jArray.getJSONObject(i);
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
//here I am calling my new task and giving it the ID to find the image
BitmapWorkerTask myTask = new BitmapWorkerTask(json.getInt("ID"));
myTask.execute();
adapter.add(new Location(bitmap, json
.getString("PlaceTitle"), json
.getString("PlaceDetails"), json
.getString("PlaceDistance"), json
.getString("PlaceUpdatedTime")));
bitmap = null;
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
} catch (Exception e) {
// TODO: handle exception
Log.e("log_tag", "Error Parsing Data " + e.toString());
}
and here is my AsyncTask
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private int photoID = 0;
public BitmapWorkerTask(int photoID) {
// Use a WeakReference to ensure the ImageView can be garbage collected
this.photoID = photoID;
}
// Decode image in background.
#Override
protected Bitmap doInBackground(Integer... params) {
String initialURL = "http://afs.spotcontent.com/img/Places/Icons/";
final String updatedURL = initialURL + photoID + ".jpg";
Bitmap bitmap2 = null;
try {
bitmap2 = BitmapFactory.decodeStream((InputStream) new URL(
updatedURL).getContent());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap2;
}
// Once complete, see if ImageView is still around and set bitmap.
#Override
protected void onPostExecute(Bitmap bitmap2) {
bitmap = bitmap2;
}
}
So, for each iteration, I am feeding the AsyncTask an ID which it uses to find the image, and then (I was hoping) should update the global Bitmap which is passed into the adapter. When I run my app, the every listing's picture is empty. Any ideas on what I'm doing wrong?
Consider the following possible order your commands get executed (remembering that tasks run in the background, so the order is non-deterministic):
myTask.execute()
BitmapWorkerTask.doInBackground()
adapter.Add(new Location(bitmap, .......
BitmapWorkerTask.onPostExecute()
When you create the Location() object in step 3, the 'bitmap' object being passed is the global object pointer. Its value is NOT valid yet, because onPostExecute() wasn't called yet. So the Location object is created with a non-bitmap object. On step 4, when the bitmap is finally retrieved, the value of the global object pointer is changed (correctly), but that doesn't affect the (empty) bitmap object already passed to Location on step 2... Which is why you don't see the bitmap on your view.
What you could do is pass an additional parameter to the BitmapWorkerTask constructor: You could pass the Location object (or the underlying bitmap). From onPostExecute() you could then update that Location/bitmap object with the retrieved bitmap. You don't need a global variable here.

Set a reference of a new Bitmap from within an AsyncTask

This may be more of a Java question than an Android question, but I'm having trouble retrieving a Bitmap created within an AsyncTask to store in another class (an Activity) so that I can recycle it when I'm done using it.
The AsyncTask creates the Bitmap in doInBackground() and sets it as the bitmap for an ImageView in onPostExecute(), the ImageView being passed in through the constructor. But after completion I want the Bitmap to be accessible in the Activity. The Activity has an ArrayList of ImageViews and another of Bitmaps, but since the AsyncTask creates a new Bitmap, I can't find an easy way to get this new object in the ArrayList of Bitmaps in the Activity. Currently I have it working by passing in the ArrayList along with an index into the list to the AsyncTask constructor, and doInBackground just sets that entry in the array to the newly created bitmap.
I don't like this solution though, because I want to be able to use this AsyncTask for different things, perhaps where the Activity doesn't have an ArrayList of Bitmaps. And I can't simply give the AsyncTask constructor a Bitmap because Java passes the reference by value, and setting it to a new Bitmap object wouldn't allow access for the caller.
How can I do this more elegantly?
Here is the relevant code. Lines not pertaining to this question have been omitted for clarity.
public class LoadCachedImageTask extends AsyncTask<String, Void, Void> {
private Context context;
private ImageView image;
private ArrayList<Bitmap> bitmaps;
int index;
public LoadCachedImageTask(Context context, ImageView image, ArrayList<Bitmap> bitmaps, int index) {
this.context = context;
this.image = image;
this.bitmaps = bitmaps;
this.index = index;
}
protected Void doInBackground(String... urls) {
String url = urls[0];
Bitmap bitmap = null;
// Create the bitmap
File imageFile = new File(context.getCacheDir(), "test");
bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
// Set the bitmap to the bitmap list
bitmaps.set(index, bitmap);
return null;
}
protected void onPostExecute(Void arg) {
// Display the image
image.setImageBitmap(bitmaps.get(index));
}
protected void onCancelled() {
if (bitmaps.get(index) != null) {
bitmaps.get(index).recycle();
bitmaps.set(index, null);
}
}
}
And here's a sample Activity that uses it.
public class SampleActivity extends Activity {
private ArrayList<ImageView> images;
private ArrayList<Bitmap> bitmaps;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
images = new ArrayList<ImageView>();
bitmaps = new ArrayList<Bitmap>();
int numImages = 15;
// Create the images and bitmaps
for (int i = 0; i < numImages; i++) {
images.add(new ImageView(this));
bitmaps.add(null);
}
// Load the bitmaps
for (int i = 0; i < numImages; i++) {
new LoadCachedImageTask(this, images.get(i), bitmaps, i).execute("http://random.image.url");
}
}
}
I haven't tested the above code, so it might not work, but I think it gets the point across.
As I understand it, you're trying to load a large number of bitmaps into a large number of ImageViews asynchronously. I would think this can be done with a single AsyncTask class that you use multiple times for each ImageView.
You're AsyncTask should be something like this:
public class LoadCachedImageTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> mImgView;
public LoadCachedImageTask(ImageView image) {
mImageView = new WeakReference<ImageView>(image);
}
protected Void doInBackground(String... urls) {
if(urls == null || urls.length < 1)
return;
// Create the bitmap
final Bitmap bitmap = BitmapFactory.decodeFile(url);
return bitmap;
}
protected void onPostExecute(Bitmap bmp) {
// Display the image
if(bmp != null) {
final ImageView imageView = (ImageView) mImgView.get();
if(imageView != null) // needed in case the weakreference is removed
imageView.setImageBitmap(bmp);
}
}
Then to fill your array of ImageViews with something like this:
for(ImageView imgView : images) {
(new LoadCachedImageTask<String, Void, Bitmap>)(imgView).execute(getBitmapUrl());
}
The for-loop will iterate through each ImageView reference and pass it to a brand new AsyncTask reference. It will then execute the AsyncTask with the given url to whatever bitmap you need. The asynctask will hold on to a reference of the ImageView so long as the ImageView exists. If, for some reason, your ImageView got destroyed, the bitmap will still load then immediately get thrown away.

Categories