Loading images from phone to my app using Fresco library android / java - java

Hello I am new to Fresco and I am trying to load all the images in my phone to the app
when I use this URI: /storage/emulated/0/DCIM/Camera/20200206_222309.jpg
with this code:
ControllerListener listener = new BaseControllerListener();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(xuri)
.setTapToRetryEnabled(true)
.setControllerListener(listener)
.build();
photosFragmentRecycler.setController(controller);
only the photo with the name 20200206_222309.jpg is loaded
how can I load all the images?
thanks in Advance

Your question doesn't depend on the image library used. You basically want to get a list of all camera images.
Something like this should get you the list of all URIs:
fun getMediaStoreUris(context: Context): List<Uri> {
val uris = mutableListOf<Uri>()
context.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
arrayOf(MediaStore.Images.Media._ID),
null,
null,
null)?.use {
val dataIndex = it.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
while (it.moveToNext()) {
uris.add(
ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
it.getLong(dataIndex)))
}
}
return uris
}
Then, you can just create a simple RecyclerView adapter and ViewHolder and load images with Fresco:
public class SimpleAdapter extends RecyclerView.Adapter<SimpleViewHolder> {
private List<Uri> mUris;
SimpleAdapter(List<Uri> uris) {
mUris = uris;
setHasStableIds(true);
}
#Override
public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView =
LayoutInflater.from(parent.getContext())
.inflate(R.layout.drawee_recycler_item, parent, false);
return new SimpleViewHolder(itemView);
}
#Override
public void onBindViewHolder(SimpleViewHolder holder, int position) {
holder.mSimpleDraweeView.setImageURI(mUris.get(position));
}
#Override
public int getItemCount() {
return mUris.size();
}
#Override
public long getItemId(int position) {
return mUris.get(position).hashCode();
}
public void setData(List<Uri> uris) {
mUris = uris;
notifyDataSetChanged();
}
}
static class SimpleViewHolder extends RecyclerView.ViewHolder {
private final SimpleDraweeView mSimpleDraweeView;
SimpleViewHolder(View itemView) {
super(itemView);
mSimpleDraweeView = itemView.findViewById(R.id.drawee_view);
}
}
and use the adapter:
final SimpleAdapter adapter = new SimpleAdapter(getMediaStoreUris(context));
recyclerView.setAdapter(adapter);
Fresco has a full sample in their Showcase sample application here: https://github.com/facebook/fresco/blob/9fde53f963d07495118c61ea2d9a3fce575afeb7/samples/showcase/src/main/java/com/facebook/fresco/samples/showcase/drawee/DraweeRecyclerViewFragment.java
This is going to work if you allow permission to access local storage, there's a guide here or to test it, by simply going to "App Info" for your app and manually allowing it.
This is a very simple solution and in practice, you probably want to implement pagination etc. for the media store. But this should guide you in the right direction.

Related

Nested RecyclerView with boolean array?

I am working on an app with a dynamic number of switches to connect to a device. Here is my model class:
public class SwitchModel {
private String product;
private String deviceId;
private ArrayList<Boolean> switchPool;
public SwitchModel(String product, String deviceId, ArrayList<Boolean> switchPool) {
this.product = product;
this.deviceId = deviceId;
this.switchPool = switchPool;
}
As you can see, I have only a product string for user input. A device id provided by the API and a dynamic number of switches.
I want to my final app functions like this:
I tried to do this task by using a nested RecyclerView:
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.MainViewHolder> {
Activity context;
private ArrayList<SwitchModel> modelList;
public MainAdapter(Activity context, ArrayList<SwitchModel> modelList) {
this.context = context;
this.modelList = modelList;
}
#Override
public void onBindViewHolder(#NonNull MainViewHolder holder, int position) {
SwitchModel model = modelList.get(position);
holder.productName.setText(model.getProduct());
ChildAdapter childAdapter = new ChildAdapter(model.getSwitchPool());
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
holder.rvChild.setLayoutManager(layoutManager);
holder.rvChild.setAdapter(childAdapter);
}
And here is the code for my Child Adapter:
public class ChildAdapter extends RecyclerView.Adapter<ChildAdapter.ViewHolder> {
private ArrayList<Boolean> switches;
public ChildAdapter(ArrayList<Boolean> switches) {
this.switches = switches;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Boolean model = switches.get(position);
holder.switchButton.setChecked(model);
holder.switchButton.setOnCheckedChangeListener(new SwitchButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(SwitchButton view, boolean isChecked) {
Log.i("myResponse", "onCheckedChanged: " + view.isChecked());
return;
}
});
}
The RecyclerView sets the checked value of the switch correctly. But my problem is as you can see in my child view I have bound a boolean for each index of array list, but when I call for a check change listener it does not return the exact switch number of the product. It would be great if anyone could help me with this?
I would perhaps try to leverage a ConcatAdapter from Google.
In essence, you can supply N adapters with N data and update/handle them individually. I have never tried to do this by myself, and I don't want to make it sound like it's an easy thing to do, but it appears to "perhaps fit the use-case" you describe.
Someone has already done an expandable recyclerview using concat adapter so perhaps this would point you in the right direction before you get your hands dirty trying to make it work.

Image is not loading in ImageView - Android

I want to load the clicked image in the next activity in fullscreen view. I don't know what I am doing wrong. The app is running completely fine but the image is not loading on the next screen. am new to android development and I thought I should start learning by doing a project. I am not understanding what is the problem in my coding.
public class CategoriesAdapter extends RecyclerView.Adapter<CategoriesAdapter.ImageViewHolder> {
private Context mCtx;
private List<Category> imageslist;
public CategoriesAdapter(Context mCtx, List<Category> imageslist) {
this.mCtx = mCtx;
this.imageslist = imageslist;
}
#NonNull
#Override
public ImageViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(mCtx).inflate(R.layout.recyclerview_images,parent,false);
return new ImageViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ImageViewHolder holder, final int position) {
final Category images=imageslist.get(position);
Glide.with(mCtx).load(images.url).into(holder.imageView);
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(mCtx, LoadWall.class);
intent.putExtra("url", (Parcelable) imageslist.get(position));
mCtx.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return imageslist.size();
}
class ImageViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
public ImageViewHolder(#NonNull View itemView) {
super(itemView);
imageView=itemView.findViewById(R.id.image_view);
}
}
}
This is the activity where I want to load the image. But its not loading. Please Help
public class LoadWall extends AppCompatActivity {
ImageView imageView;
int myImage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_load_wall);
imageView=findViewById(R.id.load_image);
get();
}
private void get(){
if(getIntent().hasExtra("url")){
String image=getIntent().getStringExtra("url");
set(image);
}
else{
Toast.makeText(this,"No Data",Toast.LENGTH_SHORT).show();
}
}
private void set(String image){
Glide.with(this).load(image).into(imageView);
}
}
Here you only need to pass URL as a String. Parcelable is not required.
intent.putExtra("url", imageslist.get(position).getUrl());
Option 1)
In your next activity you are looking for String.
String image=getIntent().getStringExtra("url");
in first activity in onClick() change your code to this.
Intent intent=new Intent(mCtx, LoadWall.class);
intent.putExtra("url", imageslist.get(position));
intent.startActivity(intent);
As i see imageslist.get(position) will return Category so you will need to add your url parameter. Something like this imageslist.get(position).getUrl();
Option 2)
If you want to get Category object then in next activity change to this
Category category = getIntent().getParcelableExtra("url");
Your imagesList contains data of type Category and you send an entry from this list to the next activity. However, the second activity expects a String to be received. It will check to see if it has an extra (it has - but not what you need), then try to retrieve that value as a String which will result in a null String. Having null, Glide will not load anything.
In other words, you made a small mistake on what data you use. When you load the data, you do it correctly by using the url field
final Category images=imageslist.get(position);
Glide.with(mCtx).load(**images.url**).into(holder.imageView);
But when you are passing it to the next activity, you send the entire object
intent.putExtra("url", **(Parcelable) imageslist.get(position)**);
Using the url field as you did in the first case will make your app work properly.
Start your Activity
Intent intent=new Intent(mCtx, LoadWall.class);
intent.putExtra("url", images.url);
mCtx.startActivity(intent);

Unable to get favicon from url when mobile does not have any internet or is it possible to save at internal storage and then to read from there

I have a parsed XML which I have read data from there. I have manually declared some data and the other data will be saved by the user.
I have declared with glide but it is not getting the right icon or when there is no internet the icons are hidden.
The declared the xml they have the icons at the drawable and when I parse they are readable and I can show.
What I want is there any option to take the favicon and save to drawable or to an internal storage or cache so I can read even if I dont have internet.
The items which are declared manually and parsed for them take the icon from drawable but for the others take the favicon from url.
Here is what I have tried so far.
The Pojo.class
public class Bookmark implements Parcelable, Comparable {
String name, id, nativeUrl, searchUrl;
long db_id;
int icon;
int viewType;
// Constructor, getters, setters & other default functions are omitted for simplicity.
}
The Adapter.class
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
ArrayList<Bookmark> arrayList;
BookmarkDB bookmarkDB;
public static final int ITEM_TYPE_ONE = 0;
public static final int ITEM_TYPE_TWO = 1;
boolean connected = false;
String BASE_URL = "https://besticon-demo.herokuapp.com/icon?url=";
public MyAdapter(Context context, ArrayList<Bookmark> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
private boolean switchOnOff;
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = null;
if (viewType == ITEM_TYPE_ONE) {
view = LayoutInflater.from(context).inflate(R.layout.grid_item, parent, false);
return new ViewHolder(view);
} else if (viewType == ITEM_TYPE_TWO) {
view = LayoutInflater.from(context).inflate(R.layout.add_bookmark, parent, false);
return new ButtonViewHolder(view);
} else {
return null;
}
}
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, final int position) {
final int itemType = getItemViewType(position);
if (itemType == ITEM_TYPE_ONE) {
final ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.tvName.setText(arrayList.get(position).getName());
RequestOptions requestOptions = new RequestOptions();
bookmarkDB = new BookmarkDB(context);
viewHolder.tvIcon.setImageResource(arrayList.get(position).getIcon());
Glide.with(context)
.load(BASE_URL+arrayList.get(position).getSearchUrl() + "&size=32;")
.apply(requestOptions)
.into(viewHolder.tvIcon);
viewHolder.tvIcon.setImageResource(arrayList.get(position).getIcon());
viewHolder.tvId.setText(arrayList.get(position).getId());
viewHolder.tvSearchUrl.setText(arrayList.get(position).getSearchUrl());
} else if (itemType == ITEM_TYPE_TWO) {
ButtonViewHolder buttonViewHolder = (ButtonViewHolder) holder;
buttonViewHolder.imgButton.setImageResource(arrayList.get(position).getIcon());
}
}
#Override
public int getItemViewType(int position) {
// Based on you list you will return the ViewType
if (arrayList.get(position).getViewType() == 0) return ITEM_TYPE_ONE;
else return ITEM_TYPE_TWO;
}
}
Ass you can see at the Adapter.class
// This get the icon from drawable and it sets to parsed array.
viewHolder.tvIcon.setImageResource(arrayList.get(position).getIcon());
// This gets the icon from URL and sets it to the parsed array but only when the user has internet.
Glide.with(context)
.load(BASE_URL+arrayList.get(position).getSearchUrl() + &size=32;")
.apply(requestOptions)
.into(viewHolder.tvIcon);
This is the declared XML which I have parsed, the file it is declared under res/xml/bookmarks.xml
<Bookmarks>
<Bookmark name="Bing" hidden="" icon="bing" id="0" nativeUrl="" searchUrl="https://www.bing.com" />
<Bookmark name="Google" hidden="" icon="google" id="1" nativeUrl="" searchUrl="https://www.google.com" />
<Bookmark name="Youtube" hidden="" icon="youtube" id="2" nativeUrl="" searchUrl="http://m.youtube.com" />
</Bookmarks>
So if I have understood correctly, you have two problems.
The default icon is not showing (i.e. hidden) when there is no internet.
You want to show the images once loaded even if there is no internet.
Both of these two can be achieved using Glide with minimal change in your code. Just change the image loading portion of your code using Glide like the following.
String imageUrl = BASE_URL + arrayList.get(position).getSearchUrl() + "&size=32";
Glide.with(context)
.load(imageUrl)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(R.drawable.placeholder)
.into(viewHolder.tvIcon);
DiskCacheStrategy.ALL manages the caching of your images and should load the images even if the device is offline. Setting the placeholder using the .placeholder(R.drawable.placeholder) can be used, when the images are not loaded for internet problem and hence you want to show a default image instead.
If you want to read more about the caching strategies, this link can help as well.
Update 1
Based on your comment, I think you should have an if statement here. When the drawable is available locally, then you will use the setImageResource function, else use Glide to load the image.
Update 2
You do not have to save the images locally if you are using Glide with DiskStrategy.ALL. It will cache the images and will show automatically when the internet connection is not available. I would like to suggest you to remove the manual setup.
Update 3
If you want to use some of the icons from your own drawable, then you might consider putting something like this.
if (theIconIsAvailableInDrawable) showThatFromDrawable();
else useGlideToShowTheIconFromUrlUsingDiskCacheStrategy();
Hope you get the idea.

Get to know device screen size programmatically in Android?

Please have a look at related Question. I got to know some hint from comments and now putting it in a new way.
I am using a RecyclerView with StaggeredGridView adapter to display the data. How do I get to know that how many items needed to be loaded for current devices to fit the whole screen?
process
Determine the screen size
Determine how many items needed to be loaded to fit full screen
Fetch data from Server with number of items
Display them
When user scroll down device fetch same amount of items and so on.
Question
I am not able to understand How to get done with first two points.
Code for Adapter
public class StaggeredGridAdapter extends RecyclerView.Adapter<StaggeredGridAdapter.StaggeredGridView> {
private Context context;
private String INTENT_VALUE = "warehouse";
private List<Warehouse> warehouses = new ArrayList<Warehouse>();
private AppDelegate app;
int size;
public StaggeredGridAdapter(Context context) {
this.context = context;
app = (AppDelegate) context;
}
public void addItems(List<Warehouse> response) {
size = response.size();
warehouses = response;
}
#Override
public StaggeredGridView onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_item, parent, false);
StaggeredGridView staggeredGridView = new StaggeredGridView(layoutView);
return staggeredGridView;
}
#Override
public void onBindViewHolder(StaggeredGridView holder, int position) {
holder.textView.setText(warehouses.get(position).getFace());
}
#Override
public int getItemCount() {
return size;
}
class StaggeredGridView extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView textView;
public StaggeredGridView(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.img_name);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Intent intent = new Intent(context, WareHouseDetailActivity.class);
intent.putExtra(INTENT_VALUE, warehouses.get(getAdapterPosition()));
v.getContext().startActivity(intent);
}
}
}
code for filling data into adapter
mRecyclerView = (RecyclerView) mActivity.findViewById(R.id.staggering_grid);
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
mAdapter = new StaggeredGridAdapter(mContext);
mAdapter.addItems(response);
mRecyclerView.setAdapter(mAdapter);
As to find the Height and Width, you can use the DisplayMetrics.
final DisplayMetrics displayMetrics = this.getApplicationContext().getResources().getDisplayMetrics();
This displayMetrics will give Height, Width and Density. Use the height of the single View (or row) and the total height to calculate the number of items.
Why do you want the Exact number of items, if it's a server call you are making, you could just make a rough estimate on the number of items based on the device size. Also, I think it's better to keep the number of items sent by server a constant and not dependent on the device height. If you received more than the number of items you can fit in the screen, well, the user can scroll to see them anyways.
Rather than trying to work out how much you'll need to load, you could set it up to automatically load more when you're close to the end of the list.
Consider this method:
#Override
public void onBindViewHolder(StaggeredGridView holder, int position) {
holder.textView.setText(warehouses.get(position).getFace());
}
This is called when the item is ready to be displayed on the screen. By doing something like if(position > getItemCount() - 5{ // load more } then you could be automatically loading more as and when they're required.

Loading listview icons locally, looking for most efficient process

Im trying to efficiently load my local drawables (from my res>drawable folders) into my list items. I want this to use as little memory as possible while loading my images.
I originally had my resource name (R.drawable.list_icon) defined as an int in the model and calling setImageResource in my adapter to apply the icon.
However after reviewing the API documentation, it suggests i use setImageDrawable or setImageBitmap since they are not ran on the UI thread. I need to know if this the following code below, where i've converted the drawable to a bitmap and used setImageBitmap is a good method and if loading the local image in a AsyncTask is worth incorporating (since i've seen this method used as well).
Model
public class ProductItem {
public int listIcon;
public String listTitle;
public String listDesc;
public ProductItem(int listIcon, String listTitle,
String listDesc) {
this.listIcon = listIcon;
this.listTitle = listTitle;
this.listDesc = listDesc;
}
public int getIconID() {
return listIcon;
}
}
Adapter
public class ProductAdapter extends ArrayAdapter<ProductItem> {
Context context;
int layoutResourceID;
ProductItem data[];
ProductHolder viewHolder;
public ProductAdapter(Context context, int layoutResourceID, ProductItem[] data) {
super(context, layoutResourceID, data);
this.layoutResourceID = layoutResourceID;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(layoutResourceID, parent, false);
viewHolder = new ProductHolder();
viewHolder.productType = (TextView) convertView.findViewById(R.id.itemTitle);
viewHolder.productDesc = (TextView) convertView.findViewById(R.id.itemSubtitle);
viewHolder.productImage = (ImageView) convertView.findViewById(R.id.itemIcon);
convertView.setTag(viewHolder);
} else {
viewHolder = (ProductHolder) convertView.getTag();
}
ProductItem objectItem = data[position];
if (objectItem != null) {
viewHolder.productType.setText(objectItem.listTitle);
viewHolder.productType.setTag(objectItem.listTitle);
viewHolder.productDesc.setText(objectItem.listDesc);
viewHolder.productDesc.setTag(objectItem.listDesc);
// Im currently using the following method for obtain the resource.
InputStream is = context.getResources().openRawResource(objectItem.getIconID());
final Bitmap imageBitmap = BitmapFactory.decodeStream(is);
viewHolder.productImage.setImageBitmap(imageBitmap);
// Im using 'setImageBitmap' since it doesnt run on the UI thread, hoping that this will in return load quicker.
// However i was previously using the following.
// viewHolder.productImage.setImageResource(objectItem.getIconID());
viewHolder.productImage.setTag(objectItem.listIcon);
}
return convertView;
}
static class ProductHolder {
public TextView productType;
public TextView productDesc;
public ImageView productImage;
}
}
Usage
listData[0] = new ProductItem(R.drawable.list_icon, getString(R.string.list_title), getString(R.string.list_description));
My main question here is what is the most efficient way to load local drawables, These image icon are pretty high quality and not just simple 1 color icons, they are actual product images.
Try to use UniversalImageLoader. It works well not only for loading images from network.

Categories

Resources