I am working on an Android application where I deliver some built-in images and give the user the option to download some more from the web to use in the application. At some point in my app, I look at an ImageView in my layout and want to determine if the Drawable inside is an in-built resource or an image I have downloaded from the web to the SD Card.
Is there any way to extract the URI of the Drawable used in the ImageView? This way I would be able to see if it is a resource or a downloaded file.
Here is my code so far:
ImageView view = (ImageView) layout.findViewById(R.id.content_img);
Drawable image = view.getDrawable();
UPDATE:
Using Barry Fruitman's suggestion from below, I stored the URI of the image directly inside my custom ImageView for later use. Here is what my implementation looks like:
public class MemoryImageView extends ImageView {
private String storedUri = null;
public MemoryImageView(Context context, String Uri) {
super(context);
}
public MemoryImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MemoryImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public String getStoredUri() {
return storedUri;
}
public void setStoredUri(String storedUri) {
this.storedUri = storedUri;
}
}
And usage looks like this:
MemoryImageView view = (MemoryImageView) layout.findViewById(R.id.content_img);
String img = view.getStoredUri();
if(img.startsWith("android.resource")) {
//in-built resource
} else {
//downloaded image
}
No. Once you create the Drawable that information is lost. What I suggest you do is subclass the ImageView and add extra member(s) to keep track of whatever you want.
Replace:
<ImageView />
with
<com.mypackage.MyImageView />
And create:
class MyImageView extends ImageView {
protected final int LOCAL_IMAGE = 1;
protected final int REMOTE_IMAGE = 2;
protected int imageType;
}
MyImageView will behave exactly like an ImageView, but with that extra member that you can read and write anywhere you want. You will probably also have to override the ImageView contructor(s) with constructors that just call super().
Related
My Question is about loading image into image View With Glide. I Know How to Load Image With Glide. But I want to Create a custom ImageView so that It can Load Images By Default With Glide (To make it faster and remove memory issues by default). Is It Possible. If Yes Then How? Thank you in advance.
public class CustomImageView extends ImageView {
public CustomImageView(Context context) {
super(context);
}
///How to Over Ride Back Ground Attribute Sent by XML / Sent By Java Initialization
Glide.with(context).load(R.drawable.chains).into(this);
}
Update:
To be very simple I want To Use My Custom ImageView in my whole project Instead of Ordinary one. so that it will over come memory issues by default. In CustomImageView I want to Load Images with Glide . I'm Looking something Like
public class CustomImageView extends ImageView {
public CustomImageView(Context context) {
super(context);
}
///How to Over Ride Back Ground Attribute Sent by XML / Sent By Java Initialization
#Override
public void setBackground(Drawable background) {
super.setBackground(background);
Glide.with(this.getContext()).load(background).into(this);
}
}
how to manage CustomImageView to work exactly like ImageView but Instead load Images With Glide.
Try something like this:
public class CustomImageView extends android.support.v7.widget.AppCompatImageView {
public CustomImageView(Context context) {
super(context);
}
public CustomImageView(Context context, #Nullable AttributeSet set) {
super(context, set);
int[] attrs = {android.R.attr.background};
TypedArray typedArray = context.obtainStyledAttributes(set, attrs);
Drawable drawable = typedArray.getDrawable(0); // 0 is an index of attrs[]
if (drawable != null) {
setBackground(null);
Glide.with(context).load(typedArray.getResourceId(0, placeholder_resource_id)).into(this); // 0 is an index of attrs[]
}
typedArray.recycle();
}
}
the question is about imageview in android:
There is an imageview, after I call method like
imageview.setImageDrawable(drawable)
or
imageview.setImageBitmap(bitmap)
then a drawable will be drawned on the imageview, I want to know that before I call another setXXXDrawable/Bitmap method to the same imageview , the drawable that had been drawned on this imageview has or has not been changed by other operation? or the image showned on the imageview has been changed since my last call?
Any help will be appreciated~ thks!
You can create your own ImageView to detect image changes , Here is the class from Sandy's answer , try with it , setImageChangeListner() to detect image changes .
public class MyImageView extends ImageView {
private OnImageChangeListiner onImageChangeListiner;
public MyImageView(Context context) {
super(context);
}
public MyImageView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
public void setImageChangeListiner(
OnImageChangeListiner onImageChangeListiner) {
this.onImageChangeListiner = onImageChangeListiner;
}
#Override
public void setBackgroundResource(int resid) {
super.setBackgroundResource(resid);
if (onImageChangeListiner != null)
onImageChangeListiner.imageChangedinView(this);
}
#Override
public void setBackgroundDrawable(Drawable background) {
super.setBackgroundDrawable(background);
if (onImageChangeListiner != null)
onImageChangeListiner.imageChangedinView(this);
}
public static interface OnImageChangeListiner {
public void imageChangedinView(ImageView mImageView);
}
}
Reference Link : ImageView onImageChangedListener Android
First get the drawable from imageView.getDrawable() method and get bimap from that drawable that you just got. Now compare these both bitmaps to identify that you have both same image or image has been changed. Both will have same bytes if they will be same.
You can check whether an image has been assigned a drawable or not as follows :
if(imageView.getDrawable() != null) {
// you can get the drawable that has been assigned to it
} else {
// assign the desired drawable
imageview.setImageDrawable(drawable)
}
I extended the class ImageView and added some custom parameters. I succeed to get these custom parameters from my code, using the method Context.getTheme().obtainStyledAttributes().
What I need is to access the standard parameters of the ImageView object, such as android:src and android:background. I know it exist the class android.R.styleable.* which I could use to get those parameters, but that class has been deprecated (and is not visible anymore). What can I do to access those android parameters?
While I’m not sure how to extract parent values from a TypedArray, you’re able to access them with appropriate getters, e.g.:
public class MyImageView extends ImageView {
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.whatever);
try {
// get custom attributes here
} finally {
array.recycle();
}
// parent attributes
final Drawable background = getBackground();
final Drawable src = getDrawable();
// etc.
}
}
It's not exactly what you're looking for, but it might help.
long time reader, first time asker so please be gently ;)
I have an Android code that displays around 10 pictures in second on ImageView.
(calling setImageBitmap on ImageView to set new bitmap)
This causes display lags so I'm trying to speed it as much as I can.
I found that (with traceview) that app spend a lot of time on methods:
ViewRoot.performTraversals
View.measure
FrameLayout.onmeasure
ViewGrou.measureChildWithMargins
I suspecting on ImageView measuring so i have create CustomImageView and overide onMeasure just to call super method and write sysout.
It seems that after every setImageBitmap onmeasure is called 3 times.
Bitmaps are allways of the same size so there is no change. Actually it can be change from time to time when image source is changed but that should be remeasured only then.
What can I change, overide, do to eliminite this measurement impact on application speed?
If you need further information tell me and I will provide it.
Sample code
final Bitmap bitmapScaled = Bitmap.createScaledBitmap(bitmap2, width, height, false);
imageView2.setScaleType(ScaleType.CENTER_INSIDE);
if (setSize) {
setSize(imageView2, width, height);
}
imageView2.setImageBitmap(bitmapScaled);
Method that I change to make it work faster (possibly not safe?!)
boolean layout=true;
int noL=1;
#Override
public void requestLayout() {
if (layout){
super.requestLayout();
if (noL>10){
layout=false;
}else{
noL++;
}
}
}
When I had a similar problem I did the following:
public class ImageViewEx extends ImageView{
private boolean makeRequest;
public ImageViewEx(Context context){
super(context);makeRequest=true;
}
public ImageViewEx(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ImageViewEx(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
makeRequest=true;
}
public void setImageBitmapNoRequestLayout(Bitmap bitmap) {
makeRequest = false;
setImageBitmap(bitmap);
makeRequest = true;
}
#Override public void requestLayout(){
if(makeRequest)super.requestLayout();
}
}
Now changing the bitmap with setImageBitmapNoRequestLayout(...) does not call requestLayout().
Is there any way to get the Drawable resource ID? For example, I am using an ImageView and I may initially use icon.png as its image but later I may change the image to icon2.png. I want to find out using the code that which image my ImageView is using from the resource. Is there any way?
This one is the best method to find out the R.drawable.img1 value when u click on the ImageView in your program. The method is something like that
in main program. First of all save the image value in the tag like that
public...activity
{
//-----this resource name is retrieved through the tag value of the drawable of (touched) ImageView //image ontouchlistener event...
ImageView imgview1.setTag("img1"); //as of R.drawable.img1
ImageView imgview2.setTag("img2"); //as of R.drawable.img2
onTouchListnener event... on imageView
{
Object tag = imageView.getTag();
int id = getResources().getIdentifier( tag, "drawable", this.getPackageName() );
switch(id)
{
case R.drawable.img1:
//do someoperation of ur choice
break;
case R.drawable.img2:
//do someoperation of ur choice
break:
}//end of switch
}//end of touch listener event
}//end of main activity
"PIR FAHIM SHAH/kpk uet mardan campus"
Are you trying to determine what the current image is on the imageview, in order to change it to some other image?
If that's so I suggest doing everything using code instead of xml.
i.e. Use setImageResource() to set the initial images during initialization and keep track of the resource ids being used somewhere in your code.
For example, you can have an array of imageviews with a corresponding array of int that contains the resource id for each imageview
Then, whenever you want to change the image, loop through the array and see what the id is.
Create a custom imageview, the rest is simple.
public class CustomImageView extends ImageView {
private int resID;
public CustomImageView(Context context) {
super(context);
}
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void setImageResource(int resId) {
this.resID = resId;
super.setImageResource(resId);
}
public int getResourceId() {
return resID;
}
}
There are a few steps to this:
create integer-array xml to hold names of drawables (ie: "#drawable/icon1" ... "#drawable/iconN"
use getIdentifier above to get the "array"
with ID for list of drawable, getStringArray will give you an array names of drawables you specified in step 1.
then use any of the drawable name in the array with getIdentifier again to get the drawable ID. This use "drawable" instead of "array" type.
use this ID to set image for your view.
HOpe this will help.
I now that the question is pretty old, but maybe someone will find it useful.
I have a list of TextViews with Drawables and want to set click listeners for all of them, without any need to change the code, when the layout is changed.
So I've put all drawables into a hashmap to get their ids later.
main_layout.xml
<LinearLayout android:id="#+id/list" >
<TextView android:drawableLeft="#drawable/d1" />
<TextView android:drawableLeft="#drawable/d2" />
<TextView android:drawableLeft="#drawable/d3" />
<TextView android:drawableLeft="#drawable/d4" />
<!-- ... -->
</LinearLayout>
MyActivity.java
import java.lang.reflect.Field;
import java.util.HashMap;
import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MyActivity extends Activity {
private final HashMap<ConstantState, Integer> drawables = new HashMap<ConstantState, Integer>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
for (int id : getAllResourceIDs(R.drawable.class)) {
Drawable drawable = getResources().getDrawable(id);
drawables.put(drawable.getConstantState(), id);
}
LinearLayout list = (LinearLayout)findViewById(R.id.list);
for (int i = 0; i < list.getChildCount(); i++) {
TextView textView = (TextView)list.getChildAt(i);
setListener(textView);
}
}
private void setListener(TextView textView) {
// Returns drawables for the left, top, right, and bottom borders.
Drawable[] compoundDrawables = textView.getCompoundDrawables();
Drawable left = compoundDrawables[0];
final int id = drawables.get(left.getConstantState());
textView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
Intent broadcast = new Intent();
broadcast.setAction("ACTION_NAME");
broadcast.putExtra("ACTION_VALUE", id);
sendBroadcast(broadcast);
}
});
}
/**
* Retrieve all IDs of the Resource-Classes
* (like <code>R.drawable.class</code>) you pass to this function.
* #param aClass : Class from R.X_X_X, like: <br>
* <ul>
* <li><code>R.drawable.class</code></li>
* <li><code>R.string.class</code></li>
* <li><code>R.array.class</code></li>
* <li>and the rest...</li>
* </ul>
* #return array of all IDs of the R.xyz.class passed to this function.
* #throws IllegalArgumentException on bad class passed.
* <br><br>
* <b>Example-Call:</b><br>
* <code>int[] allDrawableIDs = getAllResourceIDs(R.drawable.class);</code><br>
* or<br>
* <code>int[] allStringIDs = getAllResourceIDs(R.string.class);</code>
*/
private int[] getAllResourceIDs(Class<?> aClass) throws IllegalArgumentException {
/* Get all Fields from the class passed. */
Field[] IDFields = aClass.getFields();
/* int-Array capable of storing all ids. */
int[] IDs = new int[IDFields.length];
try {
/* Loop through all Fields and store id to array. */
for(int i = 0; i < IDFields.length; i++){
/* All fields within the subclasses of R
* are Integers, so we need no type-check here. */
// pass 'null' because class is static
IDs[i] = IDFields[i].getInt(null);
}
} catch (Exception e) {
/* Exception will only occur on bad class submitted. */
throw new IllegalArgumentException();
}
return IDs;
}
}
Method getAllResourceIDs I've used from here
Another approach : you just need to create your own customized view. and onCreate. then iterate the AttributeSet object(attrs) to find index of your attribute. then just call getAttributeResourceValue with index, then you will get initial ResouceID value. a simple example of extending ImageView to get ResourceID for background:
public class PhoneImageView extends ImageView {
private static final String BACKGROUND="background";
private int imageNormalResourceID;
public PhoneImageView(Context context) {
super(context);
}
public PhoneImageView(Context context, AttributeSet attrs) {
super(context, attrs);
for (int i = 0; i <attrs.getAttributeCount() ; i++) {
if(attrs.getAttributeName(i).equals(BACKGROUND)){
imageNormalResourceID =attrs.getAttributeResourceValue(i,-1);
}
}
}
public PhoneImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
This approach is suitable for who is looking to store initial values.. solution provided by Bojan Kseneman (+1 vote) is for keeping ref to resourceID whenever view is changed.
You can get the id of an image with it's name by below code.
int drawableImageId = getResources().getIdentifier(imageName,"drawable", getPackageName());