I am attempting to fetch all the images from the SD Card and display them in a gridview (contained in a fragment). However, although no exceptions are thrown, nothing is displayed in the gridview, just a plain black screen. I'm not sure where the problem is, with the binding of the view or with the fetching of the data into the cursor. This is the current code for the fragment:
public class PhotoGridFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
// member variables for
private static final int PHOTO_LIST_LOADER = 0x01;
private ImageCursorAdapter adapter;
private Cursor c;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(PHOTO_LIST_LOADER, null, this);
adapter = new ImageCursorAdapter(getActivity().getApplicationContext(), c);
}
/* R.layout.grid_item,
null, new String[] { MediaStore.Images.Thumbnails.DATA }, new int[] {R.id.grid_item},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); */
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.photo_item, container, false);
}
// Loader manager methods
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { MediaStore.Images.Thumbnails._ID, MediaStore.Images.Thumbnails.DATA };
CursorLoader cursorLoader = new CursorLoader(getActivity(),
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection,
null, null, null);
return cursorLoader;
}
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
}
public void onLoaderReset(Loader<Cursor> cursor) {
adapter.swapCursor(null);
}
private class ImageCursorAdapter extends CursorAdapter {
private LayoutInflater mLayoutInflater;
private Context mContext;
public ImageCursorAdapter(Context context, Cursor c) {
super(context, c);
mContext = context;
mLayoutInflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ImageView newView = (ImageView) view.findViewById(R.layout.grid_item);
String imagePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID));
if (imagePath != null && imagePath.length() != 0 && newView != null) {
newView.setVisibility(ImageView.VISIBLE);
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = mLayoutInflater.inflate(R.layout.grid_item, parent, false);
return v;
}
}
The layout files for the project are as follows:
photo_item.xml:
<?xml version="1.0" encoding="UTF-8"?>
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/photo_item"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="24dp"
android:padding="6dp" />
grid_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_item"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="24dp"
android:padding="6dp"
/>
in bindView, you're not actually setting the imageView's drawable to anything. You grab an image path, verify it's a real path, and then ignore it :) Use the path to get a drawable! Then set the imageView's drawable to that image.
Try this code
sdcard.java
public class Sdcard extends Activity {
// Cursor used to access the results from querying for images on the SD card.
private Cursor cursor;
// Column index for the Thumbnails Image IDs.
private int columnIndex;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sdcard);
// Set up an array of the Thumbnail Image ID column we want
String[] projection = {MediaStore.Images.Thumbnails._ID};
// Create the cursor pointing to the SDCard
cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, // Which columns to return
null, // Return all rows
null,
MediaStore.Images.Thumbnails.IMAGE_ID);
// Get the column index of the Thumbnails Image ID
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);
GridView sdcardImages = (GridView) findViewById(R.id.gridView1);
sdcardImages.setAdapter(new ImageAdapter(this));
}
private class ImageAdapter extends BaseAdapter {
private Context context;
public ImageAdapter(Context localContext) {
context = localContext;
}
public int getCount() {
return cursor.getCount();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView picturesView;
if (convertView == null) {
picturesView = new ImageView(context);
// Move cursor to current position
cursor.moveToPosition(position);
// Get the current value for the requested column
int imageID = cursor.getInt(columnIndex);
// Set the content of the image based on the provided URI
picturesView.setImageURI(Uri.withAppendedPath(
MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, "" + imageID));
picturesView.setScaleType(ImageView.ScaleType.FIT_XY);
picturesView.setPadding(10, 10, 10, 10);
picturesView.setLayoutParams(new GridView.LayoutParams(100, 100));
}
else {
picturesView = (ImageView)convertView;
}
return picturesView;
}
}
}
Related
I have an SQLite database in android. I couldn't be able to see image data in RecyclerView. How can I see that in the activity page with a RecyclerView adapter?
I tried this but EpisodesAdapter episodesAdapter = new EpisodeAdapter(this, cursorEpisode, 0); this line is giving an error.
try {
EpisodesAdapter episodesAdapter = new EpisodeAdapter(this,cursorEpisode,0);
rvEpisodeImage.setAdapter(episodesAdapter);
Toast.makeText(this, "Succeed", Toast.LENGTH_SHORT).show();
} catch (SQLException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
This is the adapter class
public class EpisodesAdapter extends RecyclerView.Adapter<EpisodesAdapter.ViewHolder> {
private CursorAdapter mEpisodesAdapter;
private Context mEpisodesContext;
private RecyclerView.ViewHolder holder;
public EpisodesAdapter(final Context mEpisodesContext, Cursor cursor) {
this.mEpisodesContext = mEpisodesContext;
mEpisodesAdapter = new CursorAdapter(mEpisodesContext, cursor,0 ) {
#Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
// Inflate the view here
View view = LayoutInflater.from(context).inflate(R.layout.list_of_parts,viewGroup, false);
return view;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ImageView ivParts = view.findViewById(R.id.ivParts);
String sEpisodeName = cursor.getString(cursor.getColumnIndexOrThrow("EPISODE_NAME"));
int iImgPath = (int) context.getResources().getIdentifier(sEpisodeName, "drawable", context.getPackageName());
ivParts.setImageResource(iImgPath);
}
};
}
#NonNull
#Override
public EpisodesAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = mEpisodesAdapter.newView(mEpisodesContext, mEpisodesAdapter.getCursor(), parent);
holder = new ViewHolder(view);
return (ViewHolder) holder;
}
#Override
public void onBindViewHolder(#NonNull EpisodesAdapter.ViewHolder holder, int position) {
mEpisodesAdapter.getCursor().moveToPosition(position);
mEpisodesAdapter.bindView(holder.itemView,mEpisodesContext,mEpisodesAdapter.getCursor());
}
#Override
public int getItemCount() {
return mEpisodesAdapter.getCount();
}
public static class ViewHolder extends RecyclerView.ViewHolder{
private ImageView ivParts;
public ViewHolder(#NonNull View itemView) {
super(itemView);
ivParts = itemView.findViewById(R.id.ivParts);
}
}
}
What am I missing here? What should I do to get a view in RecyclerView?
EpisodesAdapter episodesAdapter = new EpisodeAdapter(this, cursorEpisode, 0);
I would like to suggest you read the values from the cursor first and save the values in an ArrayList. Then pass the ArrayList to the adapter instead of passing the cursor.
The problem in your adapter is, you should get the same value from the cursor for every item in your RecyclerView as you are not actually iterating over the cursor when the position changes. The Cursor works as a pointer and hence you need to move to the next pointer to get the next element in your cursor. Hence I would like to suggest something like the following.
Declare a class to handle your data first.
public class Episode {
public String episodeName;
public int imagePath;
}
Then after getting the cursor from your database, iterate through the cursor and populate an ArrayList of Episode like the following.
public ArrayList<Episode> getEpisodesFromCursor(Cursor cursor, Context context) {
ArrayList<Episode> episodes = new ArrayList<Episode>();
if (cursor == null) return episodes;
cursor.moveToFirst();
do {
Episode episode = new Episode();
String episodeName = cursor.getString(cursor.getColumnIndexOrThrow("EPISODE_NAME"));
episode.episodeName = episodeName;
episode.imagePath = (int) context.getResources().getIdentifier(episodeName, "drawable", context.getPackageName());
episodes.add(episode);
} while(cursor.moveToNext());
return episodes;
}
Pass the cursor to the function above to get an ArrayList of your items. Then modify your adapter to accept the ArrayList<Episode> and then change your other functions accordingly.
Once you have passed the ArrayList, modify the bindView function accordingly to show proper image and other data.
#Override
public void bindView(View view, Context context, int position) {
ImageView ivParts = view.findViewById(R.id.ivParts);
String sEpisodeName = episodes.get(position).episodeName;
int iImgPath = (int) context.getResources().getIdentifier(sEpisodeName, "drawable", context.getPackageName());
ivParts.setImageResource(iImgPath);
}
I just have added some sample implementation and you need to change the code as per your need. I hope that helps!
Edit:
Moreover, you are getting the error as the adapter constructor is expecting different parameters. You need to modify the constructor of your adapter anyway if you are using an ArrayList as I have suggested.
The ImageAdapter code I used to display images from my SD card to a GridView causes the images to repeat. The same set of images, like 10 of them are repeated in the GridView.
Here's my Adapter code:
private class ImageAdapter extends BaseAdapter {
private Context context;
public ImageAdapter(Context localContext) {
context = localContext;
}
public int getCount() {
return cursor.getCount();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView picturesView;
if (convertView == null) {
picturesView = new ImageView(context);
// Move cursor to current position
cursor.moveToPosition(position);
// Get the current value for the requested column
int imageID = cursor.getInt(columnIndex);
// Set the content of the image based on the provided URI
picturesView.setImageURI(Uri.withAppendedPath(
MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, "" + imageID));
picturesView.setScaleType(ImageView.ScaleType.CENTER_CROP);
picturesView.setPadding(0, 0, 0, 0);
picturesView.setLayoutParams(new GridView.LayoutParams(300, 300));
}
else {
picturesView = (ImageView)convertView;
}
return picturesView;
}
}
Additionally, here's the code that calls the Adapter in order to display all my SD Card images in the GridView
String[] projection = {MediaStore.Images.Thumbnails._ID};
// Create the cursor pointing to the SDCard
cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, // Which columns to return
null, // Return all rows
null,
MediaStore.Images.Thumbnails._ID);
// Get the column index of the Thumbnails Image ID
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);
GridView sdcardImages = (GridView) findViewById(R.id.sdcard);
sdcardImages.setAdapter(new ImageAdapter(this));
// Set up a click listener
sdcardImages.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
// Get the data location of the image
String[] projection = {MediaStore.Images.Media.DATA};
cursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, // Which columns to return
null, // Return all rows
null,
null);
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToPosition(position);
// Get image filename
String imagePath = cursor.getString(columnIndex);
// Use this path to do further processing, i.e. full screen display
}
});
What is wrong with my code guys?
In case the view is recycled and convertView is not null, you are not resetting the image URI. This is why you seeing just the images for which the view had to be created from scratch as convertView was null.
Therefore reuse or create a new view if needed :
final ImageView picturesView = convertView == null ? new ImageView(context) : (ImageView) convertView;
and later on configure it as you want.
But it is far more easier in you case to inherit behavior from CursorAdapter rather than BaseAdapter abstract class :
private class ImageAdapter extends CursorAdapter {
private final int columnIndex;
public ImageAdapter(Context context, Cursor cursor) {
super(context, cursor, true);
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new ImageView(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
final ImageView picturesView = (ImageView) view;
final int imageID = cursor.getInt(columnIndex);
final Uri uri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, String.valueOf(imageID));
picturesView.setImageURI(uri);
picturesView.setScaleType(ImageView.ScaleType.CENTER_CROP);
picturesView.setPadding(0, 0, 0, 0);
picturesView.setLayoutParams(new GridView.LayoutParams(300, 300));
}
}
Basically I've a View-pager where I can swipe between 1-6 pictures, using an adapter for that.
In order to "keep track" of the pictures, I implemented a selector which is represented by Image-views inflated using an adapter.
What's next, I'm using setOnPageChangeListener, more exactly the onPageSelected(int position) method to see what's the current Image-view and change its background so it can be differentiated by the rest of them. BUT this doesn't work, although it targets the proper image, the resource is not changed.
Here is some code for a better understanding:
This is where I set the size of the adapter
int poop = profile.getImages().size();
for (int i = 0; i < poop; i++) {
ImageView image = new ImageView(v.getContext());
imageList.add(image);
}
selectorAdapter = new SelectorAdapter(imageList, (android.support.v4.app.FragmentActivity) v.getContext());
selector_view.setAdapter(selectorAdapter);
This is the adapter:
public class SelectorAdapter extends BaseAdapter {
private List<ImageView> mArray = new ArrayList<ImageView>();
private FragmentActivity mContext;
public SelectorAdapter(List<ImageView> mArray, FragmentActivity mContext) {
this.mArray = mArray;
this.mContext = mContext;
}
#Override
public int getCount() {
return mArray.size();
}
#Override
public Object getItem(int position) {
return mArray.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater)
mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.selector_item, null);
}
return convertView;
}
}
Layout for the adapter:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/selector_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/p_photo_unmarked"
android:layout_marginLeft="5dp"/>
And finally where the magic's supposed to happen:
profilePic.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if (selectorAdapter.getItem(position) instanceof ImageView) {
((ImageView) selectorAdapter.getItem(position)).setBackgroundResource((R.drawable.p_photo_marked));
Toast.makeText(getActivity().getApplicationContext(), "position" + position, Toast.LENGTH_SHORT).show();
}
Change the line code
((ImageView) selectorAdapter.getItem(position)).setBackgroundResource((R.drawable.p_photo_marked));
to
((ImageView) selectorAdapter.getItem(position)).setBackground(getResources().getDrawable(R.drawable.p_photo_marked))
EDITED:
((ImageView)((SimpleTabPagerAdapter) selector_view.getAdapter()).getItem(position)).setBackgroundResource((R.drawable.p_photo_marked));
I am trying to create a custom listview like this: http://i.stack.imgur.com/l8ZOc.png
Currently I managed to create it but there is a problem. For example when there are 8 items, it loads the first 4, then loads the remiaining items as you scroll down. When scrolling down, it works fine.
However, when scrolling back up from bottom, at the middle of list, it instantly moves to top, skipping 2-3-4. items. Then you can scroll down normally again, but when scrolling up, it instantly goes to top of the list.
How can i prevent this from happening?
Here is my code:
public class MyActivity extends Activity implements AdapterView.OnItemClickListener {
String headers[];
String image_urls[];
List<MyMenuItem> menuItems;
ListView mylistview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
menuItems = new ArrayList<MyMenuItem>();
headers = getResources().getStringArray(R.array.header_names);
image_urls = getResources().getStringArray(R.array.image_urls);
for (int i = 0; i < headers.length; i++) {
MyMenuItem item = new MyMenuItem(headers[i], image_urls[i]);
menuItems.add(item);
}
mylistview = (ListView) findViewById(R.id.list);
MenuAdapter adapter = new MenuAdapter(this, menuItems);
mylistview.setAdapter(adapter);
mylistview.setOnItemClickListener(this);
}
}
public class MyMenuItem {
private String item_header;
private String item_image_url;
public MyMenuItem(String item_header, String item_image_url){
this.item_header=item_header;
this.item_image_url=item_image_url;
}
public String getItem_header(){
return item_header;
}
public void setItem_header(String item_header){
this.item_header=item_header;
}
public String getItem_image_url(){
return item_image_url;
}
public void setItem_image_url(String item_image_url){
this.item_image_url=item_image_url;
}
}
public class MenuAdapter extends BaseAdapter{
Context context;
List<MyMenuItem> menuItems;
MenuAdapter(Context context, List<MyMenuItem> menuItems) {
this.context = context;
this.menuItems = menuItems;
}
#Override
public int getCount() {
return menuItems.size();
}
#Override
public Object getItem(int position) {
return menuItems.get(position);
}
#Override
public long getItemId(int position) {
return menuItems.indexOf(getItem(position));
}
private class ViewHolder {
ImageView ivMenu;
TextView tvMenuHeader;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.menu_item, null);
holder = new ViewHolder();
holder.tvMenuHeader = (TextView) convertView.findViewById(R.id.tvMenuHeader);
holder.ivMenu = (ImageView) convertView.findViewById(R.id.ivMenuItem);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
MyMenuItem row_pos = menuItems.get(position);
Picasso.with(context)
.load(row_pos.getItem_image_url())
// .placeholder(R.drawable.empty)
// .error(R.drawable.error)
.into(holder.ivMenu);
holder.tvMenuHeader.setText(row_pos.getItem_header());
Log.e("Test", "headers:" + row_pos.getItem_header());
return convertView;
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MyActivity">
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
Use lazy loading mechanism to load your image data.
There is one nice example here
I am getting text absolutely right as what i should get. but image is getting repeated and displaying same image (that is 1st one which i have inserted in database).
Code: Samsunglists.java
public class Samsunglists extends ListActivity {
BaseAdapter adapter = null;
Cursor mcursor;
static final Class[] classArray = new Class[] { Samsung.class,Samsungs1.class};
#SuppressWarnings("deprecation")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_samsunglists);
Sqlite sqllll = new Sqlite(this);
SQLiteDatabase database = sqllll.getReadableDatabase();
ListView lv= getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View v, int pos,
long id) {
// TODO Auto-generated method stub
Intent in = new Intent(Samsunglists.this, classArray[pos]);
startActivity(in);
}
});
mcursor = database.query(Sqlite.TABLE_PRODUCT,new String[] {Sqlite._ID, Sqlite.PRODUCT_IMAGE, Sqlite.PRODUCT_NAME}, null, null, null, null, null, null);
startManagingCursor(mcursor);
adapter = new ImageCursorAdapter(this, R.layout.samsunglists_entry,mcursor, new String[]
{Sqlite.PRODUCT_IMAGE, Sqlite.PRODUCT_NAME}, new int[] {R.id.imageentry, R.id.samsungtype} );
setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
code: ImageCursorAdapter.java
public class ImageCursorAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
byte[] imgssss;
public ImageCursorAdapter(Context context, int layout,
Cursor c, String[] from, int[] to) {
// TODO Auto-generated constructor stub
super(context, layout, c, from, to);
this.c = c;
this.context = context;
}
#Override
public View getView(int pos, View inView, ViewGroup parent) {
// TODO Auto-generated method stub
View v = inView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.samsunglists_entry, null);
}
this.c.moveToPosition(pos);
String productname = this.c.getString(this.c.getColumnIndex("productname"));
imgssss = this.c.getBlob(this.c.getColumnIndex("productimage"));
ImageView iv = (ImageView) v.findViewById(R.id.imageentry);
if (imgssss != null) {
if(imgssss.length > 0)
{
iv.setImageBitmap(BitmapFactory.decodeByteArray(imgssss, 0, imgssss.length));
}
}
TextView tv = (TextView) v.findViewById(R.id.samsungtype);
tv.setText(productname);
return (v);
}
how will i get respective image with the text??