RecyclerView lags in scrolling - java

I have a recyclerview with cardview in it. Also having imageview, textview. I am decoding my images using Base64 decoding scheme and displaying images within the cardview.It loads the images but producing the lag effect
onBindViewHolder code
holder.iv_contestant_image.setImageBitmap(new ProcessImage().getBitmage(contestant.getContestant_image()));
ProcessImage code
byte[] decodedString = Base64.decode(strBitmap, Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
return decodedByte;
Is something wrong am I doing ?

you can use any image loading libraries. Some of libraries are Picasso Glide Fresco

I do believe decoding process is not instant depending on the size of the bitmap. So, try perform decoding bitmap with AsyncTask
class BitmapWorkerTask extends AsyncTask<Void, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private String base64Img;
public BitmapWorkerTask(ImageView imageView, String base64Img) {
imageViewReference = new WeakReference<ImageView>(imageView);
this.base64Img = base64Img;
}
#Override
protected Bitmap doInBackground(Void... params) {
byte[] decodedString = Base64.decode(base64Img, Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
return decodedByte;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
imageViewReference.get().setImageBitmap(bitmap);
}
}
Inside onBindViewHolder
new BitmapWorkerTask(holder.iv_contestant_image, stringBitmap).execute();

you can implement lazy image loading in your recycle view for fix this issue. http://blogs.innovationm.com/lazy-loading-and-memory-management-of-images-in-listview-in-android/

Related

Cannot resolve method 'getdrawable()

I'm a newbie in programming. I want to build a QR Code Generator that the QR Code can be saved or downloaded.
Here's my code for the generator:
public class GeneratorActivity extends AppCompatActivity {
EditText text;
Button gen_btn;
ImageView image;
String text2Qr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_generator);
text = findViewById(R.id.text);
gen_btn = findViewById(R.id.gen_btn);
image = findViewById(R.id.image);
gen_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
text2Qr = text.getText().toString().trim();
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
try{
BitMatrix bitMatrix = multiFormatWriter.encode(text2Qr, BarcodeFormat.QR_CODE,200,200);
BarcodeEncoder barcodeEncoder = new BarcodeEncoder();
Bitmap bitmap = barcodeEncoder.createBitmap(bitMatrix);
image.setImageBitmap(bitmap);
bitmap = ((BitmapDrawable) ImageView.getdrawable()).getBitmap();
}
catch (WriterException e){
e.printStackTrace();
}
}
});
}
}
I got a error that I cannot resolve method 'getdrawable()
anybody know how to fix this?
Here's the screenshot of the error: screenshot
get the drawable like from imageview like
Drawable myDrawable = imageView.getDrawable();
You can compare it with a drawable resource like
if(iv.getDrawable()==getResources().getDrawable(R.drawable.image1)){
//do work here
}
getDrawable
Return a drawable object associated with a particular resource ID and
styled for the specified theme.
You should pass OBJECT
bitmap = ((BitmapDrawable) image.getDrawable()).getBitmap();
FYI
Drawable drawable = image.getDrawable();
You already have a bitmap and you have set it to imageview. Why do you need this line
bitmap = ((BitmapDrawable) ImageView.getdrawable()).getBitmap();
The error is saying that there is no method called getDrawable() in the ImageView class.
I think you can use it Bitmap bitmap = barcodeEncoder.createBitmap(bitMatrix);directly. may be not need bitmap = ((BitmapDrawable) image.getdrawable()).getBitmap();
You are getting drawable from empty imageview that will return null. for getting bitmap from drawble, try this method.
public static Bitmap drawableToBitmap (Drawable drawable) {
Bitmap bitmap = null;
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if(bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
Hope it will help you!!

RenderScript blur overrides the original Bitmap

I am trying to use RenderScript to create a blurred bitmap to set it as a background for a LinearLayout which contains an ImageView. I also want a clear original copy of the bitmap so that I can set it as an image in the ImageView.
Here's my code:
ImageView mainImage;
Bitmap mainBMP, blurredBMP
LinearLayout background;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_work_area);
getImage(); // obtain bitmap from file
mainImage.setImageBitmap(mainBMP); // set the original bitmap in imageview
// create a blurred bitmap drawable and set it as background for linearlayout
BitmapDrawable drawable = new BitmapDrawable(getResources(), blur(mainBMP));
mainBackground.setBackground(drawable);
registerForContextMenu(objectImage);
registerForContextMenu(textArea);
}
private void getImage(){
String filename = getIntent().getStringExtra("image");
try {
FileInputStream is = this.openFileInput(filename);
mainBMP = BitmapFactory.decodeStream(is);
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
#TargetApi(17)
public Bitmap blur(Bitmap image) {
if (null == image) return null;
Bitmap outputBitmap = Bitmap.createBitmap(image);
final RenderScript renderScript = RenderScript.create(this);
Allocation tmpIn = Allocation.createFromBitmap(renderScript, image);
Allocation tmpOut = Allocation.createFromBitmap(renderScript, outputBitmap);
//Intrinsic Gausian blur filter
ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
theIntrinsic.setRadius(BLUR_RADIUS);
theIntrinsic.setInput(tmpIn);
theIntrinsic.forEach(tmpOut);
tmpOut.copyTo(outputBitmap);
return outputBitmap;
}
This is how I want the final result to be:
But this is what I get:
So how do I make two copies of the same bitmap in which one of them is blurred and the other is clear and original?
The problem is with how the output bitmap is being created. You're using a call that gives you an immutable Bitmap object based on an input Bitmap object. Change this line:
Bitmap outputBitmap = Bitmap.createBitmap(image);
to be this:
Bitmap outputBitmap = image.copy(image.getConfig(), true);
That will give you a separate Bitmap object which is a copy of the original and mutable. Right now Renderscript is really modifying the original (though it really should fail because the outputBitmap was immutable.

Android image didn't display to ImageView from image URL

I want to display image to ImageView from "http://i.imgur.com/4GLKF4Q.jpg" but The image in image URL didn't display to imageview. Can I do this?
AsyncTask
class DownloadImageTask extends AsyncTask<String, Void, byte[]> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected byte[] doInBackground(String... urls) {
try {
URL url = new URL(urls[0]);
InputStream is = (InputStream) url.getContent();
byte[] buffer = new byte[8192];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
while ((bytesRead = is.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
return output.toByteArray();
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
protected void onPostExecute(byte[] result) {
ByteArrayInputStream imageStream = new ByteArrayInputStream(result);
Bitmap bm = BitmapFactory.decodeStream(imageStream);
bmImage.setImageBitmap(bm);
}
}
in activity
new DownloadImageTask((ImageView) newView.findViewById(R.id.thumbnail))
.execute("http://i.imgur.com/4GLKF4Q.jpg");
The image in image URL didn't display to imageview.
in Logcat :
09-23 10:26:49.410 10591-10591/com.*** D/skia: --- SkImageDecoder::Factory returned null
Update from comment : changing image server to another one solve the issue. I guess it's a i.imgur.com issue.
You shouldn't use your own image loader task, it will leak somewhere.
Two good library exist :
- Fresco (from Facebook)
- Picasso (from Square up)
There is also UniversalImageLoader (UIL).
I would suggest you to checkout Image Management Library by Facebook that is Fresco that is pretty awesome and mature as compared to other Image Loading Library.
Fresco handles all the things caching of images with 3 Tier architecture ( BITMAP_MEMORY_CACHE, ENCODED_MEMORY_CACHE and DISK_CACHE). It also reduces OOM(Out Of Memory) issues. When image in a view goes out of screen it automatically recycles the bitmap, hence releasing the memory.
Now there is an official way to load an ImageView from a URL and that is NOT to use an ImageView.
NetworkImageView—builds on ImageLoader and effectively replaces ImageView for situations where your image is being fetched over the network via URL. NetworkImageView also manages canceling pending requests if the view is detached from the hierarchy.
Images are automatically loaded in a background thread and the view updated on the UI thread. It even supports caching.

Android set bitmap to Imageview

Hi i have a string in Base64 format. I want to convert it ot a bitmap and then display it to an ImageView. This is the code:
ImageView user_image;
Person person_object;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_profile_screen);
// ImageViews
user_image = (ImageView) findViewById(R.id.userImageProfile);
Bundle data = getIntent().getExtras();
person_object = data.getParcelable("person_object");
// getPhoto() function returns a Base64 String
byte[] decodedString = Base64.decode(person_object.getPhoto(), Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
user_image.setImageBitmap(decodedByte);
}
This code get the Base64 String successfully and i do not get any error. But It does not display the image.
What can be the problem?
Thanks
Please try this:
byte[] decodedString = Base64.decode(person_object.getPhoto(),Base64.NO_WRAP);
InputStream inputStream = new ByteArrayInputStream(decodedString);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
user_image.setImageBitmap(bitmap);
//decode base64 string to image
imageBytes = Base64.decode(encodedImage, Base64.DEFAULT);
Bitmap decodedImage = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
image.setImageBitmap(decodedImage);
//setImageBitmap is imp
There is a library named Picasso which can efficiently load images from a URL. It can also load an image from a file.
Examples:
Load URL into ImageView without generating a bitmap:
Picasso.with(context) // Context
.load("http://abc.imgur.com/gxsg.png") // URL or file
.into(imageView); // An ImageView object to show the loaded image
Load URL into ImageView by generating a bitmap:
Picasso.with(this)
.load(artistImageUrl)
.into(new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
/* Save the bitmap or do something with it here */
// Set it in the ImageView
theView.setImageBitmap(bitmap)
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
There are many more options available in Picasso. Here is the documentation.
this code works with me
ImageView carView = (ImageView) v.findViewById(R.id.car_icon);
byte[] decodedString = Base64.decode(picture, Base64.NO_WRAP);
InputStream input=new ByteArrayInputStream(decodedString);
Bitmap ext_pic = BitmapFactory.decodeStream(input);
carView.setImageBitmap(ext_pic);

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