android listview getting correct icons - android

I have ListView with icons. Every ListView row either has a different icon or or doesn't have an icon.
I am able to get correct icons for rows which should have them but problem is, in rows where there shouldn't be any icon there is some icon.
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.list_item, null);
TextView title = (TextView) vi.findViewById(R.id.name);
ImageView icon = (ImageView) vi.findViewById(R.id.icon);
HashMap<String, String> item = new HashMap<String, String>();
item = data.get(position);
String imgPath = ASSETS_DIR + item.get(myTable.KEY_PIC) + ".png";
try {
Bitmap bitmap = BitmapFactory.decodeStream(vi
.getResources().getAssets().open(imgPath));
icon.setImageBitmap(bitmap);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
title.setText(item.get(myTable.KEY_NAME));
return vi;
}
KEY_PIC always has a value and if KEY_PIC's value is equal to some icon's filename only then it should show icon. I cant figure out how to code it. I should do something in if-else i guess.

Firstly you've done a bad thing by putting HashMap<String, String> item = new HashMap<String, String>(); in your getView(). Right now you're making a new one of these for every row re-shown and that's unneeded. just delete it and use:
String imgPath = ASSETS_DIR + data.get(position).get(myTable.KEY_PIC) + ".png";
Quite honestly i can't understand how it is that you see an icon if you claim that your path doesn't lead to anything if the row isn't supposed to be showing something. If it worked well, then you could simply catch the exception that might occur upon setting and do nothing with it. Looking into the actual value of data at that position should yield insight. if it were me, i'd just put null at those positions.
A temporary alternative solution is to make a boolean array for each of the positions in your listview and then only perform your icon setting if the value at that position checks out.
boolean[] varIcon = {
true,
false,
false,
true,
false,
true };
// ...
// then in the getView() now;
if (varIcon[position] == true) {
String imgPath = ASSETS_DIR + data.get(position).get(myTable.KEY_PIC) + ".png";
try {
Bitmap bitmap = BitmapFactory.decodeStream(vi
.getResources().getAssets().open(imgPath));
icon.setImageBitmap(bitmap);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

The likely problem is that the views are getting recycled and you're never clearing the image that was previously set, try this to prove it:
String imgPath = ASSETS_DIR + item.get(myTable.KEY_PIC) + ".png";
try {
Bitmap bitmap = BitmapFactory.decodeStream(vi
.getResources().getAssets().open(imgPath));
icon.setImageBitmap(bitmap);
} catch (Exception e) {
e.printStackTrace();
icon.setImageDrawable(null);
}
However, relying on exception handling for a perfectly valid outcome is not a good practice (nor performance friendly). I would recommend you make your myTable.KEY_PIC column return null, and then you can do:
String imageName = item.get(myTable.KEYP_PIC);
if (imageName == null) {
icon.setImageDrawable(null);
} else {
//your code
}
Which is much cleaner.

Related

getView() is not working as i supposed

I am going to develop a APP where i am using customize alert dialog. Data have come from database to this alert-dialog.
menu_to_showdialogCursor = dh.rawQuery("SELECT _id ,item_name,Item_cost FROM order_customer WHERE item_name LIKE ? AND Item_cost LIKE ?", new String[]{"%","%"});
OrderListAdapter orderAdapter = new OrderListAdapter(MainScreen.this,menu_to_showdialogCursor );
orderList.setAdapter(orderAdapter);
ABove line is calling my Adapter class.Now i ma going to show my getView() in adapter class
public View getView(int position, View convertView, ViewGroup parent) {
OrderViewHolder orderViewHolder = null;
if (convertView == null) {
orderViewHolder = new OrderViewHolder();
convertView = inflater.inflate(R.layout.order_list_row, null);
orderViewHolder.setTvTitle((TextView) convertView
.findViewById(R.id.orderTitle));
orderViewHolder.setTvPrice((TextView) convertView
.findViewById(R.id.orderPrice));
orderViewHolder.setIvDelete((ImageButton) convertView
.findViewById(R.id.deleteOrder));
convertView.setTag(orderViewHolder);
} else {
orderViewHolder = (OrderViewHolder) convertView.getTag();
}
if (position != 0)
{
System.out.println(" value of position :"+position);
List lit = new ArrayList();
List litp = new ArrayList();
// System.out.println(" value of postion of cursor : ");
OrderViewHolder odr_obj = null;
if (oStarterCursor.moveToFirst()) {
do{
odr_obj = new OrderViewHolder();
title = oStarterCursor.getString(oStarterCursor.getColumnIndex("item_name"));
System.out.println("value of title :"+title);
lit.add(title);
price = oStarterCursor.getString(oStarterCursor.getColumnIndex("Item_cost"));
System.out.println("value of price :"+price);
litp.add(price);
}while(oStarterCursor.moveToNext());
}
// _id = oStarterCursor.getInt(oStarterCursor.getColumnIndex("_id"));
if (title != null) {
title = title.trim();
Iterator it = lit.iterator();
while (it.hasNext()) {
int i =0;
//System.out.println(" data iterator "+it.next().toString());
String test =it.next().toString();
System.out.println(" iterator vavue :"+test);
orderViewHolder.getTvTitle().setText(test);
}
orderViewHolder.getTvTitle().setTextColor(R.color.black);
orderViewHolder.getTvTitle().setTextSize(12);
orderViewHolder.getTvTitle().setTypeface(Typeface.DEFAULT);
orderViewHolder.getTvTitle().setGravity(
Gravity.CENTER_VERTICAL);
}
if (price != null) {
price = price.trim();
orderViewHolder.getTvPrice().setText(price + ".00");
orderViewHolder.getTvTitle().setTextColor(R.color.black);
orderViewHolder.getTvTitle().setTextSize(12);
orderViewHolder.getTvTitle().setTypeface(Typeface.DEFAULT);
orderViewHolder.getTvTitle().setGravity(
Gravity.CENTER_VERTICAL);
}
//_id = oStarterCursor.getInt(oStarterCursor.getColumnIndex("_id"));
//convertView.setTag(R.id.orderTitle, _id);
if (orderViewHolder.getIvDelete() != null) {
//orderViewHolder.getIvDelete().setTag(R.id.orderTitle, _id);
}
}
return convertView;}
Problem is that in my data base there is two row as in below image..
But in my alert dialog only showing one row twice. I did not get where is logical mistake.For conveniences i am going to show my screen-shot
So Where is problem i can't get please some body help me take out of this problem.
I think it's your line :
if (position != 0)
The first line of an adapter is 0 so it will not set the data for the first line of data.
I believe its because you are using getView wrong, getView does not just get called once it gets called many times. you are looping through your cursor each time getView is called so you are only displaying the last item in the cursor after you loop through your 2 lists.
if you are getting data from a cursor you should be using SimpleCursorAdapter and then override bindView and just use the cursor variable in the method each time its called
Edit
basically along the lines of this
oStarterCursor.moveToPosition(position);
orderViewHolder.getTvTitle().setText(oStarterCursor.getString(oStarterCursor.getColumnIndex("item_name")));
is all you need to get the data really

Image in listview via database+assets

I have a database which has a name of an animal, and in an other column a sound of the animal.
The listview works fine, and now I would like to extend it with an image out of the assets.
For this I've read about how to get the assets data and use it.
An example I've tried worked fine for me.
Now I want this "assets" code (at least I think I want this) in the extended BaseAdapter class.
Unfortunately I'm doing something wrong as I can't use the getAssets() in the BaseAdapter.
The problem starts in the try-catch block: " getAssets " doesn't get recognized
Which way would I think of solving this?
Creating another class in which this assets code can run in an extended "Activity"?
Or are there better ways of showing an image via database info in a listview?
Thank you for your support in my quest to get familiar with Android / Java.
public View getView(int position, View convertView, ViewGroup parent) {
// get view reference
View view = convertView;
// if null
if(view == null) {
// inflate new layout
view = mInflater.inflate(R.layout.layout_list_item, null);
// create a holder
ViewHolder holder = new ViewHolder();
// find controls
holder.txtName = (TextView)view.findViewById(R.id.txtName);
holder.txtPicture = (ImageView)view.findViewById(R.id.txtPicture);
// set data structure to view
view.setTag(holder);
}
// get selected user info
UserInfo userInfo = mListUserInfo.get(position);
// if not null
if(userInfo != null) {
// query data structure
ViewHolder holder = (ViewHolder)view.getTag();
// set data to display
holder.txtName.setText(userInfo.getName() + ", " + userInfo.getPicture() );
try {
// get input stream
InputStream ips = getAssets().open( userInfo.getPicture() + ".jpg");
Log.d("Imageloading", "Reading: " + ips);
// load image as Drawable
Drawable d = Drawable.createFromStream(ips, null);
// set image to ImageView
holder.txtPicture.setImageDrawable( d );
}
catch(IOException ex) {
Log.e("Imageloading", "Could not load '" + ex.getMessage()+ "'!");
}
}
// return view
return view;
}
I've just edited the code.
To solve the getAssets() thing I've done the following:
holder.txtPicture.setImageDrawable( getSomePicture(null, userInfo.getPicture() + ".jpg") );
public Drawable getSomePicture(Context myContext, String WhichPicture) throws IOException {
// get input stream
InputStream ips = myContext.getAssets().open( WhichPicture );
Log.d("Imageloading", "Reading: " + ips);
// load image as Drawable
Drawable d = Drawable.createFromStream(ips, null);
return d;
}
This still is not the solution, researching some more....
Found an interesting source for Lazy Loading
to call getAssets() function in non-activity class you need reference to Context. In your updated code you called function 'getSomePicture()' and passed null to myContext parameter. that means your code will fail because you have myContext.getAssets() later in your method code.
try to do this in your getView method:
Context context = getContext();
holder.txtPicture.setImageDrawable( getSomePicture(context, userInfo.getPicture() + ".jpg") );
You won't have access to the getAssets() method because that is a method that only the Context (and it's subclass, Activity) have. What I find is easiest here is to make your BaseAdapter subclasses private inner classes of the Activity in which it is to be used. That way, you'll have access to the getAssets() method.
Here is what this might look like:
public class YourExampleActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
}
private class YourListAdapter extends BaseAdapter {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// get view reference
View view = convertView;
// if null
if(view == null) {
// inflate new layout
view = mInflater.inflate(R.layout.layout_list_item, null);
// create a holder
ViewHolder holder = new ViewHolder();
// find controls
holder.txtName = (TextView)view.findViewById(R.id.txtName);
holder.txtPicture = (ImageView)view.findViewById(R.id.txtPicture);
// set data structure to view
view.setTag(holder);
}
// get selected user info
UserInfo userInfo = mListUserInfo.get(position);
// if not null
if(userInfo != null) {
// query data structure
ViewHolder holder = (ViewHolder)view.getTag();
// set data to display
holder.txtName.setText(userInfo.getName() + ", " + userInfo.getPicture() );
try {
// get input stream
InputStream ips = getAssets().open( userInfo.getPicture() + ".jpg");
Log.d("Imageloading", "Reading: " + ips);
// load image as Drawable
Drawable d = Drawable.createFromStream(ips, null);
// set image to ImageView
holder.txtPicture.setImageDrawable( d );
}
catch(IOException ex) {
Log.e("Imageloading", "Could not load '" + ex.getMessage()+ "'!");
}
}
// return view
return view;
}
// Override other key methods of BaseAdapter here
}
}
Alternatively, you could take in a Context object in the constructor when the BaseAdapter subclass is instantiated, and keep a reference to that with which to call getAssets() on. Please post a comment if you need an example of this.

Load resource (layout) from another apk dynamically

I managed to pull the layouts, and i add it to my viewflipper, however, there it is loaded as blank.
The code is,
Resources packageResources;
Context packageContext;
try
{
packageResources = pm.getResourcesForApplication(packageName);
packageContext = this.createPackageContext(packageName, Context.CONTEXT_INCLUDE_CODE + Context.CONTEXT_IGNORE_SECURITY);
}
catch(NameNotFoundException excep)
{
// the package does not exist. move on to see if another exists.
}
Class layoutClass;
try
{
// using reflection to get the layout class inside the R class of the package
layoutClass = packageContext.getClassLoader().loadClass(packageName + ".R$layout");
}
catch (ClassNotFoundException excep1)
{
// Less chances that class won't be there.
}
for( Field layoutID : layoutClass.getFields() )
{
try
{
int id = layoutID.getInt(layoutClass);
XmlResourceParser xmlResourceLayout = packageResources.getLayout(id);
View v = new View(this, Xml.asAttributeSet(xmlResourceLayout));
this.viewFlipper.addView(v);
}
catch (Exception excep)
{
continue;
}
}
I get no errors, and i debugged and checked. The layout IDs are correct. However, in my viewFlipper its just blank. No warnings or errors i can find.
Finally got it.... Its actually simple !!!!
Here is what i did...
In the target apk, there is only resources and layouts with no application or activity code. I created a class,
public final class ViewExtractor
{
private static final int NUMBER_OF_LAYOUTS = 5;
public static View[] getAllViews(Context context)
{
View[] result = new View[ViewExtractor.NUMBER_OF_LAYOUTS];
result[0] = View.inflate(context, R.layout.layout_0, null);
result[1] = View.inflate(context, R.layout.layout_1, null);
result[2] = View.inflate(context, R.layout.layout_2, null);
result[3] = View.inflate(context, R.layout.layout_3, null);
result[4] = View.inflate(context, R.layout.layout_4, null);
return result;
}
}
Then in my current application, I modified my earlier code. The modification takes place once package has been verified to exist.
// If the package exists then get the resources within it.
// Use the method in the class to get the views.
Class<?> viewExtractor;
try
{
viewExtractor = packageContext.getClassLoader().loadClass(packageName + ".ViewExtractor");
}
catch (ClassNotFoundException excep)
{
continue;
}
View[] resultViews;
try
{
Method m = viewExtractor.getDeclaredMethod("getAllViews", Context.class);
resultViews= (View[])m.invoke(null, new Object[]{packageContext});
for( View v : resultViews)
{
this.viewFlipper.addView(v);
}
}
catch (Exception excep)
{
excep.printStackTrace();
}
You are not inflating a layout. You are creating an empty View and adding it to your ViewFlipper.
I am currently doing this. It only works if a know the packageName of activity or fragment from the .apk that should provide the layout hierarchy (I call this foreign context). And you need to know the name of the layout you want to inflate (e.g. R.layout.mylayout -> "mylayout")
Context c = createPackageContext(foreignPackageName,
Context.CONTEXT_INCLUDE_CODE|Context.CONTEXT_IGNORE_SECURITY); //create foreign context
int resId = c.getResources.getIdentifier(mylayoutName,"layout",foreignPackageName);
LayoutInflater myInflater = LayoutInflater.from(c); //Inflater for foreign context
View myLayout = myInflater.inflate(resId,null,false); //do not attach to a root view

Adding an unknown amount of items to a List in a Dialog for my Android app

I'm trying to cycle through a JSONObject to see how many passengers there are, and then I want to display them all nicely in a dialog window. It looks like there are a few ways to do it, but overall I'm just confused on how to go about it. This is the closest I've gotten, it works but as you can see I'm only adding one item. So there is only one item displaying in my alertdialog, and there should be a couple more. My alertdialog (called ticketbuilder) is created somewhere else, I'm just trying to add everything in this for loop. How do I add all of my passengers to the list to display? Thanks a ton in advance!
for (int i = 0; i < tickets.length(); i++) {
final int ticketCount = i;
JSONObject ticket;
try {
ticket = tickets.getJSONObject(ticketCount);
passengername = ticket.getString("passengername");
ticketnumber = ticket.getString("ticketnumber");
CharSequence[] array = {passengername + " \n" + ticketnumber};
ticketBuilder.setItems(array, null); //adding to my dialog
} catch (JSONException e) {
System.out.println(e);
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Try putting the CharSequence outside the loop and init it like this:
CharSequence[] array = new CharSequence[tickets.length()];
Then in the loop add thing to the array:
array[i] = {passengername + " \n" + ticketnumber};
Move ticketBuilder.setItems so it is after, outside the loop.

app not showing data when opend it for the second time

i am looking to make game of questions and answers.i had taken a textview and 4 radio group buttons.and i am fetching data from the external data file from the assets folder.when i installs the app into the emulater it works fine.when i reopens the app in the emulater it is just showing question not showing any text in the radio buttons.here is my code in the data base file
public String makeatext(String My_database_table,int i) {
SQLiteDatabase myDB = getDatabase();
String results = new String();
try {
String firstColumn = "questions";
// final String KEY_ROWID = "id";
// Cursor c = myDB.rawQuery("SELECT questions FROM " +
// My_database_table+ ";",null);
Cursor c = myDB.query(true, My_database_table,
new String[] { firstColumn },null, null, null, null, null,
null);
int iquestion = c.getColumnIndex(firstColumn);
if(c.moveToPosition(i)){
results = c.getString(iquestion)+"\n";
}
//while (c.moveToPosition(1)) {
//String firstName = c.getString(iquestion);
//results =(" "+ firstName + " ");
//}
return results;
} catch (Exception e) {
Log.e("ERROR","ERROR in Make test file :"+e.toString());
e.printStackTrace();
// TODO: handle exception
}
return results;
}
and in the Activity file i am just calling it as
String shoow = myDb.makeatext("question", Qno);
showQuestion.setText(shoow);
and on the top of the oncreate methode i initilized the data base asprivate final DataBaseHelper myDb = new DataBaseHelper(this);
can any one say me why this is happenig.do i need to write the for loop in the activity file also or shall i take a cursor in the activity class .
plz help me out
thanks in advance
for radio buttons the code in the database file is as follows as i have 4 buttons the code for 4 buttons will be as same as this
public String makeExtra1(String My_database_table ,int positions) {
String results = new String();
try {
String secondColumn = "Extra1";
Cursor c = myDataBase.query(true, My_database_table,
new String[] { secondColumn }, null, null, null, null, null,
null);
int iExtra1 = c.getColumnIndex(secondColumn);
if(c.moveToPosition(positions)){
results = results+c.getString(iExtra1)+"\n";
}
return results;
} catch (Exception e) {
Log.e("ERROR","ERROR in Make test file :"+e.toString());
e.printStackTrace();
// TODO: handle exception
}
return results;}
and in the Activity file
String showextra1 = myDb.makeExtra1("question", Qno);
r0.setText(showextra1);
i repeted this thing for 4 times as changing the makeExtra2,3,4 and in the assinged to r1,r2,r3 as above.
You should call Cursor.close() after reading data from it. Better to do it finally{} block.
If you want to raise only one answer per query - fill where param of myDataBase.query().
The unreachable code error is because you are writing finally{} block after return results;
Move this line after the finally{} block, eclipse will not give you any error.
Also do use myDB.close(); in this finally block.

Categories

Resources