I want to get a Bitmap[] from my String[] with links. But this doesn't work as I want. I have this Method:
private Bitmap[] getBitmaps(String[] images){
ArrayList<Bitmap> temp = new ArrayList<>();
for(int i = 0; i < images.length; i++){
ImageView img = new ImageView(getContext());
FrameLayout.LayoutParams x = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
img.setLayoutParams(x);
Picasso.with(getContext()).load(MainPostAdapter.USER_URL+images[i]+".png").into(img, new Callback() {
#Override
public void onSuccess() {
temp.add(BitmapRes.drawableToBitmap(img.getDrawable()));
movableBackgroundContainer.removeView(img);
}
#Override
public void onError() {
}
});
movableBackgroundContainer.addView(img);
}
return temp.toArray(new Bitmap[temp.size()]);
}
The problem is I get a null Array because it adds the Bitmap to the list after the onSuccess function. How can I now wait until all onSuccess added the bitmaps and then return?
The get() function of Picasso does what you're looking for. It downloads a Bitmap rather than load an image into an ImageView. Note that Picasso's get() method cannot be called on the main thread. My example uses an AsyncTask to download images on a separate thread.
String[] images = new String[] {"http://path.to.image1.jpg", "http://path.to.image2.jpg"};
new AsyncTask<String[], Void, List<Bitmap>>() {
#Override
protected List<Bitmap> doInBackground(String[]... params) {
try {
List<Bitmap> bitmaps = new ArrayList<Bitmap>();
for (int i = 0; i < params[0].length; ++i) {
bitmaps.add(Picasso.with(getActivity()).load(params[0][i]).get());
}
return bitmaps;
} catch (IOException e) {
return null;
}
}
#Override
public void onPostExecute(List<Bitmap> bitmaps) {
if (bitmaps != null) {
// Do stuff with your loaded bitmaps
}
}
}.execute(images);
You could increase an integer every time on success until the integer equals to the images.lengh(). You could check this with a loop. And in the loop is an if clause within the return.
For example
int currentSuccess = 0;
In the loop:
#Override
public void onSuccess() {
temp.add(BitmapRes.drawableToBitmap(img.getDrawable()));
movableBackgroundContainer.removeView(img);
currentSuccess++;
}
And for the return:
while(true){
if(currentSuccess == images.length){
return temp.toArray(new Bitmap[temp.size()]);
}
}
Hope that helps.
Related
So the thing is that i want to get Bitmap from absolute path, so i pass those paths as ArrayList<Strings> to my presenter, where i have next piece of code:
private void decodeImageUri(final ArrayList<String> imageUris) {
while(imageCounter < imageUris.size()) {
DecodeBitmapsThreadPool.post(new Runnable() {
#Override
public void run() {
Bitmap bitmap = BitmapFactory.decodeFile(imageUris.get(imageCounter));
mImagesBase64Array.add(bitmapToBase64(bitmap));
}
});
}
DecodeBitmapsThreadPool.finish();
Log.d("SIZE OF BASE64", " ---------- " + mImagesBase64Array.size());
}
And this is my ThreadPool class:
public class DecodeBitmapsThreadPool {
private static DecodeBitmapsThreadPool mInstance;
private ThreadPoolExecutor mThreadPoolExec;
private static int MAX_POOL_SIZE;
private static final int KEEP_ALIVE = 10;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
public static synchronized void post(Runnable runnable) {
if (mInstance == null) {
mInstance = new DecodeBitmapsThreadPool();
}
mInstance.mThreadPoolExec.execute(runnable);
}
private DecodeBitmapsThreadPool() {
int coreNum = Runtime.getRuntime().availableProcessors();
MAX_POOL_SIZE = coreNum * 2;
mThreadPoolExec = new ThreadPoolExecutor(
coreNum,
MAX_POOL_SIZE,
KEEP_ALIVE,
TimeUnit.SECONDS,
workQueue);
}
public static void finish() {
mInstance.mThreadPoolExec.shutdown();
}
}
So when i start ThreadPool it looks like it get in some kind of a endless loop (according to Logcat) and then i just get OutOfMemoryException. I wonder what i`m i doing wrong, since i cant debug it. I simply want to decode the bitmap in background threads and create base64 representation of those Bitmaps, so i can upload them to the server. P.S. Any ideas how can this be implemented with RxJava2? Thanks in advance!
You are not incrementing imageCounter, so it actually is an endless loop.
An enhanced for loop is less error prone:
for (String uri : imageUris) {
...
Bitmap bitmap = BitmapFactory.decodeFile(uri);
...
imageCounter value not changed in while loop,so this condition (imageCounter < imageUris.size()) always true and while loop run infinite times
while(imageCounter < imageUris.size()) {
DecodeBitmapsThreadPool.post(new Runnable() {
#Override
public void run() {
Bitmap bitmap = BitmapFactory.decodeFile(imageUris.get(imageCounter));
mImagesBase64Array.add(bitmapToBase64(bitmap));
}
});
}
The issue is that you don't increment the while loop, so the while loop's condition will never be met. You should increment it at the end of code within the while loop like so:
while(imageCounter < imageUris.size()) {
DecodeBitmapsThreadPool.post(new Runnable() {
#Override
public void run() {
Bitmap bitmap = BitmapFactory.decodeFile(imageUris.get(imageCounter));
mImagesBase64Array.add(bitmapToBase64(bitmap));
}
});
imageCounter++;
}
Though as mentioned in bwt's answer, an enhanced for loop is generally the best approach for these types of tasks.
I'm solving my problem about Image Loader and I have some problems..
What I want is to show many images (about 400) in GridView(or ListView).
I don't want to use the Library like Picasso, Glide like that.
and Here is the problem.
When I call the method which convert from url to bitmap?
3.1. before setAdapter, then pass the bitmap array.
3.2. while getView.
two things are working well. but too much slow... maybe cuz of the times to call URLConnection..
Could anyone help me about these problem? How can I speed up? or are there any other solution without Open Source.
Here is my Source.
Now, 3-1.
ShowImage
private void showImages(ArrayList<String> imgUrls) {
ArrayList<Bitmap> bitmaps = new ArrayList<>();
for (int i = 0; i < imgUrls.size(); i++) {
try {
String img_path = imgUrls.get(i);
Bitmap bitmap = new UriToBitmapAsyncTask().execute(img_path).get();
bitmaps.add(bitmap);
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
CustomAdapter adapter = new CustomAdapter(getApplicationContext(),R.layout.row,bitmaps);
gridView.setAdapter(adapter);
}
and This is the customAdapter's GetView
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = inflator.inflate(rowLayout, parent, false);
viewHolder = new ViewHolder();
viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.imageView.setImageBitmap(bitmaps.get(position));
return convertView;
}
You should really take Reinventing the wheel to heart but if you really want to toture yourself an Approach could be:
use a ThreadPoolExecutor to fetch more images at once, you should read up how to use them
implement a way to cancel threads who load a img for a griditem which isn't displayed anymore
use two sets of data a thumbnail which loads faster for the grid view and a real image which gets loaded when the user clicks on the grid
dont't forget to use a LRU caching method or your device will run out of memory depending on the images
Don't use ArrayList to store bitmaps. Bitmaps usually take consumes a lot of memory. Try using LRUCache like this way,
public class TCImageLoader implements ComponentCallbacks2 {
private TCLruCache cache;
public TCImageLoader(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
int maxKb = am.getMemoryClass() * 1024;
int limitKb = maxKb / 8; // 1/8th of total ram
cache = new TCLruCache(limitKb);
}
public void display(String url, ImageView imageview, int defaultresource) {
imageview.setImageResource(defaultresource);
Bitmap image = cache.get(url);
if (image != null) {
imageview.setImageBitmap(image);
}
else {
new SetImageTask(imageview).execute(url);
}
}
private class TCLruCache extends LruCache<String, Bitmap> {
public TCLruCache(int maxSize) {
super(maxSize);
}
#Override
protected int sizeOf(ImagePoolKey key, Bitmap value) {
int kbOfBitmap = value.getByteCount() / 1024;
return kbOfBitmap;
}
}
private class SetImageTask extends AsyncTask<String, Void, Integer> {
private ImageView imageview;
private Bitmap bmp;
public SetImageTask(ImageView imageview) {
this.imageview = imageview;
}
#Override
protected Integer doInBackground(String... params) {
String url = params[0];
try {
bmp = getBitmapFromURL(url);
if (bmp != null) {
cache.put(url, bmp);
}
else {
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
}
return 1;
}
#Override
protected void onPostExecute(Integer result) {
if (result == 1) {
imageview.setImageBitmap(bmp);
}
super.onPostExecute(result);
}
private Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection
= (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
}
#Override
public void onLowMemory() {
}
#Override
public void onTrimMemory(int level) {
if (level >= TRIM_MEMORY_MODERATE) {
cache.evictAll();
}
else if (level >= TRIM_MEMORY_BACKGROUND) {
cache.trimToSize(cache.size() / 2);
}
}
}
get a instance of TCImageLoader and call display method appropriately.
I redesigned my project by simplifying the code programming. i placed all the images that are static through the xml layout.
i get only 2 results when i run the program.
1) running with no problems
2) running with problems
i get the following error:
Connected to process 10651 on device 4.7_WXGA_API_22 [emulator-5554]
I/art: Not late-enabling -Xcheck:jni (already on)
W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
I believe the problem lies somewhere in this inner class, i think?!
private class MatchCardGame{
private Game mMatchGame;
private List<Drawable> revealImagesOfCards;
private List<Integer> revealCards;
private Drawable hiddenCard;
private List<Integer> cardPoints;
private List< Boolean> isHidden;
public MatchCardGame(int numOfCards){
mMatchGame = new Game(numOfCards);
revealImagesOfCards = new ArrayList<>();
revealCards = new ArrayList<>();
cardPoints = new ArrayList<>();
isHidden = new ArrayList<>();
setCoverCard();
for(int i = 1; i <= numOfCards; i++)
setMatchImageCard(i);
}
public void setMatchImageCard( int cardLoc){
int drawableLoc = mMatchGame.findImageOfCard(cardLoc);
Drawable drawable = ResourcesCompat.getDrawable(getResources(), drawableLoc, null);
Integer revealCard = mMatchGame.findContentsOfCard(cardLoc);
revealImagesOfCards.add(drawable);
revealCards.add(revealCard);
cardPoints.add(Integer.valueOf(20));
Boolean hideCard = true;
isHidden.add(hideCard);
}
private void setCoverCard(){
hiddenCard = ResourcesCompat.getDrawable(getResources(), R.drawable.black_card, null);
}
public Drawable getImage(int loc, boolean statReveal){
loc--;
if(!statReveal){
Boolean hideCard = isHidden.get(loc);
hideCard = true;
return hiddenCard;
}
else {
Boolean hideCard = isHidden.get(loc);
hideCard = false;
return revealImagesOfCards.get(loc);
}
}
public boolean getHiddenStat(int loc){
loc--;
Boolean hideCard = isHidden.get(loc);
return hideCard;
}
public boolean compareCards(int loc1, int loc2){
loc1--;
loc2--;
Integer card1 = revealCards.get(loc1);
Integer card2 = revealCards.get(loc2);
Integer cardPts1 = cardPoints.get(loc1);
Integer cardPts2 = cardPoints.get(loc2);
if(card1 == card2){
int num = Integer.valueOf( scoreText.getText().toString());
Log.i("TAGG","Score Points: " + (cardPts1 + cardPts2));
new AdjustScore().execute(Integer.valueOf(cardPts1 + cardPts2));
return true;
}
else{
cardPts1 -= 5;
cardPts2 -= 5;
if(cardPts1 < 0)
cardPts1 = 0;
if(cardPts2 < 0)
cardPts2 = 0;
cardPoints.set(loc1, cardPts1);
cardPoints.set(loc2,cardPts2);
return false;
}
}
private class AdjustScore extends AsyncTask<Integer,Integer,Void>{
private TextView scoreText;
private int currentScore;
#Override
protected void onPreExecute() {
super.onPreExecute();
scoreText = (TextView) findViewById(R.id.score_txt);
currentScore = Integer.valueOf( scoreText.getText().toString());
}
#Override
protected Void doInBackground(Integer... integers) {
final int num = integers[0];
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int x = 1; x <= num; x++){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(Integer.valueOf(currentScore + x));
}
}
};
new Thread(runnable).start();
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
Message msg = scoreHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString("myPoints",String.valueOf(values[0]));
msg.setData(bundle);
scoreHandler.sendMessage(msg);
}
}
}
I call this in onCreate of activity
private MatchCardGame myGame;
private List<Integer> selectCards;
private TextView scoreText;
private Handler scoreHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
Bundle bundle = msg.getData();
String stat1 = bundle.getString("myPoints");
int num = Integer.valueOf(stat1);
scoreText.setText(String.valueOf(num));
}
};
#Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card_game);
myGame = new MatchCardGame(12);
}
I have another inner class derived from AsynTask.
it is mainly used to setup the card views and set clicklisteners on imageviews. but i don't think it is the problem.
First off, those aren't errors. They're the garbage collector. That's perfectly normal, and shouldn't give you any concern unless you have a performance issue at the same time. Doing something in code rather than in xml to avoid those is unnecessary, and will work or not based on pure luck of when the garbage collector is needed.
Secondly, you're loading all your images in an AsyncTask. Sometimes thats good (it stops you from pausing the main thread to load images), but if you don't have a default image in place, then until that task is done it won't actually be able to display any images. So you have a race condition between drawing and the task finishing.
Solution: do it in xml, or put up a loading screen. I suggest the first, because your task isn't actually doing anything useful if the images are static images from the app- those were loaded when the app launched.
I would like to add some ImageViews to a RelativeLayout view.
The code that I'm using is as follows:
Thread thread = new Thread(new Runnable() {
ArrayList<ImageView> icons = new ArrayList<ImageView>();
#Override
public void run() {
for (int i = 0; i < 20; i++) {
ImageView imageView1 = new ImageView(G.context);
imageView1.setImageResource(R.drawable.music_icon);
imageView1.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT));
imageView1.getLayoutParams().width = (int) convertDpToPixel(20);
imageView1.getLayoutParams().height = (int) convertDpToPixel(20);
icons.add(imageView1);
Log.i("LOG", "Icons Size: " + icons.size());
Log.i("LOG", "I: " + i);
relativeLayout.addView(icons.get(i));
icons.get(i).startAnimation(animationMusic);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
The first time the loop runs fine, but the second time there's an error in the line:
relativeLayout.addView(icons.get(i));
Where is the problem?
One major problem is manipulating the view (e.g. adding a View) from a background thread. You can get similar async behavior by making use of Android's AsyncTask objects and do any UI manipulation from the onPostExecute method.
Without know more about what you're doing, it's hard to find a solution that will work for you. I was mainly pointing out a primary issue with your code.
Here is an attempt to rewrite your code in a way that might work better in an Android environment:
public void addImageViews() {
for(int i = 0; i < 20; i++) {
asyncAdd(i, G.context);
}
}
protected void asyncAdd(final int index, final Context c) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(3000 * index);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
relativeLayout.addView(generateImageView(c));
}
}.execute();
}
protected ImageView generateImageView(Context c) {
ImageView imageView1 = new ImageView(c);
imageView1.setImageResource(R.drawable.music_icon);
imageView1.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT));
imageView1.getLayoutParams().width = (int) convertDpToPixel(20);
imageView1.getLayoutParams().height = (int) convertDpToPixel(20);
return imageView1;
}
In the project universal image loader was used for displaying gridview,viewpager.while I need to integrate the offline mode for app,
I need to download and store images on disc in separate thread and then when displaying gridview ,viewpager images should load from disc.
How to implement universal-image-loader in separate thread? I have tried it but after some time the activity exits it's like the thread and loading universal imageloader exceeds the app cache,I mean somethings goes wrong. I have seen different discussions but I really need to download via UIL in separate thread.
#Override
public void run() {
int x = 0;
while (x < 1) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
processBitmaps();
}
}
public void processBitmaps() {
fulls = Application.getOnThisDeviceFulls();
if (fulls != null && fulls.size() > 0) {
for (int index = 0; index < fulls.size(); index++) {
Full full= fulls.get(index).getFull();
ArrayList<Page> pages =fulls.get(index).getPages();
for (int j = 0; j < pages.size(); j++) {
String pagePattern = ...
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
loadUILImage();
if (j == pages.size() - 1) {
Application.removeFullOnDevice(index);
}
if (resetIndex) {
break;
}
}
if (resetMagazineIndex) {
magazineIndex = 0;
Log.i("magazinethread ", resetIndex + "");
resetIndex = false;
break;
}
}
}
}
The simple example in the documentation works thread based:
// Load image, decode it to Bitmap and return Bitmap to callback
imageLoader.loadImage(imageUri, new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(String imageUri,
View view, Bitmap loadedImage) {
// Do whatever you want with Bitmap
}
});
Use the ImageLoaderConfiguration in order to define particular threading parameters:
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.threadPoolSize(3)
.threadPriority(Thread.NORM_PRIORITY - 2)
...
From the JavaDoc:
public void loadImage(String uri, ImageLoadingListener listener)
Adds load image task to execution pool. Image will be returned with
ImageLoadingListener.onLoadingComplete(String, android.view.View,
android.graphics.Bitmap) callback}. NOTE:
init(ImageLoaderConfiguration) method must be called before this
method call