I'm totally stuck with something. I'm trying to do simple de-reference of a clicked object in Android environment but for the life of me can't find a way.
I have a MainView where I load json objects and I pass these objects to my adapter where I find these to a list. I have onClick on a TextView items in a list to capture click events.
Issue: the OnClick fires but I can't get back the original bound object from there, or I'm not sure how? I was trying to use a position variable that increments when getView function gets called for each row, but my position when OnClick happens always points to the last record in my list. I also tried implementing onItemClick in MainView but that never seems to fire.
How can I get back the object I bound to my TextView? Thank you in advance for any assistance with this.
public class MainActivity extends AppCompatActivity {
private static final String LOCATION_KEY = "location";
SharedPreferences pref;
SharedPreferences.Editor editor;
public JSONObject jsonObj = null;
ListView mainList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.digitour.www.R.layout.activity_main);
// Load state from shared preferences
pref= getApplicationContext().getSharedPreferences("MyPref", MODE_PRIVATE);
editor=pref.edit();`enter code here`
mainList = (ListView) findViewById(com.digitour.www.R.id.checkableList);
try {
jsonObj=new JSONObject(pref.getString("json",null));
// Bind Data and pass the json object read from a file to the adapter
MainViewAdapter customListViewAdapter = new MainViewAdapter(this, jsonObj);
mainList.setAdapter(customListViewAdapter);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here is the adapters code:
public class MainViewAdapter extends BaseAdapter {
private LayoutInflater layoutInflater;
private Context context;
private JSONArray listItems;
private int positionPrivate;
private JSONObject jsonObj;
public MainViewAdapter(Context context, JSONObject jsonObj) {
layoutInflater = LayoutInflater.from(context);
this.context = context;
this.jsonObj = jsonObj;
JSONObject jObjectResult = null;
try {
jObjectResult = jsonObj.getJSONObject("Items");
this.listItems = jObjectResult.getJSONArray("Item");
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final SharedPreferences pref= context.getApplicationContext ().getSharedPreferences("MyPref", context.MODE_PRIVATE);
final SharedPreferences.Editor editor = pref.edit();
try {
positionPrivate = position;
if(convertView == null){
convertView = layoutInflater.inflate (com.digitour.www.R.layout.activity_row,parent,false);
}
TextView textView = (TextView) convertView.findViewById (com.digitour.www.R.id.rowText);
textView.setText(listItems.getJSONObject(position).getString ("description"));
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try{
//Trying to get here the bound object
TextView tv = (TextView)v;
int id = tv.getId();
if (listItems != null){
JSONObject clickedItem = listItems.getJSONObject(positionPrivate); // positionPrivate always indexed to last item in a list
Intent intent = new Intent(context, DetailActivity.class);
context.startActivity(intent);
}
} catch (Exception e){
e.printStackTrace();
}
}
});
return convertView;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
You have a single member variable private int positionPrivate that you store the index in. It can only hold one index, so ends up with the last index that was written to it.
Try removing this variable and just use the position parameter in your getView function.
JSONObject clickedItem = listItems.getJSONObject(position);
I think what you are looking for is a setTag(Object tag) method.
textView.setTag(position)
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = (int) textView.getTag()
if (listItems != null) {
JSONObject clickedItem = listItems.getJSONObject(position);
...
}
}
}
Related
I got the data from server to list view successfully with some online help. What I wanted is to go to another activity and get the "id" of the list view item and display it.
I have been trying a lot to figure this out but haven't succeeded.
My mainactivity.java file
public class MainActivity extends AppCompatActivity {
ListView listView;
Button button;
// Server Http URL
String HTTP_URL = "http://192.168.100.48/listview/index.php";
// String to hold complete JSON response object.
String FinalJSonObject ;
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Assign ID's to ListView.
listView = (ListView) findViewById(R.id.listView1);
button = (Button)findViewById(R.id.button);
progressBar = (ProgressBar)findViewById(R.id.ProgressBar1);
// Adding click listener to button.
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Showing progress bar just after button click.
progressBar.setVisibility(View.VISIBLE);
// Creating StringRequest and set the JSON server URL in here.
StringRequest stringRequest = new StringRequest(HTTP_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// After done Loading store JSON response in FinalJSonObject string variable.
FinalJSonObject = response ;
// Calling method to parse JSON object.
new ParseJSonDataClass(MainActivity.this).execute();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// Showing error message if something goes wrong.
Toast.makeText(MainActivity.this,error.getMessage(),Toast.LENGTH_LONG).show();
}
});
// Creating String Request Object.
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
// Passing String request into RequestQueue.
requestQueue.add(stringRequest);
}
});
}
// Creating method to parse JSON object.
private class ParseJSonDataClass extends AsyncTask<Void, Void, Void> {
public Context context;
// Creating List of Subject class.
List<Subject> CustomSubjectNamesList;
public ParseJSonDataClass(Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0) {
try {
// Checking whether FinalJSonObject is not equals to null.
if (FinalJSonObject != null) {
// Creating and setting up JSON array as null.
JSONArray jsonArray = null;
try {
// Adding JSON response object into JSON array.
jsonArray = new JSONArray(FinalJSonObject);
// Creating JSON Object.
JSONObject jsonObject;
// Creating Subject class object.
Subject subject;
// Defining CustomSubjectNamesList AS Array List.
CustomSubjectNamesList = new ArrayList<Subject>();
for (int i = 0; i < jsonArray.length(); i++) {
subject = new Subject();
jsonObject = jsonArray.getJSONObject(i);
//Storing ID into subject list.
subject.Subject_ID = jsonObject.getString("id");
//Storing Subject name in subject list.
subject.Subject_Name = jsonObject.getString("subject_Name");
// Adding subject list object into CustomSubjectNamesList.
CustomSubjectNamesList.add(subject);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result)
{
// After all done loading set complete CustomSubjectNamesList with application context to ListView adapter.
ListViewAdapter adapter = new ListViewAdapter(CustomSubjectNamesList, context);
// Setting up all data into ListView.
listView.setAdapter(adapter);
// Hiding progress bar after all JSON loading done.
progressBar.setVisibility(View.GONE);
}
}
}
My Listviewadapter.java file
public class ListViewAdapter extends BaseAdapter
{
Context context;
List<Subject> TempSubjectList;
public ListViewAdapter(List<Subject> listValue, Context context)
{
this.context = context;
this.TempSubjectList = listValue;
}
#Override
public int getCount()
{
return this.TempSubjectList.size();
}
#Override
public Object getItem(int position)
{
return this.TempSubjectList.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewItem viewItem = null;
if(convertView == null)
{
viewItem = new ViewItem();
LayoutInflater layoutInfiater = (LayoutInflater)this.context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = layoutInfiater.inflate(R.layout.listview_items, null);
viewItem.IdTextView = (TextView)convertView.findViewById(R.id.textviewID);
viewItem.NameTextView = (TextView)convertView.findViewById(R.id.textviewSubjectName);
convertView.setTag(viewItem);
}
else
{
viewItem = (ViewItem) convertView.getTag();
}
viewItem.IdTextView.setText(TempSubjectList.get(position).Subject_ID);
viewItem.NameTextView.setText(TempSubjectList.get(position).Subject_Name);
return convertView;
}
}
class ViewItem {
TextView IdTextView;
TextView NameTextView;
}
And of course, my subject.java file
public class Subject {
public String Subject_ID;
public String Subject_Name;
}
IMAGE - It successfully shows the data from server. But I haven't figured it out how to make what I want to do when I click the item.
So yes, that's what's taking my sleep and peace.
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long id) {
Intent intent = new Intent(MainActivity.this, AnotherActivity.class);
intent.putExtra("ID",CustomSubjectNamesList.get(position).Subject_ID);
startActivity(intent);
}
});
And From Another Activity
First, get the intent which has started your activity using the getIntent() method:
Intent intent = getIntent();
If your extra data is represented as strings, then you can use intent.getStringExtra(String name) method. In your case:
Intent intent = getIntent();
String id = intent.getStringExtra("ID");
you can send a string or an integer or simply any object that implements Serializable to another activity using intent.putExtra()
listView.setOnItemClickListener(new AdapaterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long id) {
Intent intent = new Intent(MainActivity.this, AnotherActivity.class);
intent.putExtra("id",CustomSubjectNamesList.get(position).Subject_ID;
startActivity(intent);
}
});
And in your new activity receive that info you just sent using getIntent.getIntExtra("id") or getIntent.getStringExtra(). or using it's other methods based on what you have sent.
I have a ListView with songs and a player. In my ListView I want to add a function to button to save ListView row and add it in different ListView in different Activity(Favorites Activity). How can I do this?
This is my code for Adapter:
public class Adapter extends ArrayAdapter<String> {
Context context;
int[] song_icon;
boolean pausedSamePos = false;
String[] song_name;
String[] song_duration;
String[] song_duration_sb;
private final int mLcdWidth = 0;
private final float mDensity = 0;
public static MediaPlayer mp = new MediaPlayer();
public static Boolean isPlaying = Boolean.valueOf(false);
public static int pos = 55;
Ids holder;
private final Handler handler = new Handler();
Runnable updateTimeProgressBar;
public Adapter(Context c, String[] song_titles, int song_Icons[],
String[] song_durations) {
super(c, R.layout.item, R.id.textview_song_duration,
song_titles);
this.context = c;
this.song_icon = song_Icons;
this.song_name = song_titles;
this.song_duration = song_durations;
this.song_duration_sb = song_durations;
}
final int[] songPos = { R.raw.song1, R.raw.song2, R.raw.song3,
R.raw.song4, R.raw.song5, R.raw.song6, R.raw.song7,
R.raw.song8, R.raw.song9, R.raw.song10,
R.raw.song11, R.raw.song12, R.raw.song13,
R.raw.song14, R.raw.song15, R.raw.song16,
R.raw.song17, R.raw.song18, R.raw.song19,
R.raw.song20, R.raw.song21, R.raw.song22,
R.raw.song23, R.raw.song24, R.raw.song25,
R.raw.song26, R.raw.song27, R.raw.song28,
R.raw.song29, R.raw.song30, };
#Override
public int getViewTypeCount() {
return getCount();
}
#Override
public int getAdapterViewType(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View row = convertView;
holder = null;
if (row == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.item, parent, false);
holder = new Ids(row);
row.setTag(holder);
} else {
holder = (Ids) row.getTag();
}
if (Adapter.isPlaying && Adapter.pos == position) {
if (pausedSamePos == true) {
holder.pauseed_play.setVisibility(View.VISIBLE);
holder.playing_pause.setVisibility(View.GONE);
} else {
holder.pauseed_play.setVisibility(View.GONE);
holder.playing_pause.setVisibility(View.VISIBLE);
}
holder.song_currenttime_sb.setVisibility(View.VISIBLE);
holder.song_duration.setVisibility(View.INVISIBLE);
holder.song_duration_sb.setVisibility(View.VISIBLE);
holder.seekbar.setVisibility(View.VISIBLE);
} else {
holder.seekbar.setVisibility(View.GONE);
holder.song_currenttime_sb.setVisibility(View.GONE);
holder.song_icon.setImageResource(song_icon[position]);
holder.song_duration_sb.setVisibility(View.INVISIBLE);
holder.song_duration.setVisibility(View.VISIBLE);
holder.pauseed_play.setVisibility(View.GONE);
holder.playing_pause.setVisibility(View.GONE);
}
holder.song_name.setText(song_name[position]);
holder.song_duration.setText(song_duration[position]);
holder.song_duration_sb.setText(song_duration_sb[position]);
final Ids finalHolder = holder;
holder.favorite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "The favorite", Toast.LENGTH_SHORT)
.show();
}
holder.clickRegister
.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
stopPlaying();
return true;
}
});
finalHolder.song_currenttime_sb.setTag(position);
holder.seekbar.setFocusable(true);
holder.seekbar.setTag(position);
holder.clickRegister.setTag(position);
holder.song_icon.setTag(position);
holder.song_name.setTag(position);
holder.song_duration.setTag(position);
holder.song_duration_sb.setTag(position);
int widthSpec = MeasureSpec.makeMeasureSpec(
(int) (mLcdWidth - 10 * mDensity), MeasureSpec.EXACTLY);
holder.menu_options.measure(widthSpec, 0);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.menu_options
.getLayoutParams();
params.bottomMargin = -holder.menu_options.getMeasuredHeight();
holder.menu_options.setVisibility(View.GONE);
return row;
}
What I want TLDR: To get song_name,song_duration,songPos on Clicked Row, and save it and then use that data to populat ListView in Favorites Activity.
If some more details are required I will be glad to provide.
basically the correct way is:
1) Create a Song model class and declare all required attributes inside this class
2) Extend the BaseAdapter and use an ArrayList<Song> as its data
Using this approach you will be able to easily retrieve a Song object from the clicked row and pass it anywhere you want. If you have no clue what I'm talking about then you are missing some basic knowledge about the ListView and its pointless to just throw code at you. There are tons of tutorials, check out this one or that one.
there is so much ways to imp this , here is a way that i would use
save your data (song_name,song_duration,songPos) in an object in the shared preferences
and when you go to the fav activity read that shared preferences you saved
#Override
public void onClick(View v) {
Toast.makeText(context, "The favorite", Toast.LENGTH_SHORT)
.show();
//for example get the fav here and save it in object
YoursongInfoObject yourSongInfoObject=new YoursongInfoObject();
yourSongInfoObject.name=holder.song_name.getText();
.
.
.
.
SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_FILE, Context.MODE_PRIVATE);
Editor editor = prefs.edit();
try {
editor.putString("YourSongInfoID", ObjectSerializer.serialize(yourSongInfoObject));
} catch (IOException e) {
e.printStackTrace();
}
editor.commit();
}
and your fav activity
public void onCreate() {
super.onCreate();
if (null == currentFavSong) {
currentFavSong = new YourSongInfoObject();
}
// load tasks from preference
SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_FILE, Context.MODE_PRIVATE);
try {
currentFavSong = (YourSongInfoObject) ObjectSerializer.deserialize(prefs.getString("YourSongInfoObject", ObjectSerializer.serialize(new YourSongInfoObject())));
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
I made a custom base adapter class in which I pass the context of activity and a JSONArray. I use this JSONArray data to set all the views. But the notifyDataSetChanged() on the adapter is not working. Do I have to pass a string array or arraylist of strings in the adapter for notifyDataSetChanged() to work? Will it not work if I pass JSONArray?
My Custom Adapter class code:
public class InboxMessagesAdapter extends BaseAdapter {
Activity act;
SharedPreferences prefs;
LayoutInflater Inflater;
JSONArray arrayOfMessages;
public InboxMessagesAdapter(Activity a, JSONArray arry) {
act = a;
arrayOfMessages = arry;
prefs = PreferenceManager.getDefaultSharedPreferences(a);
Inflater = (LayoutInflater) act
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return arrayOfMessages.length();
}
#Override
public Object getItem(int arg0) {
return arg0;
}
#Override
public long getItemId(int arg0) {
return arg0;
}
#Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
View v1 = arg1;
try {
final int x = arg0;
JSONObject js = arrayOfMessages.getJSONObject(arg0);
v1 = Inflater.inflate(R.layout.element_inbox, null);
TextView titleOfMessage = (TextView) v1
.findViewById(R.id.msg_inbox_title);
TextView timeOfMessage = (TextView) v1
.findViewById(R.id.msg_inbox_time);
final CheckBox selectMessage = (CheckBox) v1
.findViewById(R.id.msg_inbox_check_button);
ImageView attachment = (ImageView) v1
.findViewById(R.id.msg_inbox_attachment);
ImageView starStatus = (ImageView) v1
.findViewById(R.id.msg_inbox_addtofav);
if (js.getString("StarStatus").equals("0"))
starStatus.setImageResource(R.drawable.btn_add_to_fav_normal);
else
starStatus.setImageResource(R.drawable.btn_add_to_fav_pressed);
if (js.getString("AttachmentStatus").equals("0"))
attachment.setVisibility(View.GONE);
titleOfMessage.setText(js.getString("MessageSubject"));
String arr[] = js.getString("MessageDate").split(" ");
try {
timeOfMessage.setText(arr[1] + arr[2]);
} catch (Exception e) {
timeOfMessage.setText(js.getString("MessageDate"));
}
v1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
try {
Intent in = new Intent(act, MessageActivity.class);
in.putExtra("data", arrayOfMessages.getJSONObject(x)
.toString());
act.startActivity(in);
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
return v1;
}
}
you must be updating a different object of arrayOfMessages create a function in adapter like:
public void setArrayOfMessages(JSONArray arrayOfMessages){
this.arrayOfMessages=arrayOfMessages;
}
and before calling notifyDataSetChanged all this:
adapter.setArrayOfMessages(object);
adapter.notifyDataSetChanged();
Better take your data from Json Array into an Arraylist or List and then apply notifyDataSetChanged.
I have a ListView whose list item comes from a 'String' from Shared Preference. Now I have to set two icons "success" and "failed" identifying those keywords "successful" and "failed" from string. But while setting it is either setting "success" icons to all listitems or "failed" icons to all reason because string contains both. Any idea how can i identify each list items and set icons to them ? Below is my code :
Class where I am retrieving "oldlistitems" and "newlistitems" strings from Shared Preference and trying to set icons to listitems
public class EntryAdapterLog extends ArrayAdapter<Item> {
private Context context;
private ArrayList<Item> items;
private LayoutInflater vi;
public EntryAdapterLog(Context context,ArrayList<Item> items) {
super(context,0, items);
this.context = context;
this.items = items;
vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
final Item i = items.get(position);
if (i != null) {
if(i.isSection()){
SectionItem si = (SectionItem)i;
v = vi.inflate(R.layout.list_item_section, null);
v.setOnClickListener(null);
v.setOnLongClickListener(null);
v.setLongClickable(false);
final TextView sectionView = (TextView) v.findViewById(R.id.list_item_section_text);
sectionView.setText(si.getTitle());
}else{
String oldlistitems = LogListView.first;
String newlistitems = LogListView.title;
Log.d("LOG", "ABCD : " + oldlistitems);
Log.d("LOG", "DEFG : " + newlistitems);
EntryItem ei = (EntryItem)i;
v = vi.inflate(R.layout.list_item_entry_log, null);
final TextView title = (TextView)v.findViewById(R.id.list_item_entry_title);
final TextView subtitle = (TextView)v.findViewById(R.id.list_item_entry_summary);
final ImageView imageicon = (ImageView)v.findViewById(R.id.list_item_entry_drawable);
if(title != null) {
title.setText(ei.title);
}
if(subtitle != null){
subtitle.setText(ei.subtitle);
}
//HERE IS PROCESS OF SETTING ICONS
if ((oldlistitems !=null && oldlistitems.contentEquals("Sync Successful")) || (newlistitems != null && newlistitems.contentEquals("Sync Successful"))){
imageicon.setImageResource(R.drawable.ok);
}
else {
imageicon.setImageResource(R.drawable.wrong);
}
}
}
return v;
}
}
Class where i am setting shared preference
public class LogListView extends ListActivity {
/** Called when the activity is first created. */
static String newString;
private static EntryAdapterLog adapter;
int clickCounter = 0;
static ArrayList<Item> items = new ArrayList<Item>();
static SharedPreferences preferences = null;
private static Context context = null;
static StringTokenizer tokens;
static String first;
private static String second;
private JSONArray jsonarry = null;
static String saveitems;
private JSONObject jsonobject = null;
private String subtitle;
static String title;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
adapter = new EntryAdapterLog(this, items);
// items.add(new SectionItem("Log Report"));
setListAdapter(adapter);
if (adapter.getCount() != 0) {
// Do nothing Adapter has value
} else {
retreiveItems();
}
}
// Method which will handle dynamic insertion
public static void addItems() {
preferences = context.getSharedPreferences("LOG",android.content.Context.MODE_PRIVATE);
newString = preferences.getString("log", "");
tokens = new StringTokenizer(newString, ",");
first = tokens.nextToken();
second = tokens.nextToken();
items.add(new EntryItem(first, second));
adapter.notifyDataSetChanged();
}
// Method which will handle dynamic insertion ends
#Override
protected void onDestroy() {
super.onDestroy();
saveItems();
}
// Save ListItems if restarted
protected static void saveItems() {
SharedPreferences prefs = context.getSharedPreferences("prefName",Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("myList", new Gson().toJson(items).toString());
editor.apply();
Log.d("LOG", "Saved Items : " + items);
}
// Save ListItems if restarted ends
// Retrieve ListItems if restarted
protected void retreiveItems() {
preferences = context.getSharedPreferences("prefName",android.content.Context.MODE_PRIVATE);
saveitems = preferences.getString("myList", "");
Log.d("LOG", "Retreived Items : " + saveitems);
try {
jsonarry = new JSONArray(saveitems);
} catch (JSONException e) {
e.printStackTrace();
}
if (jsonarry == null || jsonarry.length() == 0) {
return; //This checks before setting adapter onCreate if adapter is null
}
for (int i = 0; i < jsonarry.length(); i++) {
try {
jsonobject = jsonarry.getJSONObject(i);
} catch (JSONException e) {
e.printStackTrace();
}
// get all values here from JSONObject
title = jsonobject.optString("title");
subtitle = jsonobject.optString("subtitle");
items.add(new EntryItem(title, subtitle));
adapter.notifyDataSetChanged();
}
}
// Retrieve ListItems if restarted ends
// Counter for amount of period of time before flusing adapter
protected void flushList(){
}
// Counter for amount of period of time before flusing adapter ends
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
if (!items.get(position).isSection()) {
items.get(position);
Toast.makeText(this, "You clicked " + position, Toast.LENGTH_SHORT).show();
}
if (position == 9) {
}
super.onListItemClick(l, v, position, id);
}
}
Regards
If I understand correctly, you want to update the icon for each item, based on if sync successful or sync failed for that item.
You should do something like this (update your code accordingly):
//HERE IS PROCESS OF SETTING ICONS
if ((ei.title.contains("Sync Successful")) {
imageicon.setImageResource(R.drawable.ok);
}
else {
imageicon.setImageResource(R.drawable.wrong);
}
First of all your adapter will laggy when you will have big number of list items, you should use ViewHolder pattern as is described HERE
Second, it will be better to get all the data from sharedPreferences and store them in an ArrayList and give that list to adapter, Reading and Writing to SharedPreferences is an expansive operation.
Also to handle if the sync is success or fail use a boolean in your Item object, and in the adapter just chec that boolean and like this change the drawable of the list item.
I'm having some troubles with correct identification of items in a ListView.
There are 4 classes that matter, it's a lot of code so at first I'm going to explain the logic of those classes.
Enter the ListActivity and initialize its ListView
execute an AsyncTask that downloads JSON response from the server, parses it, populates the ListView with Objects and sets the adapter while showing a ProgressDialog
the PlaylistItem class includes methods which simply get the data from a single JSONObject. It is used to parameterize the ArrayList with its Objects
after the AsyncTask is done the list is filled with items and looks like |Button| Artist(TextView) - Title(TextView)
UPDATE
resolved 1st issue but still can't figure out what's wrong with buttons
2). I set an OnClickListener to my buttons in the Adapter's getView() method. To find out if the button is identified correctly I did nothing but just changed its background. BUT a click on a certain button forces the background of every 11th or 12th button to be changed. Can't figure it out so far.
I can't proceed to getting url and streaming audio until those problems are resolved, so any help is greatly appreciated. My classes go below, please ask if something appears unclear.
AudioList
public class AudioList extends ListActivity {
private ListView lv;
private PlaylistLoader loader;
private AudioListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_audio_list);
init(); // initialize the ListView
/*--- populate the list with user's audio in case network connection is available ---*/
loader = new PlaylistLoader(this, lv, adapter);
if (Utils.isNetworkAvailable(this)) {
loader.execute();
} else {
APP_CONSTANTS.NO_DATA_CONNECTION(this);
}
}
#Override
protected void onResume() {
super.onResume();
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
Toast.makeText(getApplicationContext(), Integer.toString(arg2),
Toast.LENGTH_SHORT).show();
}
});
}
private void init() {
lv = getListView();
lv.setTranscriptMode(0x00000000);
lv.setDividerHeight(1);
lv.setSmoothScrollbarEnabled(true);
lv.setVerticalFadingEdgeEnabled(true);
}
PlaylistLoader
public class PlaylistLoader extends AsyncTask<Void, Void, Void> {
private JSONObject usersPlaylist, singleJSONItem;
private JSONArray responseJSONArray;
private ListView lv;
private ArrayList<PlaylistItem> playlist;
private Activity a;
private PlaylistItem audioList;
private SharedPreferences prefs;
private ProgressDialog pd;
AudioListAdapter adapter;
public PlaylistLoader(Activity a, ListView lv, AudioListAdapter adapter) {
this.lv = lv;
this.a = a;
this.adapter = adapter;
}
#Override
protected Void doInBackground(Void... arg0) {
/*--- create new ArrayList of PlaylistItem Objects ---*/
playlist = new ArrayList<PlaylistItem>();
/*--- get the preferences using context of calling activity ---*/
prefs = PreferenceManager.getDefaultSharedPreferences(a);
try {
/*--- download the response JSONObject from server // access_token and
* user_id come from activity's defaultSharedPreferences ---*/
usersPlaylist = Utils.retrieveJsonObjectFromUrl(new URL(
APP_CONSTANTS.REQUEST_AUDIO_LIST(prefs)), a);
/*--- get the response array from received object ---*/
responseJSONArray = usersPlaylist.getJSONArray("response");
/*--- populate the ArrayList with Objects from the response array ---*/
for (int i = 0; i < responseJSONArray.length(); i++) {
singleJSONItem = responseJSONArray.getJSONObject(i);
audioList = new PlaylistItem(singleJSONItem);
playlist.add(audioList);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(a);
pd.setTitle("Please wait");
pd.setMessage("Retrieving audio list...");
pd.show();
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
lv.setVisibility(View.VISIBLE);
pd.dismiss();
/*--- set the adapter passed in constructor as an adapter for passed ListView ---*/
adapter = new AudioListAdapter(a, R.layout.playlist_item, playlist);
lv.setAdapter(adapter);
}
}
AudioListAdapter
public class AudioListAdapter extends ArrayAdapter<PlaylistItem> {
private PlaylistItem pl;
private Context context;
private int layoutResourceId;
private PlaylistItem aud;
private ArrayList<PlaylistItem> data = null;
public AudioListAdapter(Context context, int layoutResourceId,
ArrayList<PlaylistItem> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public PlaylistItem getItem(int position) {
return super.getItem(position);
}
#Override
public int getCount() {
return data.size();
}
#Override
public int getPosition(PlaylistItem item) {
return super.getPosition(item);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
pl = new PlaylistItem();
aud = getItem(position);
if (convertView == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(layoutResourceId, parent, false);
pl.btnPlay = (Button) convertView.findViewById(R.id.btn_list_play);
pl.imgSaved = (ImageView) convertView
.findViewById(R.id.img_list_audio_saved);
pl.tvArtist = (TextView) convertView
.findViewById(R.id.tvListItemArtist);
pl.tvTitle = (TextView) convertView
.findViewById(R.id.tvListItemSong);
convertView.setTag(pl);
} else {
pl = (PlaylistItem) convertView.getTag();
pl.btnPlay.setBackgroundResource(R.drawable.list_button_play);
}
pl.tvArtist.setText(aud.getArtist() + " " + "-");
pl.tvTitle.setText(aud.getTitle());
pl.btnPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/*--- vibrate if this option is enabled in the preferences ---*/
if (APP_CONSTANTS.isHapticFeedbackEnabled(getContext())) {
APP_CONSTANTS.doVibrate(getContext());
}
pl.btnPlay.setBackgroundResource(R.drawable.list_button_pause);
}
});
return convertView;
}
PlayListItem
public class PlaylistItem {
private String artist, title;
private JSONObject obj;
public Button btnPlay;
public TextView tvArtist, tvTitle;
public ImageView imgSaved;
public int duration;
public int audio_id;
public String url;
/*--- the constructor takes a single JSONObject from the response array ---*/
public PlaylistItem(JSONObject obj) {
this.obj = obj;
}
public PlaylistItem() {
// default constructor
}
/*--- the methods below return values by key from the passed JSONObject ---*/
public String getArtist() {
try {
artist = obj.getString("artist");
} catch (JSONException e) {
e.printStackTrace();
}
return artist;
}
public String getTitle() {
try {
title = obj.getString("title");
} catch (JSONException e) {
e.printStackTrace();
}
return title;
}
public int getID() {
try {
audio_id = obj.getInt("aid");
} catch (JSONException e) {
e.printStackTrace();
}
return audio_id;
}
public String getURL() {
try {
url = obj.getString("url");
} catch (JSONException e) {
e.printStackTrace();
}
return url;
}
}
Edit:
Try this
Take a custom Selector in your drawable
button_play.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/pause_button"
android:state_selected="true" />
<item android:drawable="#drawable/play_button" />
</selector>
Modifty your adapter like this
public class AudioListAdapter extends ArrayAdapter<PlaylistItem> {
private PlaylistItem pl;
private Context context;
private int layoutResourceId;
private PlaylistItem aud;
private ArrayList<PlaylistItem> data = null;
Button previous;
public AudioListAdapter(Context context, int layoutResourceId,
ArrayList<PlaylistItem> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
previous=new Button(context);
this.context = context;
this.data = data;
}
....
....
#Override
public View getView(int position, View convertView, ViewGroup parent) {
pl = new PlaylistItem();
aud = getItem(position);
if (convertView == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(layoutResourceId, parent, false);
pl.btnPlay = (Button) convertView.findViewById(R.id.btn_list_play);
pl.btnPlay.setBackGroundResouce(R.drawable.button_play); //you can set here or in xml
pl.imgSaved = (ImageView) convertView
.findViewById(R.id.img_list_audio_saved);
pl.tvArtist = (TextView) convertView
.findViewById(R.id.tvListItemArtist);
pl.tvTitle = (TextView) convertView
.findViewById(R.id.tvListItemSong);
convertView.setTag(pl);
} else {
pl = (PlaylistItem) convertView.getTag();
}
pl.tvArtist.setText(aud.getArtist() + " " + "-");
pl.tvTitle.setText(aud.getTitle());
pl.btnPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/*--- vibrate if this option is enabled in the preferences ---*/
if (APP_CONSTANTS.isHapticFeedbackEnabled(getContext())) {
APP_CONSTANTS.doVibrate(getContext());
}
//for some reason, the background gets changed for every 11th or 12th button in the list
Button current=((Button)v);
current.setSelected(true);
previous.setSelected(false);
previous=current;
}
});
return convertView;
}
}
The reason why your button and listitem not clickable is because Your list have a focus item button, so you need to setFocusable=false for your button.
Try setting focusable=false for your button in the xml. If it is not worked for you than do like this
In your row xml file
1.set focusable=true for your button.
2.In the same set android:descendantFocusability="blocksDescendants" for your parent item.(i.e parent layout in which your views lie).
In getView() method after setting the onclickListener for the button, set focusable false for the button.
It will work for sure. I hope this will help you..
BUT a click on a certain button forces the background of every 11th or 12th button to be changed. Can't figure it out so far.
You are fighting the way ListViews recycle the row layouts.
Think of it this way: if you have a ListView with 10,000 rows but can only fit 9 of them on the screen, then it doesn't make sense to create 10,000 unique layouts. This just waste resources, instead ListView only creates ~10 layouts and reuses them.
Solution: return each row to it's default state when it is reused. In getView() add:
} else {
pl = (PlaylistItem) convertView.getTag();
pl.btnPlay.setBackgroundResource(R.drawable.list_button_play);
// I guessed at the resource's name ^^^^^^^^^^^^^^^^
}
(Also you can make a few small changes to speed up your code. For instance, you only need one OnClickListener since they all contain the same code, make this a class variable and pass this to each play Button. There are more.)