ListView button not always working - android

As you can see, i have a listview with textviews and a button pressing of which causes a phone call. The problem is that after selecting a list item ( which always works) pressing the button leads to weird behavior: sometimes it works, sometimes it does not. I have read similar topics but was unable to find a solution. Any help would be appreciated
for (i = 0; i < final_itinList.size(); i++) {
final_itinList.get(i).put("num", String.valueOf(i + 1));
String timi = final_itinList.get(i).get("diff");
final_itinList.get(i).put("diff", timi + "Km");
}
final ListAdapter adapter = new SimpleAdapter(
CheckItineraries.this, final_itinList,
R.layout.list_item2, new String[] { "num",
"startPoliPro", "finalPoliPro", "diff" },
new int[] { R.id.number_n, R.id.startpoli,
R.id.finalpoli, R.id.numKm });
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent,
View container, int position, long id) {
#SuppressWarnings("unchecked")
HashMap<String, Object> obj = (HashMap<String, Object>) adapter.getItem(position-1);
final String phone_number = (String) obj.get("phone_number");
Button btnphone = (Button) findViewById(R.id.btnphone);
btnphone.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View btnphone) {
try {
Intent intent = new Intent(
Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+phone_number));
startActivity(intent);
} catch (Exception e) {
Log.e("Demo application",
"Failed to invoke call", e);
}

There are couple of things which not seems to be right in your code snippet using ListView. I would recommend to look into Google I/O presentation for proper using ListView in android.
The problem in your code snippet that you're trying to bind the button action event on ListView row Item onClick event - which is completely wrong! You've to override the getView method of adapter and inflate the childview for each row item with provided dataset.
For example:
public class CustomAdapter extends SimpleAdapter {
private Context context;
private int layoutResId;
public CustomAdapter(Context context, List<? extends Map<String, ?>> data,
int resource, String[] from, int[] to) {
super (context, data, resource, from, to);
// hold the items
this.context = context;
this.layoutResId = resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolderItem viewHolder;
if (converView == null) {
// inflate the layout
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
convertView = inflater.inflate(layoutResId, parent, false);
// well set up the ViewHolder
viewHolder = new ViewHolderItem();
viewHolder.phoneBtn = (Button)view.findById(R.id.btnphone);
// store the holder with the view.
convertView.setTag(viewHolder);
}
else {
// we've just avoided calling findViewById() on resource everytime
// just use the viewHolder
viewHolder = (ViewHolderItem) convertView.getTag();
}
// Don't know the purpose of position-1 here.
HashMap<String, Object> data = (HashMap<String, Object>) getItem(position-1);
if (data != null) {
String phone_number = (String)data.get("phone_number");
// set button action
viewHolder.phoneBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + phone_number));
startActivity(intent);
} catch (Exception e) {
Log.e("Demo application", "Failed to invoke call", e);
}
}
}
}
}
/**
* Hold View items
*/
static class ViewHolderItem {
private Button phoneBtn;
}
}
Now you can create the object of CustomAdapter and assign to ListView.
CustomAdapter adapter = new CustomAdapter(
CheckItineraries.this,
final_itinList,
R.layout.list_item2,
new String[] { "num", "startPoliPro", "finalPoliPro", "diff" },
new int[] { R.id.number_n, R.id.startpoli, R.id.finalpoli, R.id.numKm });
// set the adapter
list.setAdapter(adapter);
Note: The ViewHolderItem defined earlier is android design pattern that reduce the look-ups findViewById() and increase the performance for smooth scrolling. You can find more about it here.

You are setting a button listener inside an list item listener.
That means: when you click a list item, the button click listener is set. Only then can you click that specific button to invoke the call.
What you have to do is to create a custom adapter, that sets the button listener once the list item is inflated (created). Here's an example:
for (i = 0; i < final_itinList.size(); i++) {
final_itinList.get(i).put("num", String.valueOf(i + 1));
String timi = final_itinList.get(i).get("diff");
final_itinList.get(i).put("diff", timi + "Km");
}
final ListAdapter adapter = new SimpleAdapter(
CheckItineraries.this, final_itinList,
R.layout.list_item2, new String[] { "num",
"startPoliPro", "finalPoliPro", "diff" },
new int[] { R.id.number_n, R.id.startpoli,
R.id.finalpoli, R.id.numKm }) {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
// Fetch the phone number (dunno why you have position-1...)
HashMap<String, Object> obj = (HashMap<String, Object>) getItem(position-1);
final String phone_number = (String) obj.get("phone_number");
Log.d("phone", phone_number);
// Set the button click listener
Button btnphone = (Button) view.findViewById(R.id.btnphone);
btnphone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View btnphone) {
try {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + phone_number));
startActivity(intent);
} catch (Exception e) {
Log.e("Demo application", "Failed to invoke call", e);
}
}
});
return view;
}
};
Note: This way of re-setting the button listener is inefficient, but nevertheless it should work (as long as your other code works). If you run into further problems you should ask another question.

Related

Android Picasso 2.5.2, showing images from adapter inside listivew. With async task

I would like to use Picasso library to download and show images that are in URL's inside JSON data from my server.
I've lost all hope, I saw something about custom adapter but to no avail.
I need help here.
Here's how I do stuff now to show data from json inside onPostExecute:
protected void onPostExecute(JSONObject objdanejson){
pDialog.dismiss();
try {
android = objdanejson.getJSONArray(TAG_ZAWARTOSC);
for(int i = 0; i < android.length(); i++){
JSONObject c = android.getJSONObject(i);
final String akt_tytul = c.getString(TAG_TYTUL);
final String akt_skrot = c.getString(TAG_SKROT);
final String akt_tresc = c.getString(TAG_TRESC);
final String akt_id = c.getString(TAG_ID);
final String akt_IMG = c.getString(TAG_IMG);
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_TYTUL, akt_tytul);
map.put(TAG_SKROT, akt_skrot);
map.put(TAG_ID, akt_id);
map.put(TAG_TRESC, akt_tresc);
map.put("http://www.apirest.poligon.webimpuls.pl/"+TAG_IMG, akt_IMG);
oslist.add(map);
lista_aktualnosci = (ListView)findViewById(R.id.lista_aktualnosci);
final ListAdapter adapter = new SimpleAdapter(aktualnosci.this, oslist,
R.layout.aktualnosc_item,
new String[]{TAG_TYTUL, TAG_SKROT, TAG_IMG}, new int[]{R.id.aktTytul, R.id.aktSkrot, R.id.aktIMG});
lista_aktualnosci.setAdapter(adapter);
lista_aktualnosci.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(aktualnosci.this, "Kliknąłeś na " + oslist.get(+position).get("akt_tytul"),Toast.LENGTH_SHORT).show();
Intent czytaj = new Intent(aktualnosci.this, aktualnosc_czytaj.class);
czytaj.putExtra("tytuł",oslist.get(+position).get("akt_tytul"));
czytaj.putExtra("tresc",oslist.get(+position).get("akt_tresc"));
czytaj.putExtra("id",oslist.get(+position).get("akt_id"));
startActivity(czytaj);
}
});
}
}
catch (JSONException e) {
e.printStackTrace();
}
}
EDIT:
How my custom controler looks:
oslist.add(map);
lista_aktualnosci = (ListView)findViewById(R.id.lista_aktualnosci);
/* final ListAdapter adapter = new SimpleAdapter(aktualnosci.this, oslist,
R.layout.aktualnosc_item,
new String[]{TAG_TYTUL, TAG_SKROT}, new int[]{R.id.aktTytul, R.id.aktSkrot});
*/
class ListAdapter extends ArrayAdapter<ClipData.Item> {
public ListAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
public ListAdapter(Context context, int resource, List<ClipData.Item> items) {
super(context, resource, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.aktualnosc_item, null);
}
ClipData.Item p = getItem(position);
if (p != null) {
aktTytul = (TextView)findViewById(R.id.aktTytul);
aktSkrot = (TextView)findViewById(R.id.aktSkrot);
aktIMG = (ImageView)findViewById(R.id.aktIMG);
}
return v;
}
}
lista_aktualnosci.setAdapter(adapter);
Create a class that extends Simple Adapter or Base Adapter. In getView() the adapter will ask you to create a list item when this is needed. As you create the item you can use Picasso to display the image in whatever image view you've selected for this purpose.
That being said you should ditch ListView and use RecyclerView instead - for which you can find all the information you need here
Other stuff that may improve your code are things like Retrofit and Gson.
Does that help?
you can get your image from listview. You can this code your activity after set adapter then you can set your imageview.
for(int i = 0; i < this.listView.getChildCount(); i ++) {
View view = this.listView.getChildAt(i);
ImageView img= (ImageView)view.findViewById(R.id.yourimage);
//do something your image
}

How to add multiple items in Listview Android

I'm working on an Android application of booking medicine offline. I have used ListView for Cart, but whenever I add a new item in cart, my previous item get replaced.
L1 = imageacidity
L2 = imagecough
if(msg.toString().equals("L1")) {
adapter = new ContactImageAdapter(this, R.layout.list, imageacidity);
ListView dataList = (ListView) findViewById(R.id.list);
dataList.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
if(msg.toString().equals("L2"))
{
adapter = new ContactImageAdapter(this, R.layout.list, imagecough);
ListView dataList = (ListView) findViewById(R.id.list);
dataList.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
Here I have 5 elements in imageacidity and Imagecough Array. Whenever I select 1 item, it gets added in cart, but when I try to select another item it get replaced with new one.
You have to Add the element inside your adapter.
I will post a custom Adapter and show you how to add elements properly.
Adapter:
public class YourAdapter extends BaseAdapter {
List<String> itens;
private Context mContext;
private static LayoutInflater inflater = null;
public YourAdapter(Context context, List<String> itens){
this.itens = itens;
mContext = context;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return itens.size();
}
public String getItem(int position) {
return itens.get(position);
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (convertView == null)
vi = inflater.inflate(R.layout.list_row, parent, false);
String msg = itens.get(position);
TextView tx = vi.findViewById(R.id.your_id);
tx.setText(msg);
return vi;
}
public void addItem(String item){
itens.add(item);
}
public void addItens(List<String> itens){
this.itens.addAll(itens);
}
}
ListView:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter = new CustomAdapter(this,yourListOfItens);
listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
You can set initial data on constructor of adapter, or use methods addItem and addAll on a click button for example.
The problem you are describing of the data being removed is happening because making a new ContactImageAdapter and calling setAdapter, which will completely remove the data that was already in the ListView.
If you want to properly implement the code in the question, you need something like this.
String msg = ""; // TODO: get this String value
ListView dataList = (ListView) findViewById(R.id.list);
// TODO: Define a single List to store the data and use that in *one* adapter
List<Contact> contacts = new ArrayList<Contact>();
adapter = new ContactImageAdapter(this, R.layout.list, contacts);
dataList.setAdapter(adapter);
// TODO: Replace this with the object to add to the adapter
Contact contact = null;
if(msg.equals("L1")) {
// TODO: Use whatever values you want for "L1"
int img = R.drawable.bati_acidity_1;
String name = "Amlapitta";
String price = "price 170";
contact = new Contact(img, name, price);
}
else if(msg.equals("L2")) {
// TODO: Use whatever values you want for "L2"
int img = R.drawable.bati_acidity_2;
String name = "Amlapitta2";
String price = "price 270";
contact = new Contact(img, name, price);
}
if (contact != null) {
contacts.add(contact);
adapter.notifyDataSetChanged();
}
Another problem is that you are calling notifyDataSetChanged without actually changing the datasets of imageacidity or imagecough.
You can use an algorithm (logic) on the InputListAdapter checking and verifying if there is a MedicineVO (Value Object Pattern) item on old list before the calling notyChange(..) method. In addition, you can wrapping the logic in other class such as MedicineLogic to improve the adapter readability.
See the sample code below:
public class MedicineInputListAdapter extends ArrayAdapter<MedicineVo> {
public static final int[] COLORS = new int[] { Color.WHITE, Color.BLUE };
private Context mContext;
private List<MedicineVo> medicineVos;
private MedicineVo medicineVoActual;
public BasePreOSPreventivaCorretivaInputListAdapter(Context context, int resource, List<MedicineVo> medicineVos) {
super(context, resource, medicineVos);
this.medicineVoActual = new MedicineVo();
this.medicineVos = new ArrayList<MedicineVo>();
this.medicineVos.addAll(medicineVos);
this.mContext = context;
}
private static class ViewHolder {
TextView mMedicineTextView;
//------------------------------------------------------
// others Android view components
//------------------------------------------------------
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
//------------------------------------------------------
// mapper from xml to view and add itens to holder
//------------------------------------------------------
//------------------------------------------------------
// add event action to the mMedicineTextView
//------------------------------------------------------
viewHolder.mMedicineTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
TextView textView = (TextView) view;
MedicineVo medicineVo = (MedicineVo) textView.getTag();
boolean selected = medicineVo.getSelected();
if (selected) {
/*do it*/
}
refreshPreOSMaterialWhenUpdate(preOSMaterialVo);
}
});
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
}
//------------------------------------------------------
// get item and adjust color
//------------------------------------------------------
MedicineVo item = getItem(position);
/*do it*/
return convertView;
}
public void refreshMedicineListWhenUpdate(MedicineVo medicineVo){
List<MedicineVo> newMedicineVos = new ArrayList<MedicineVo>();
for (MedicineVo medicineVoOnList : medicineVos) {
if( StringUtils.isNull(medicineVoOnList.getId()) )
continue;
if( MedicineLogic.existsOnList(medicineVos, medicineVoOnList) )
continue;
/* others checks if necessary */
newMedicineVos.add(medicineVoOnList);
}
medicineVos.addAll(newMedicineVos);
}
}
If you can't select more but only one item of your ListView, this might help.As others have commented on the question, changing the adapter of a ListView can clear the selection too, but as I supposed the code you've posted is inside onCreate (or other kind of initialization) so setting the adapter there won't affect the selection (since there can't be selection without items... :) )

ArrayAdapter strange behaviour with id when items's height exceed Listview height

I'm facing a strange behaviour using an ArrayAdapter.
When the number of listview item exceed the height of the listView (say after item 8), the next item get the id 0 instead the id 9.
In my opinion this type of issue was explained here with the convertView, but i use it in the same way (i think).
The following code is my ArrayAdapter.
public class StepsAdapter extends ArrayAdapter<String> {
Context context;
List<String> steps;
public StepsAdapter(Context context, int resourceId, List<String> steps) {
super(context, resourceId, steps);
this.context = context;
}
private class ViewHolder {
EditText stepValue;
ImageView removeStep;
}
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
final String step = getItem(position);
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.row_step, null);
holder = new ViewHolder();
holder.stepValue = (EditText) convertView.findViewById(R.id.stepEdit);
holder.removeStep = (ImageView) convertView.findViewById(R.id.removeStep);
holder.stepValue.setText(step);
holder.removeStep.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context,"* Remove id step " + position, Toast.LENGTH_LONG).show();
steps.remove(position);
notifyDataSetChanged();
}
});
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
}
Then my main activity where i get existing data and put it in my listView, the add button and the save button.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_game);
mContext = getApplicationContext();
steps = new ArrayList<String>();
stepsAdapter = new StepsAdapter(mContext,R.layout.row_step,steps);
Gson gson = new GsonBuilder().create();
game = gson.fromJson(gameJson, Games.class);
/*
* Settings values
*/
gameNameValue.setText(game.getName());
gameBackgroundPreview.setBackgroundColor(game.getColor());
colorSelected = game.getColor();
for(int i = 0; i < game.getSteps().size() ; i++){
//steps.add(game.getSteps().get(i).toString());
//notifyDataSetChanged();
stepsAdapter.add(game.getSteps().get(i).toString());
}
final ListView listSteps = (ListView) findViewById(R.id.listViewSteps);
listSteps.setAdapter(stepsAdapter);
gameNameValue.setText(gameName);
addSteps.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
stepsId = steps.size();
Toast.makeText(getApplicationContext(), "addSteps : " + stepsId, Toast.LENGTH_LONG).show();
stepsAdapter.insert("newstep", stepsId);
}
});
buttonSaveGame.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String valueEditGameName = gameNameValue.getText().toString();
int valueColorBackaground = colorSelected;
String picture = "testPic";
for(int i=0; i < listSteps.getChildCount(); i++) {
LinearLayout rowLayout = (LinearLayout) listSteps.getChildAt(i);
//Log.e(TAG, ">> :) layout >>" + listSteps.getChildAt(i).getClass().getName());
EditText editRow = (EditText) rowLayout.getChildAt(0);
stepsValues.add(editRow.getText().toString());
//Log.e(TAG, ">> :) inside layout >>" + editRow.getText().toString());
}
if(valueEditGameName.trim().length() > 0 && picture.trim().length() >0 ){
Games game = new Games(valueEditGameName,valueColorBackaground,picture,stepsValues);
String goToSave = game.createJson();
Log.e(TAG, ">>Saved>>" + goToSave);
final CkdFile file = new CkdFile();
String saved = file.writeToSDFile(game.getName(), goToSave);
Toast.makeText(mContext, saved, Toast.LENGTH_LONG).show();
Intent backToMain = new Intent(mContext,MainActivity.class);
startActivity(backToMain);
} else {
Toast.makeText(mContext, "Fill all texts", Toast.LENGTH_LONG).show();
}
}
});
}
I try to add items in 2 different ways :
add item through : List steps
add item through : StepsAdapter stepsAdapter
Both give me same behaviour.
If someone has a clue to help understanding what i'm doing wrong with my implementation of ListView/ArrayAdapter.
Thanks in advance !
EDIT 1 :
After pushing some logs everywere, it understand the strange behaviour :
My adapter have only 6 slots (the limit came from the size of the listview in layout), and when my arraylist have more than 6 items, the getView select items only between 0 and 5.
I'm searching now a way to get the position in ArrayList and not the position in arrayadapter.
I faced same issue recently. Add following overrides to Adapter:
#Override
public int getViewTypeCount() {
return getCount();
}
#Override
public int getItemViewType(int position) {
return position;
}
I found a simple xml "trick" to avoid this behaviour : i set a biger height to listView.
<ListView
android:layout_width="match_parent"
android:layout_height="1000dp"
android:layout_gravity="center_horizontal"
android:id="#+id/listViewSteps"
android:layout_margin="10dp">
</ListView>
It's not really resolve but a take it ...

getting to another screen from listview row

In the following code, I want to set Onclick Listeners on some "elements" of my row. where should I place the setOnclick listener code? In the activity code or in the adapter? I suppose the first, but in that case how will I identify which row has been selected
(each row is supposed to get me to different views)?
Java code:
List<String[]> info=new ArrayList<String[]>();
String[] names_info=new String[5];
String[] phones_info=new String[5];
String[] map_info=new String[5];
String[] web_info=new String[5];
String[] photos_info=new String[5];
for(int i=0;i<names_info.length;i++)
{
info.add(new String[]{names_info[i],phones_info[i],map_info[i],web_info[i],photos_info[i]});
}
for (int i = 0; i < info.size(); i++) {
Log.d("TAG", "item " + i +
" name:" + info.get(i)[0] +
" info:" + info.get(i)[1]);
}
FacilitiesAdapter adapter = new FacilitiesAdapter(this,info,want_info_display,want_phone_display,want_photos_display);
//System.out.println(info[0]);
setListAdapter(adapter);
EDIT
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// When clicked, show a toast with the TextView text
//Toast.makeText(getApplicationContext(), ((TextView) arg1).getText(),
//Toast.LENGTH_SHORT).show();
Intent i33 = new Intent(HotelsScreen.this,AbousUsScreen.class);
i33.putExtra("position", arg2);
System.out.println(arg2);
System.out.println(info.get(arg2)[0]);
startActivity(i33);
}
});
I see results in Log, so that means that my info is getting its result normally.
This is my adapter.
public class FacilitiesAdapter extends ArrayAdapter<String[]> {
private final Context context;
List <String[]> dataList;
public FacilitiesAdapter(Context context, List<String[]> dataList, int need_phone, int need_info, int need_photos) {
super(context, R.layout.expand_row);
this.context = context;
this.dataList = dataList;
//this.tracks_condition=tracks_condition;
//this.count=count;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.expand_row, parent, false);
System.out.println("I am here");
String[] data = dataList.get(position);
String name=data[0];
TextView textView = (TextView) rowView.findViewById(R.id.name);
System.out.println("I am in the adapter "+name);
textView.setText(name);
return rowView;
}
}
EDIT 1:
am I supposed now to see in every item I click its position and its name? Cause I see nothing?
can be as simple as something alone these lines:
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3)
{
Intent i33 = new Intent(MyScreen.this,OtherScreen.class);
i33.putExtra("position", position);
startActivity(i33);
}
});
I think your biggest problem will be figuring out how to map a row to the appropriate screen. If you can do this, you can set up a Map object with all the mappings.
In your adapter, you can then use setTag() on the view and pass it what you get back from the Map, then creating a new Intent from it.
//In your adapter's getView() method...
Class activityClass = rowToActivityMap.get(someRowAttribute);
view.setTag(activityClass);
//In your click listener...
Class activityClass = (Class)view.getTag();
Intent intent = new Intent(this, activityClass);
startActivity(intent);

in ListView.setOnItemClickListener the (View)adapter.getChildAt(6); returns null

I have a ListView, whose every item (i.e TextView) is filled with Lyrics text of Song. Whenever i click an item it should be highlighted and previous selected item background should be changed to default. For this i use ListView.setOnItemClickListener as below:
public int songNo;
public int totalSongs;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lyric_display);
songNo=0;
totalSongs=7;
ListView songLyricsListView = (ListView) findViewById(R.id.LyricDisplayListView);
MediaPlayer soundPlayer = new MediaPlayer();
songLyricsListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View selectedView, int pos,
long arg3) {
**//set background to older selection**
View oldSelectedView;
oldSelectedView = (View)adapter.getChildAt(songNo);
oldSelectedView.setBackgroundColor(0x00000000);
songNo = pos;
selectedView.setBackgroundColor(0xFFFFFFFF);
songLyricsListView.smoothScrollToPosition(songNo);
try {
soundPlayer.reset();
soundPlayer.setDataSource("/sdcard/0"+Integer.toString(songNo)+".mp3");
soundPlayer.prepare();
soundPlayer.start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
String[] from = new String[] {"lyrics","translation"};
int[] to = new int[] {R.id.songTextView, R.id.translationTextView};
try {
InputStream is = getResources().openRawResource(R.raw.lyric_text);
BufferedInputStream bis = new BufferedInputStream(is);
int myInt=0;
for(int songno=0; songno<=totalSongs; songno++)
{
HashMap<String, String> map = new HashMap<String, String>();
ByteArrayBuffer myByteArray = new ByteArrayBuffer(100);
while((myInt = bis.read())!=-1)
{
if(myInt == 10) break;
myByteArray.append((byte)myInt);
}
String lyricsText = new String(myByteArray.toByteArray(), 0, myByteArray.length(), "UTF-8");
myByteArray.clear();
map.put("lyrics",lyricsText);
map.put("translation", Integer.toString(songno)+"- sample translation");
list.add((HashMap<String, String>)map);
}
bis.close();
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
adapter = new SpecialAdapter(
this,
list,
R.layout.lyrics_display_item,
from,
to );
songLyricsListView.setAdapter(adapter);
public class SpecialAdapter extends SimpleAdapter {
public SpecialAdapter(Context context, List> items, int resource, String[] from, int[] to) {
super(context, items, resource, from, to);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
if(position == songNo)
{
view.setBackgroundColor(0xFFFFFFFF);
}else
view.setBackgroundColor(0x00000000);
return view;
}
}
when i set bigger font size to list item, when i select 6th item and again i select 5th item, in the code line:
oldSelectedView = (View)adapter.getChildAt(songNo);
oldSelectedView is returned as null. But when i use small font, the list fits on a single screen and 6th item seletction and then 7th or 5th selection does't make any problem.
Please help me solve this problem..
It maybe has something todo with the ListAdapter not having the same position as your song number. Maybe using a custom list adapter and using an array solves the problem:
link
It's a sample of a custom list adapter in APIDemos
listadapter.notifyDataSetChanged() in onItemClickListner() fixed the problem..

Categories

Resources