I'm trying to play two or more gifs in Android Studio. I'm using gif image view, but everytime I try to play more gifs in it, it displays only the last one. I can't find a way to play all of the gifs sequenatally. Any ideas please?
List gifs = Arrays.asList("gif1", "gif2", "gif3");
GifImageView gifView = view.findViewById(R.id.gifView);
for (int i=0; i < gifs.size(); i++) {
String word = gifs.get(i);
int idNum = getResources().getIdentifier(word, "drawable"
getActivity().getPackageName());
gifView.setImageResource(idNum);
}
Since you are using a loop to load gifs into the view, all gifs except the last one will be overwritten on each iteration, you should load the next gifs only after completely playing the gif.
Here is an example of achieving this using Glide and ImageView
public class MainActivity extends AppCompatActivity {
int gifLoaded = 0;
List gifs = Arrays.asList("https://i.kym-cdn.com/photos/images/newsfeed/001/708/675/4b5.gif",
"https://c.tenor.com/tOH34YVvpq4AAAAC/malayalam.gif",
"https://c.tenor.com/AKtcHf4ZTAsAAAAC/malayalam-kerala.gif"
);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadImage();
}
private void loadImage() {
if (gifLoaded > gifs.size() - 1) {
gifLoaded = 0;
}
String url = (String) gifs.get(gifLoaded);
ImageView giv = findViewById(R.id.iv_gif);
Glide.with(this).asGif().load(url).listener(new RequestListener<GifDrawable>() {
#Override
public boolean onLoadFailed(#Nullable GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) {
resource.setLoopCount(1);
resource.registerAnimationCallback(new Animatable2Compat.AnimationCallback() {
#Override
public void onAnimationEnd(Drawable drawable) {
gifLoaded++;
loadImage();
}
});
return false;
}
}).into(giv);
}
}
Related
For creating image slide show , I want to use image switcher with timer .
I read this blog post it's very clear but it doesn't load images from network .
Now i want load images from network with Glide Library .
This is MainActivity :
public class MainActivity extends Activity {
private ImageSwitcher imageSwitcher;
private int[] gallery = { http://www.helloworld.com/image1.png, http://www.helloworld.com/image2.png, http://www.helloworld.com/image3.png,
http://www.helloworld.com/image4.png, };
private int position;
private static final Integer DURATION = 2500;
private Timer timer = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageSwitcher = (ImageSwitcher) findViewById(R.id.imageSwitcher);
imageSwitcher.setFactory(new ViewFactory() {
public View makeView() {
return new ImageView(MainActivity.this);
}
});
// Set animations
// https://danielme.com/2013/08/18/diseno-android-transiciones-entre-activities/
Animation fadeIn = AnimationUtils.loadAnimation(this, R.anim.fade_in);
Animation fadeOut = AnimationUtils.loadAnimation(this, R.anim.fade_out);
imageSwitcher.setInAnimation(fadeIn);
imageSwitcher.setOutAnimation(fadeOut);
}
// ////////////////////BUTTONS
/**
* starts or restarts the slider
*
* #param button
*/
public void start(View button) {
if (timer != null) {
timer.cancel();
}
position = 0;
startSlider();
}
public void stop(View button) {
if (timer != null) {
timer.cancel();
timer = null;
}
}
public void startSlider() {
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
// avoid exception:
// "Only the original thread that created a view hierarchy can touch its views"
runOnUiThread(new Runnable() {
public void run() {
imageSwitcher.setImageResource(gallery[position]);
position++;
if (position == gallery.length) {
position = 0;
}
}
});
}
}, 0, DURATION);
}
// Stops the slider when the Activity is going into the background
#Override
protected void onPause() {
super.onPause();
if (timer != null) {
timer.cancel();
}
}
#Override
protected void onResume() {
super.onResume();
if (timer != null) {
startSlider();
}
}
}
I try to load images with glide but i don't know what should i do .
It's pretty easy to do, all you need is to load image using Glide to the ImageView that you can get from ImageSwitcher by method imageSwitcher.getCurrentView(). So you need to replace code inside run of your runOnUiThread method to the next code:
Glide.with(MainActivity.this)
.load(gallery[position])
.asBitmap()
.listener(new RequestListener<String, Bitmap>() {
#Override
public boolean onException(Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(Bitmap resource, String model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
position++;
if (position == gallery.length) {
position = 0;
}
imageSwitcher.setImageDrawable(new BitmapDrawable(getResources(), resource));
return true;
}
}).into((ImageView) imageSwitcher.getCurrentView());
Also don't forget to replace your image urls with appropriate urls (you now have there some dummy urls I see). So your gallery array should be a String[] array.
Don't forget also to include android.permission.INTERNET to your AndroidManifest.xml.
And finally you need to change android:layout_width property of your ImageSwitcher to match_parent in xml as Glide won't load image in it otherwise.
I think the approved answer is great but it is missing something key.
When they update the current image, this is basically just replacing the one in view. This means we might as well not use the ImageSwitcher at all. What we need to do, is update the next view and then show it. This will allow us to also see any transition effects we have added.
I have separated all this logic out within my own code to make it clean, but here it is in RAW form.
Setting up of your ImageSwitcher
Animation in = AnimationUtils.loadAnimation(this,android.R.anim.fade_in);
Animation out = AnimationUtils.loadAnimation(this,android.R.anim.fade_out);
imageSwitcher.setFactory(() -> {
ImageView imageView = new ImageView(getApplicationContext());
imageView.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
));
return imageView;
});
imageSwitcher.setInAnimation(in);
imageSwitcher.setOutAnimation(out);
Call this to then update the next image
RequestOptions requestOptions = new
RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL);
Bitmap nextImage = getAppropriateImage();
GlideApp.with(this)
.load(nextImage)
.apply(requestOptions)
.into((ImageView) imageSwitcher.getNextView());
imageSwitcher.showNext();
I used the version of #rom4ek but I had some crash:
Fatal Exception: java.lang.RuntimeException
Canvas: trying to use a recycled bitmap android.graphics.Bitmap#7ad49c4
I think that this is because the drawable is not set into the same ImageView passed to into(...).
I changed it to use the "next view". We have to set the visibility from GONE to INVISIBLE for Glide.
imageSwitcher.getNextView().setVisibility(View.INVISIBLE);
Glide.with(...)
.load(url)
.listener(new RequestListener<String, Bitmap>() {
#Override
public boolean onException(Exception e, String model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(Drawable resource, String model, Target<Drawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
imageSwitcher.setImageDrawable(resource);
return true;
}
}).into((ImageView) imageSwitcher.getNextView());
Kotlin version:
it.nextView.visibility = View.INVISIBLE
Glide.with(...)
.load(url)
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
return false
}
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
it.setImageDrawable(resource)
return true
}
})
.into(it.nextView as ImageView)
I have this method, everything is worked perfectly but images always got from server and not load from cache! what happened ?
public static void makeImageRequest(String Unique_ID, final View parentView, final int id) {
String url = FILE_UPLOAD_FOLDER + Unique_ID + ".png";
final int defaultImageResId = R.drawable.user;
// Retrieves an image specified by the URL, displays it in the UI.
ImageCacheManager.getInstance().getImage(url, new ImageListener() {
#Override
public void onErrorResponse(VolleyError error) {
ImageView imageView = (ImageView) parentView.findViewById(id);
imageView.setImageResource(defaultImageResId);
}
#Override
public void onResponse(ImageContainer response, boolean isImmediate) {
if (response.getBitmap() != null) {
ImageView imageView = (ImageView) parentView.findViewById(id);
imageView.setImageBitmap(response.getBitmap());
} else if (defaultImageResId != 0) {
ImageView imageView = (ImageView) parentView.findViewById(id);
imageView.setImageResource(defaultImageResId);
}
}
});
}
Just use Picasso instead ImageCacheManager. Picasso is a powerful image downloading and caching library for Android. Images add much-needed context and visual flair to Android applications. Picasso allows for hassle-free image loading in your application—often in one line of code!
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Here also can manage whether the image is successfully downloaded or it fails:
Picasso.with(context)
.load("http://i.imgur.com/DvpvklR.png")
.into(imageView, new Callback() {
#Override
public void onSuccess() {
// your code
}
#Override
public void onError() {
// your code
}
});
You should only add this line in your gradle:
compile 'com.squareup.picasso:picasso:2.5.2'
Hope it helps!
I wanna retrieve images in Picasso for later and keep them in cache, at the moment I use this code:
for(int i=0; i<urlList.size(); i++) {
Picasso.with(getActivity())
.load(url.get(i))
.fetch();
}
but I wanna retrieve them sequentially. What's the best for that?
You can load the image into a Target, if you have an array of your urls you can recursively load them from the Target.
Example activity that does this:
public class MainActivity extends ActionBarActivity{
private ArrayList<String> urls;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
urls = new ArrayList<>();
urls.add("http://placehold.it/300&text=0");
urls.add("http://placehold.it/300&text=1");
urls.add("http://placehold.it/300&text=2");
urls.add("http://placehold.it/300&text=3");
urls.add("http://placehold.it/300&text=4");
loadImages(0);
}
private void loadImages(final int index){
Target t = new Target(){
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from){
Log.w("image", "image received" + index);
loadImages(index + 1);
}
#Override
public void onBitmapFailed(Drawable errorDrawable){
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable){
}
};
if(index < urls.size())
Picasso.with(this)
.load(urls.get(index))
.into(t);
}
}
I want to load large bitmaps efficiently in my Image Switcher and i have been using Picasso for this purpose but now i am stuck at this point. Without Picasso a lot of OOMs and other nasty exceptions please tell me if I can use this library with Image Switcher too.
If yes then provide sample code.
Thanks!
imswitch.setFactory(new ViewFactory() {
#Override
public View makeView() {
ImageView imageView = new ImageView(getApplicationContext());
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
return imageView;
}
} );
And onClick:
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
currentIndex++;
// If index reaches maximum reset it
if(currentIndex==messageCount)
currentIndex=0;
ImageView imageView = (ImageView)findViewById(R.id.imswitch);
Picasso.with(getApplicationContext()).load(imageIds[currentIndex]).into(imageView);
Toast.makeText(getApplicationContext(), "Pressed "+currentIndex,Toast.LENGTH_LONG).show();
}
One of the possible way is to create own implementation using Target interface.
https://square.github.io/picasso/javadoc/com/squareup/picasso/Target.html
public class ImageSwitcherPicasso implements Target {
private ImageSwitcher mImageSwitcher;
private Context mContext;
public ImageSwitcherPicasso(Context context, ImageSwitcher imageSwitcher){
mImageSwitcher = imageSwitcher;
mContext = context;
}
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
mImageSwitcher.setImageDrawable(new BitmapDrawable(mContext.getResources(), bitmap));
}
#Override
public void onBitmapFailed(Drawable drawable) {
}
#Override
public void onPrepareLoad(Drawable drawable) {
}
}
Than just use as follow
ImageSwitcherPicasso mImageSwitcherPicasso = new ImageSwitcherPicasso(getActivity(), playerBackground);
Picasso.with(getActivity()).load(new File(path)).into(mImageSwitcherPicasso);
where playerBackground is reference to ImageSwitcher
In my Android application I would like to download a certain number of photos which are linked to points on a map. For example, I have ten points on a map and I have 5 or 6 photos for each point.
At the begining I get 5 or 6 URL (http://theimageurls.com/image.jpg) per point, and for each photo,
I want to download them
I want to save them in the device.
Of course, everything's done in background.
The problem is that sometimes my images are not persisted... but the problem is very irregular and can be encountered on whatever image...
here is my code :
For each point, loadPictures() is called :
private void loadPictures(final KickstartrGeolocPoint point) {
//Photos : get directory path
final File pointDir = FileUtils.getPointPhotoDir(getActivity(), point);
//set boolean to true if the point has photos not downloaded.
ArrayList<String> photosNotDownloaded = getPhotosNotDownloaded(point, pointDir);
if(photosNotDownloaded.size()!=0){
point.setPhoto(true);
kickstartrGeolocService.updatePoint(currentPoint);
}else{
fillPointData(point);
return;
}
//for each urls, download and save photo
for(final String url : photosNotDownloaded){
if (!Utils.isValidUrl(url)) continue;
BitmapUtils.getBitmapFromUrl(url, new OnBitmapRetrievedListener() {
#Override
public void bitmapRetrieved(Bitmap bitmap) {
LogWrapper.debug(getClass(), "Ready to be saved");
persistImageforPoint(point, pointDir, bitmap, FileUtils.getFileNameFromUrl(url));
}
#Override
public void onLoadingStarted(String imageUri, View view) {
LogWrapper.debug(getClass(), "Image downloading... " + imageUri);
//YOU CAN NOTIFY THE VIEW HERE
}
#Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
LogWrapper.debug(getClass(), "Loading failed : " + imageUri);
}
});
}
}
getBitmapFromUrl() is a static method which use an external library called https://github.com/nostra13/Android-Universal-Image-Loader.
getBitmapFromUrl() :
public static void getBitmapFromUrl(String url, final OnBitmapRetrievedListener listener) {
//final int maxSize = context.getResources().getDimensionPixelSize(R.dimen.icon_max_size);
ImageLoader.getInstance().loadImage(url, new ImageLoadingListener() {
#Override
public void onLoadingStarted(String imageUri, View view) {
listener.onLoadingStarted(imageUri,view);
}
#Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
listener.onLoadingFailed(imageUri,view,failReason);
}
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
listener.bitmapRetrieved(loadedImage);
}
#Override
public void onLoadingCancelled(String imageUri, View view) {
//do nothing for the moment...
// TODO notify the UI
}
});
}
persistImageforPoint() is called to save the photo :
private void persistImageforPoint(KickstartrGeolocPoint point, File pointDir, Bitmap bitmap, String imageName) {
// Create a subfolder for each point with its id
if (!pointDir.exists()) {
if (!pointDir.mkdirs()) {
LogWrapper.debug(FileUtils.class, "Failed to create directory");
return;
}
}
final String fullPath = pointDir.getPath()+File.separator+FileUtils.getPointPhotoPrefix(point)+FileUtils.getFileNameFromUrl(imageName);
//save the file. Asynchronous task --> do not block the UI
new BitmapPersist(bitmap,fullPath, new OnBitmapPersistedListener() {
#Override
public void persistedSuccessfully() {
addPhotoView(fullPath);
}
#Override
public void errorInPersistance() {
LogWrapper.error(getClass(),"Error persisting image with path "+fullPath);
}
}).execute();
}
Here is my BitmapPersist class :
public class BitmapPersist extends AsyncTask<String, Void, Boolean> {
private String path;
private Bitmap bitmap;
private OnBitmapPersistedListener onBitmapPersistedListener;
public BitmapPersist(Bitmap bitmap, String path, OnBitmapPersistedListener onBitmapPersistedListener) {
this.bitmap=bitmap;
this.path=path;
this.onBitmapPersistedListener=onBitmapPersistedListener;
}
#Override
protected Boolean doInBackground(String... params) {
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try{
out.close();
} catch(Throwable ignore) {}
}
return false;
}
#Override
protected void onPostExecute(Boolean success) {
if (success)
onBitmapPersistedListener.persistedSuccessfully();
onBitmapPersistedListener.errorInPersistance();
}
}
Problem : Sometimes my pictures are not saved, sometimes the application crashes... although everything's done in background threads...
Thanks for your help.
EDIT : Maybe I can add precisions on the library I'm using to download images : It's Android-Universal-Image-Loader (link above). This library works with memory cache and... disk cache. Maybe I can look at this cache. Maybe I can change the path of disk cache and save my pictures with that. I'm also looking for someone who knows this library (developped by NOSTRA)... The documentation is quite succinct...
SOLUTION : Don't need to create 2 Asynctasks : Download the picture synchronously and then persist it in the same asynctask.