In my application I need to display questions along with images in Android. I have stored questions in sqlite db and displaying them. I have created a folder DBimages in assets folder. Now all my images are there in DBimages folder.
I have created two classes. I am able to display the question and options from local sqlite db but I am unable to display the image which is stored in assets\DBimages\abc.png.
The names of all the images are stored in pictures column in sqlite db table. But how to display the image related to that particular question. Please help me regarding this.
UserBO.java
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getImage() {
return pictures;
}
public void setImage(String pictures) {
this.pictures = pictures;
}
Select.java
ArrayList<UserBO> usersList = new ArrayList<UserBO>();
for (int i = 0; i < stringList.size(); i++) {
ArrayList<String> list = stringList.get(i);
UserBO user = new UserBO();
try {
user.id = Integer.parseInt(list.get(0));
user.name = list.get(2);
user.question = list.get(3);
user.option1 = list.get(4);
user.option2 = list.get(5);
user.option3 = list.get(6);
user.option4 = list.get(7);
user.option5 = list.get(8);
user.pictures = list.get(9);
user.answer = (list.get(10));
}
catch (Exception e){}
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
try{
if (view == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(R.layout.list_item, null);
}
final UserBO listItem = mList.get(position);
if (listItem != null) {
( (TextView) view.findViewById(R.id.tv_question) ).setText( listItem.getQuestion()+"");
((ImageView) view.findViewById(R.id.imageView1)).setImageResource(R.drawable.f);
( (RadioButton) view.findViewById(R.id.option1) ).setText( listItem.getOption1() );
( (RadioButton) view.findViewById(R.id.option2) ).setText( listItem.getOption2()+"" );
( (RadioButton) view.findViewById(R.id.option3) ).setText( listItem.getOption3()+"" );
( (RadioButton) view.findViewById(R.id.option4) ).setText( listItem.getOption4()+"" );
( (RadioButton) view.findViewById(R.id.option5) ).setText( listItem.getOption5()+"" );
}}catch(Exception e){}
return view;
}
}
Some ugly way, to store images in SQLite database. Just store images in sdcard and save the relevant path of those images in SQLite database.
In your need, put the images in either drawable folder or in asset folder then store its
name(with question ID or number also) in SQLite and use it in application.
I had the same problem and i want first to clarify this, storing image path or uri from gallery as string might not give good results when populating or display the data to listview specific the images. You need to store your images on sqlite database as BLOB data types and you need to insert the image to the DB as bytes.
In my case, i tried working with image path from gallery but never worked from me.
Image path is suitable when only your are using urls from a website
You can see an example from this link
Related
Gist: custom adapter gets file resource indirectly via filepath in database. Inefficiency / memory concerns. Your opinion requested.
References to all searches, related links, and things useful re topic are at post bottom.
Code below works, but several factors are of concern. Need some more experienced eyes on this please to suggest improvement or potential errors to avoid. App doesn't need to be a content provider (data sourced local to app only). The ListView in question will be very light weight with only about 5 to max 10 entries. (I left out the database stuff because it works.)
Overview:
DataBase contains some text and an Image File path. - OK
image files are stored on device (SD card / external storage, where ever). - OK
That the files are not in the database makes this different than a normal SimpleCursorAdapter - have to pull the image file. Added overhead of making it into a thumbnail before populating the listview.
As said, it's light, however, even with only one or two entries, the VM is burping. I suspect it's all the memory joggling related to the Bitmaps:
08-27 19:53:14.273: I/dalvikvm-heap(11900): Grow heap (frag case) to 4.075MB for 1228816-byte allocation
08-27 19:53:14.393: D/dalvikvm(11900): GC_CONCURRENT freed <1K, 5% free 4032K/4244K, paused 13ms+3ms, total 116ms
/* myTextAndImageCursorAdapter.java */
import android.widget.SimpleCursorAdapter;
//import android.support.v4.widget.SimpleCursorAdapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.database.Cursor;
import java.io.File;
import android.widget.ImageView;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import static android.media.ThumbnailUtils.extractThumbnail;
public class TextAndImageCursorAdapter extends SimpleCursorAdapter {
private Context context;
private int layout;
public TextAndImageCursorAdapter (Context ctx, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.context = ctx;
this.layout = layout;
}
#Override
public View newView(Context ctx, Cursor cursor, ViewGroup parent) {
Cursor c = getCursor();
final LayoutInflater inflater = LayoutInflater.from(ctx);
View vView = inflater.inflate(layout, parent, false);
int iCol_Text = c.getColumnIndex(DBCOL_TEXT);
int iCol_Image = c.getColumnIndex(DBCOL_IMAGE);
String sText = c.getString(iCol_Text);
String sFileAndPath_Image = c.getString (iCol_Image); //// sImage path & file
TextView tvText = (TextView) v.findViewById(R.id.gui_text);
if (tvText != null) {
tvText.setText(sSomeText);
}
ImageView ivImage (ImageView) v.findViewById(R.id.gui_image);
if (ivImage != null) {
ivImage.setImage (mySetImage (sFileAndPath_Image) );
}
return vView;
}
#Override
public void bindView(View v, Context ctx, Cursor c) {
//// ( like newView(), without an inflater, view, or return )
int iCol_Text = c.getColumnIndex(DBCOL_TEXT);
int iCol_Image = c.getColumnIndex(DBCOL_IMAGE);
String sText = c.getString(iCol_Text);
String sFileAndPath_Image = c.getString (iCol_Image); //// path & file
TextView tvText = (TextView) v.findViewById(R.id.gui_text);
if (tvText != null) {
tvText.setText(sSomeText);
}
ImageView ivImage (ImageView) v.findViewById(R.id.gui_image);
if (ivImage != null) {
ivImage.setImageBitmap ( mySetImage ( sFileAndPath_Image ) ) ;
}
}
/////
/////
protected Bitmap mySetImage ( String path ) {
int width = 60; int height = 40 ;
File imgFile = new File ( path ); //// usually like: \sdcard0\wherever\filename1234.bmp
Bitmap myBitmap = null;
if( imgFile.exists() )
{
myBitmap = BitmapFactory.decodeFile ( imgFile.getAbsolutePath () );
}
else
Log.d ("oops", "no image file ... using default.");
myBitmap = getTheDefaultImage (); //// not shown - this is arbitrary
}
imgFile.close();
return ( extractThumbnail ( myBitmap, width, height ) ) ;
}
}
[EDIT - added links]
Search Criteria:
"
Android custom simplecursoradapter with image from file with path in database
"
The nearest hit, but attempts to pull image from res, not from external / sd store (unanswered):
SimpleCursorAdapter how to show an image?
Also a near hit / miss - similar algo (unanswered) references 4):
Customizing list shown from SimpleCursorAdapter using ViewBinder
Almost, but OP's code doesn't work, (no working answer):
Load Image in a custom list by SimpleCursorAdapter
Working for OP, but uses JSON for remote retrieval, not local (maybe this could be tweaked, but it's not clear to me how).
How to show images in imageview in simple adapter?
Not quite, but again close:
ListView scroll slow while loading image from Internal Storage
Image Loader problems (references 2):
Imageloader not loading image on real device
Related links:
Android Custom Cursor Adapter
Android: Issue with newView and bindView in custom SimpleCursorAdapter
Similarly named hits, but unrelated to my specific questions - these usually refer to in-app RESources:
show image from database where you saved the path of image
Custom SimpleCursorAdapter error
Custom SimpleCursorAdapter, database query and NullPointerException
nullPointerException with extended SimpleCursorAdapter
Android SimpleCursorAdapter - Adding conditional images
External References:
0) Simple intro tut on custom cursor adapters
http://thinkandroid.wordpress.com/2010/01/11/custom-cursoradapters/
1) Romain Guy - basic layout ... 2 txts, 1 image
http://www.curious-creature.org/2009/02/22/android-layout-tricks-1/
2) AQuery (Android Query)
http://code.google.com/p/android-query/wiki/ImageLoading
3) Android thumbnails
http://developer.android.com/reference/android/media/ThumbnailUtils.html
4) Cust. listview with an "on/off" star image:
http://enjoyandroid.wordpress.com/2012/03/12/customizing-simple-cursor-adapter/
Two things you can do:
1) Use the ViewHolder pattern, cache the LayoutInfalter and most important: don't bind data twice:
/* ... imports */
import static android.media.ThumbnailUtils.extractThumbnail;
public class TextAndImageCursorAdapter extends SimpleCursorAdapter {
private LayoutInflater mLayoutInflater;
private Context context;
private int layout;
private class ViewHolder {
TextView textView;
ImageView imageView;
ViewHolder(View v) {
textView = (TextView) v.findViewById(R.id.gui_text);
imageView = (ImageView) v.findViewById(R.id.gui_image);
}
}
public TextAndImageCursorAdapter (Context ctx, int layout, Cursor c, String[] from, int[] to) {
super(ctx, layout, c, from, to);
this.context = ctx;
this.layout = layout;
mLayoutInflater = LayoutInflater.from(ctx);
}
#Override
public View newView(Context ctx, Cursor cursor, ViewGroup parent) {
View vView = mLayoutInflater.inflate(layout, parent, false);
vView.setTag( new ViewHolder(vView) );
// no need to bind data here. you do in later
return vView;// **EDITED:**need to return the view
}
#Override
public void bindView(View v, Context ctx, Cursor c) {
// you might want to cache these too
int iCol_Text = c.getColumnIndex(DBCOL_TEXT);
int iCol_Image = c.getColumnIndex(DBCOL_IMAGE);
String sText = c.getString(iCol_Text);
String sFileAndPath_Image = c.getString (iCol_Image); //// path & file
ViewHolder vh = (ViewHolder) v.getTag();
vh.textView.setText(sSomeText);
vh.imageView.setImageBitmap ( mySetImage ( sFileAndPath_Image ) );
}
}
2) This is really important: don't create a thumbnail on every bind. you need to cache the result:
private void setThumbnail(String path, Bitmap b) {
// save thumbnail to some kind of cache
// see comment below
}
private Bitmap getThumbnail(String path) {
Bitmap thumbnail = null;
// try to fetch the thumbnail from some kind of cache
// see comment below
return thumbnail;
}
protected Bitmap mySetImage ( String path ) {
int width = 60; int height = 40 ;
Bitmap thumbnail = getThumbnail(path); // try to fetch thumbnail
if (thumbnail != null) return thumbnail;
File imgFile = new File ( path ); //// usually like: /sdcard/wherever/filename1234.bmp
Bitmap myBitmap = null;
if( imgFile.exists() ) {
myBitmap = BitmapFactory.decodeFile ( imgFile.getAbsolutePath () );
} else {
Log.d ("oops", "no image file ... using default.");
myBitmap = getTheDefaultImage (); //// not shown - this is arbitrary
}
imgFile.close();
thumbnail = extractThumbnail ( myBitmap, width, height );
myBitmap.recycle();
setThumbnail(path, thumbnail); // save thumbnail for later reuse
return thumbnail;
}
Depending on you use case, you want to fill getThumbnail() and setThumbnail() with some kind of LruCache:
There is a in memory LruCache available in the android API and in support lib: https://developer.android.com/reference/android/util/LruCache.html
Jake made an persistent DiskLruCache: https://github.com/JakeWharton/DiskLruCache
EDIT :
#Override
public View newView(Context ctx, Cursor cursor, ViewGroup parent) {
View vView = mLayoutInflater.inflate(layout, parent, false);
vView.setTag( new ViewHolder(vView) );
// no need to bind data here. you do in later
return vView;// **EDITED:**need to return the view
}
In my scenario i am having 3 records in sqlite which were fetched from websercive that contains id,name,description and image now i want to display the first record and second one after flipping the first record.and 3 one after second record flips..
What i have done so far is
while (cursor.moveToNext())
{
String temp_bookid = cursor.getString(0);
Log.i("temp_bookid",temp_bookid);
String temp_desc=cursor.getString(1);
byte[] temp_image1 = cursor.getBlob(2);
byte[] temp_image2 = cursor.getBlob(3);
String temp_id=cursor.getString(4);
String temp_name = cursor.getString(5);
String temp_bname=cursor.getString(6);
mapId.add(temp_id);
mapBname.add(temp_bname);
mapBookId.add(temp_bookid);
mapName.add(temp_name);
mapDesc.add(temp_desc);
map2.add(temp_image2);
map1.add(temp_image1);
Log.i("temp_id of the page in sqlite", temp_id);
TextView txtDesc = (TextView) findViewById(R.id.tDescription);
text = (TextView) findViewById(R.id.tTitle);
text.setText(temp_name);
txtDesc.setText(temp_desc);
ImageView img = (ImageView)findViewById(R.id.smallImage);
img.setImageBitmap(BitmapFactory.decodeByteArray(temp_image1, 0,temp_image1.length));
txtName1 = (TextView) findViewById(R.id.tvName);
txtName1.setText(temp_bname);
break;
}
mContext = this;
vf = (ViewFlipper) this.findViewById(R.id.vfShow);
vf.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(final View view, final MotionEvent event) {
detector.onTouchEvent(event);
Log.i("ew","ae");
return true;
}
});
I am able to display first record data when i set break; statement otherwise it is displaying last record data..How can proceed for this approach?
First fetch all the records and store in List<YourDataClass> myList object from onCreate method. As I have just giving you the examples
Now after fetching the data and stored in your list object you need to implement flipper change event so when flipper was change get the current position and using this position get the data as object from your list object. As you move right/left it will giving you the current position and you just need to use this position to fetch the records from list object
For example
Your POJO class will store the data MyData.java
public class MyData{
public long id = -1;
public String name = "";
public String description = "";
public String imagePath = ""; /// I don't know you want exactly, you need to implement image as per your requirement.
}
In your activity
private List<MyData> myList = new ArrayList<MyData>();
oncreate(){
fetchData(); // you need to implement this in AsyncTask so UI was not block just implement AsyncTask and call this method in doInBackground().
// after this you can implment View flipper and add view and set the data by fetch the list object using current view flipper position.
}
private void fetchData(){
while (cursor.moveToNext()){
MyData myData = new MyData();
myData.id = cursor.getLong(0);
myData.desc=cursor.getString(1);
myData.name = cursor.getString(5);
list.add(myData);
myData = null;
}
}
In my scenario i am having 3 records in sqlite which were fetched from websercive that contains id,name,description and image now i want to display the first record and second one after flipping the first record.and 3 one after second record flips..
What i have done so far is
while (cursor.moveToNext())
{
String temp_bookid = cursor.getString(0);
Log.i("temp_bookid",temp_bookid);
String temp_desc=cursor.getString(1);
byte[] temp_image1 = cursor.getBlob(2);
byte[] temp_image2 = cursor.getBlob(3);
String temp_id=cursor.getString(4);
String temp_name = cursor.getString(5);
String temp_bname=cursor.getString(6);
mapId.add(temp_id);
mapBname.add(temp_bname);
mapBookId.add(temp_bookid);
mapName.add(temp_name);
mapDesc.add(temp_desc);
map2.add(temp_image2);
map1.add(temp_image1);
Log.i("temp_id of the page in sqlite", temp_id);
TextView txtDesc = (TextView) findViewById(R.id.tDescription);
text = (TextView) findViewById(R.id.tTitle);
text.setText(temp_name);
txtDesc.setText(temp_desc);
ImageView img = (ImageView)findViewById(R.id.smallImage);
img.setImageBitmap(BitmapFactory.decodeByteArray(temp_image1, 0,temp_image1.length));
txtName1 = (TextView) findViewById(R.id.tvName);
txtName1.setText(temp_bname);
break;
}
mContext = this;
vf = (ViewFlipper) this.findViewById(R.id.vfShow);
vf.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(final View view, final MotionEvent event) {
detector.onTouchEvent(event);
Log.i("ew","ae");
return true;
}
});
I am able to display first record data when i set break; statement otherwise it is displaying last record data..How can proceed for this approach?
First fetch all the records and store in List<YourDataClass> myList object from onCreate method. As I have just giving you the examples
Now after fetching the data and stored in your list object you need to implement flipper change event so when flipper was change get the current position and using this position get the data as object from your list object. As you move right/left it will giving you the current position and you just need to use this position to fetch the records from list object
For example
Your POJO class will store the data MyData.java
public class MyData{
public long id = -1;
public String name = "";
public String description = "";
public String imagePath = ""; /// I don't know you want exactly, you need to implement image as per your requirement.
}
In your activity
private List<MyData> myList = new ArrayList<MyData>();
oncreate(){
fetchData(); // you need to implement this in AsyncTask so UI was not block just implement AsyncTask and call this method in doInBackground().
// after this you can implment View flipper and add view and set the data by fetch the list object using current view flipper position.
}
private void fetchData(){
while (cursor.moveToNext()){
MyData myData = new MyData();
myData.id = cursor.getLong(0);
myData.desc=cursor.getString(1);
myData.name = cursor.getString(5);
list.add(myData);
myData = null;
}
}
In my scenario i am having 3 records in sqlite which were fetched from websercive that contains id,name,description and image now i want to display the first record and second one after flipping the first record.and 3 one after second record flips..
What i have done so far is
while (cursor.moveToNext())
{
String temp_bookid = cursor.getString(0);
Log.i("temp_bookid",temp_bookid);
String temp_desc=cursor.getString(1);
byte[] temp_image1 = cursor.getBlob(2);
byte[] temp_image2 = cursor.getBlob(3);
String temp_id=cursor.getString(4);
String temp_name = cursor.getString(5);
String temp_bname=cursor.getString(6);
mapId.add(temp_id);
mapBname.add(temp_bname);
mapBookId.add(temp_bookid);
mapName.add(temp_name);
mapDesc.add(temp_desc);
map2.add(temp_image2);
map1.add(temp_image1);
Log.i("temp_id of the page in sqlite", temp_id);
TextView txtDesc = (TextView) findViewById(R.id.tDescription);
text = (TextView) findViewById(R.id.tTitle);
text.setText(temp_name);
txtDesc.setText(temp_desc);
ImageView img = (ImageView)findViewById(R.id.smallImage);
img.setImageBitmap(BitmapFactory.decodeByteArray(temp_image1, 0,temp_image1.length));
txtName1 = (TextView) findViewById(R.id.tvName);
txtName1.setText(temp_bname);
break;
}
mContext = this;
vf = (ViewFlipper) this.findViewById(R.id.vfShow);
vf.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(final View view, final MotionEvent event) {
detector.onTouchEvent(event);
Log.i("ew","ae");
return true;
}
});
I am able to display first record data when i set break; statement otherwise it is displaying last record data..How can proceed for this approach?
First fetch all the records and store in List<YourDataClass> myList object from onCreate method. As I have just giving you the examples
Now after fetching the data and stored in your list object you need to implement flipper change event so when flipper was change get the current position and using this position get the data as object from your list object. As you move right/left it will giving you the current position and you just need to use this position to fetch the records from list object
For example
Your POJO class will store the data MyData.java
public class MyData{
public long id = -1;
public String name = "";
public String description = "";
public String imagePath = ""; /// I don't know you want exactly, you need to implement image as per your requirement.
}
In your activity
private List<MyData> myList = new ArrayList<MyData>();
oncreate(){
fetchData(); // you need to implement this in AsyncTask so UI was not block just implement AsyncTask and call this method in doInBackground().
// after this you can implment View flipper and add view and set the data by fetch the list object using current view flipper position.
}
private void fetchData(){
while (cursor.moveToNext()){
MyData myData = new MyData();
myData.id = cursor.getLong(0);
myData.desc=cursor.getString(1);
myData.name = cursor.getString(5);
list.add(myData);
myData = null;
}
}
I am now stuck at a point and can't find any solution.
Description : I have a sqlite database having a table(channel table) which have 4 column
uid channel_name cid(country id) rating
uid is Unique channel id.
I have three images with star rating if star is yellow then channel have either 4 or 5 rating
if star is half yellow then channel rating is 2 or 3. if star is white then rating 1 will be considered.
I am showing these three images from gallery widgets in android. ant the channel name below star images. according to channel rating.
public View getView(int paramInt, View paramView, ViewGroup paramViewGroup) {
View view = null;
Cursor mCursor=db.dataChannelsName();
mCursor.moveToFirst();
String [] channels_name = new String[mCursor.getCount()];
for(int icount=0; icount<mCursor.getCount();icount++) {
channels_name[icount] = mCursor.getString(mCursor.getColumnIndex("name"));
mCursor.moveToNext();
}
if(paramView == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
view = inflater.inflate(R.layout.items1, null);
ImageView image1 = (ImageView) view.findViewById(R.id.image1);
TextView description = (TextView) view.findViewById(R.id.description);
image1.setImageResource(mImageIds[paramInt]);
description.setTextColor(0xffffffff);
description.setText(channels_name[paramInt]);
} else {
view = paramView;
}
return view;
Question 1:
How will i show only these three images for all channel with different channels name.?
Question 2:
It can be possible to have same name channel in database
I am using sql queries and cursor for retrieving data.
Now my problem is when user will select the particular channel from the gallery then there is a possibility that there can be more than one channel with same name.
I just want to store the uid when user click on the channel name from the gallery??
EDIT I just solved the second question but i am stuck at question 1
any help would be appreciated.
Lets begin fixing some things, shall we?
public View getView(int paramInt, View paramView, ViewGroup paramViewGroup) {
View view = null;
Cursor mCursor=db.dataChannelsName();
mCursor.moveToFirst();
String [] channels_name = new String[mCursor.getCount()];
for(int icount=0; icount<mCursor.getCount();icount++) {
channels_name[icount] = mCursor.getString(mCursor.getColumnIndex("name"));
mCursor.moveToNext();
}
Now the getView Function is called everytime a listView displays a new Row (even when scrolling!!)...I'm assuming db.dataChannelName() fires a query SELECT * from channel (or worse, you might be opening and closing the database)....This is a very expensive operation, you should query it once in the constructor, store the array of channel names as a member variable and use it for the rest of the adapter.
Here's a concise way..
public View getView(int paramInt, View view, ViewGroup paramViewGroup) {
if(view== null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
view = inflater.inflate(R.layout.items1, null);
}
ImageView image1 = (ImageView) view.findViewById(R.id.image1);
TextView description = (TextView) view.findViewById(R.id.description);
image1.setImageResource(mImageIds[paramInt]); // i'm assuming 0 - 0 star, 1 - 1 star, etc...
description.setTextColor(0xffffffff);
description.setText(channels_name[paramInt]); //remember channel_name was obtained in the constructor.
return view
}