I am populating a ListView using remote JSON data in the following format:
{"nodes":[{"node":{"title":"Article#1","id":"4"}},{"node":{"title":"Article#2","id":"3"}}]}
My ListView is constructed with the following code:
ArrayList<String> articles = new ArrayList<String>();
try{
for(int i=0; i < data.length(); i++){
JSONObject dataObj = (JSONObject)data.get(i);
JSONObject record = dataObj.getJSONObject("node");
title = (record.getString("title"));
nid = (record.getString("nid"));
Log.i("FOUND", "title: " + title);
Log.i("FOUND", "nid: " + nid);
articles.add(title);
}
}catch(JSONException j){
Log.e("CHECK", "Attempting to read data returned from JSONReader: " + j.toString());
}
ListView articlesList = (ListView)findViewById(R.id.articlesList);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(ArticlesActivity.this, R.layout.article_item, R.id.articleItem, articles);
articlesList.setAdapter(adapter);
The entire process works and successfully lists my Article titles. But, I am trying to follow tutorials which will help me enable onSelectListeners on each list item. The ID element associated to each article title is all I need to remotely fetch the article content.
Is it possible to setup my ArrayList to contain both title and id data and use it to setup my dynamic OnSelectListener enabled ListView?
The proper way to do it is to create a class that will hold the article name and id and whatever info you need. In your custom adapter you setTag() method when you create the view.
Then in your onClickListener use getTag() method. Below I'll give you some code snipsetss hope they will help you.
public class Article{
private String name;
private String id;
public Article(String name, String id) {
this.name =name;
this.id = id;
}
public String getName() {
return name;
}
public String getID() {
return id;}
}
In you custom adapter class use setTag method when you create the view
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.group_list, null);
TextView title = (TextView) v.findViewById(R.id.group_title);
...//rest of my code
Article article = getItem(position);
title.setText(article.getName());
title.setTag(article);
v.setTag(article);
return v;
}
In your click listener
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Article article= (Article ) view.getTag();
String articleID= article.getID();
}
}
Related
I have written a code to display json items into listview , when i debug the code i can see the data properly , when i am setting the list to the listview i am only seeing the last item
Code i tried :
try {
foodintervallist.clear();
final String result = response.body().string();
JSONObject jsonObject = new JSONObject(result);
String data = jsonObject.getString("data");
JSONArray foodintervalarray = new JSONArray(data);
HashMap<String, String> menuMap =
new HashMap<String, String>();
for (int j = 0; j < foodintervalarray.length(); j++) {
String key1 = "";
JSONObject jsonObject1 =
foodintervalarray.getJSONObject(j);
final String food_interval =
jsonObject1.getString(FOOD_INTERVAL);
if (jsonObject1.isNull(ITEM_NAME)) {
item_name = "";
} else {
item_name = jsonObject1.getString(ITEM_NAME);
}
if (!menuMap.containsKey(food_interval)) {
menuMap.put(food_interval, item_name);
} else {
String key = menuMap.get(food_interval);
key1=key+","+item_name;
menuMap.put(food_interval, key1);
}
runOnUiThread(new Runnable() {
#Override
public void run() {
foodintervallist.add(menuMap);
listViewAdapter = new ListViewAdapter(Diet_Order_Activity_New.this, foodintervallist);
listView.setAdapter(listViewAdapter);
listViewAdapter.notifyDataSetChanged();
}
});
}
My BaseAdapter class
#Override
public View getView(int position, View convertView, ViewGroup parent) {
inflater = (LayoutInflater)
activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.table_row, parent,
false);
resultp = fooditervallist.get(position);
txtFoodInterval = (TextView)
itemView.findViewById(R.id.foodInterval);
txtFoodItem = (TextView) itemView.findViewById(R.id.foodItems);
for (Map.Entry<String, String> entry : resultp.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
txtFoodInterval.setText(key);
Toast.makeText(activity, "" + key, Toast.LENGTH_LONG).show();
txtFoodItem.setText(value);
// do what you have to do here
// In your case, an other loop.
}
return itemView;
}
I am declaring the foodintervallist globally in my main activity class and also the listviewadapter i am initializing inside oncreate method
I am getting the data inside my arraylist , but i am able to display only the last item , what to do ?
Thanx
I would recommend to check your implementation of Adapter's getCount(). As it is not provided how it looks, I would looked there...
it should be like:
public int getCount (){ return fooditervallist.get(0).size() }
As you provide a list with only one item. Also I see there some issues in getView() :
fooditervallist.get(position); --> don't use position there, your list has always only one item therefore use 0 instead otherwise you'll get null pointer
your for loop is setting the txtFoodInterval and txtFoodItem with the all values in the Map.Set which might result in all list items having the same value ... instead of for loop you should use a "position" parameter here which is not possible with HashMap as order is not predicable. Use LinkedHashMap instead to have correct order and logic needs to be adjusted
Nevertheless I would implement it differently:
JSON parsing - I would create a new object model for holding the data
class FoodItem { int interval; String name; // getters and setters
here }
I would put these items in the list you put your map
In adapter you can then use this object quite easily like without any for loop like:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
inflater = (LayoutInflater)
activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.table_row, parent, false);
FoodItem item = fooditervallist.get(position);
txtFoodInterval = (TextView) itemView.findViewById(R.id.foodInterval);
txtFoodItem = (TextView) itemView.findViewById(R.id.foodItems);
txtFoodInterval.setText(item.interval) ;
txtFoodItem.setText(item.name);
return itemView;
}
Also I would recommend to have a look on Retrofit library. It will make your life easier...
put your Hashmap inside the for loop. Because when you use globally the data will be overrided and you get only last item.
Put the below code outside the loop // set adapter outside the loop
listViewAdapter = new ListViewAdapter(Diet_Order_Activity_New.this,foodintervallist);
listView.setAdapter(listViewAdapter);
listViewAdapter.notifyDataSetChanged();
I have 2 tables, Logs and Price. Content from table logs is displayed into textviews for each item. Now I would like to display some content form table Price into the same base adapter.
Is it possible and how should I done that?
This is my activity with base adapter in which i displayed content form table logs. How should I display here content form table Price?
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.display_logs_listview);
boolean sort = getIntent().getBooleanExtra("sort", false);
mainListView = (ListView) findViewById(R.id.ListViewItem);
final String place = (String) getIntent().getExtras().get("keyPlace");
dbHandler = new LogsDBHandler(this);
ArrayList<Logs> logsList = sort ? dbHandler.getAllLogsByPlace() : dbHandler.getAllLogs(place);
TextView result = (TextView) findViewById(R.id.LogMassResult);
double sum = 0.0;
for( int i=0; i<logsList.size(); i++) {
sum += logsList.get(i).getResult();
}
result.setText(String.format("%.2f", sum));
listAdapter = new LogsArrayAdapter(logsList);
mainListView.setAdapter(listAdapter);
}
private class LogsArrayAdapter extends BaseAdapter {
private LayoutInflater inflater;
private List<Logs> logsList;
private List<Price> priceList;
public LogsArrayAdapter(List<Logs> logsList) {
inflater = LayoutInflater.from(DisplayLogs.this);
this.logsList = logsList;
}
#Override
public int getCount() {
return logsList.size();
}
#Override
public Object getItem(int position) {
return logsList.get(position);
}
#Override
public long getItemId(int position) {
return logsList.get(position).getId();
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.activity_display_logs, parent, false);
}
Logs log = logsList.get(position);
((TextView) convertView.findViewById(R.id.textPlace)).setText(log.getPlace());
((TextView) convertView.findViewById(R.id.textNumber)).setText(log.getPlate_number());
((TextView) convertView.findViewById(R.id.textSort)).setText(log.getSort_id());
((TextView) convertView.findViewById(R.id.textGrade)).setText(log.getGrade());
((TextView) convertView.findViewById(R.id.textDiameter)).setText(log.getDiameter());
((TextView) convertView.findViewById(R.id.textLength)).setText(log.getLength());
Log.d("Value", log.getCreatedAt());
try {
Date dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(log.getCreatedAt());
((TextView) convertView.findViewById(R.id.textDate)).setText(new SimpleDateFormat("dd.MM.yyyy HH:mm").format(dt));
} catch (ParseException e) {
e.printStackTrace();
}
Log.d("Masa Trupca", String.format("%.2f", log.getResult()));
String final_result = String.format("%.2f", log.getResult());
((TextView) convertView.findViewById(R.id.textAmount)).setText(final_result);
return convertView;
}
}
and this is my dbQuery for getting price. I created this in my Logs class. Here I'm displaying price based on parameters in string.
public Cursor getPrice() {
Cursor cursor = db.query("Price", new String[]{"price_stump_kn", "price_stump_eur", "road_price_kn", "road_price_eur"}, "sort = ? AND grade = ? AND length = ? BETWEEN diameter_dg = ? AND diameter_gg = ?",
new String[]{getSort_id(), getGrade(), getLength(), getDiameter(), getDiameter()}, null, null, null);
if (cursor.moveToFirst()) {
do {
Price price = new Price();
price.setStumpPrice_kn(cursor.getString(0));
price.setStumpPrice_eur(cursor.getString(1));
price.setRoadPrice_kn(cursor.getString(2));
price.setRoadPrice_eur(cursor.getString(3));
} while (cursor.moveToNext());
}
return cursor;
}
So how should I display content from two tables inside one base adapter (listview)?
It depends on how the records in those two tables are related. Your remark that you included a DB query in the Logs class (which I suppose is a domain class, not a DAO), I suspect that your class structure is somewhat confusing. Therefore, I try to sketch a class structure for each of the two ways of mixing your logs and prices.
Solution A: Each log is connected to a price, and data of both are to be displayed in one item.
class LogDAO extends SQLiteOpenHelper {
...
public Log getLogs(some selection parameters) {
Get logs according to selection parameters, and for each log
call getPrice(selection parameter according to log just found)
log.setPrice(price just found)
...
Now, in your adapter, the items are Logs, and with log.getPrice() you can get the price attributes and are free to mix log and price attributes in your adapter to display them in your view item.
Solution B: There is a mixed list -- some items are logs, others are prices
The key to this is that you can dynamically decide, for each item, which layout to use in your adapter. So the structure will be:
class LogPriceDAO extends SQLiteOpenHelper {
...
public Object getLogsAndPrices(some selection parameters)
Get logs and prices in some sequence, according to your business
logic and the selection parameters (If logs and prices have some
common superclass, use that instead of Object)
...
class LogsAndPricesAdapter extends BaseAdapter {
...
#Override
public View getView (int i, View view, ViewGroup viewGroup) {
...
Object currObject = this.getItem(i); // or common superclass
...
View v;
if (currObject instanceOf Log) {
v = layoutInflater.inflate(R.layout.log_layout, null)
now fill fields of your log layout
...
} else {
if (currObject instanceOf Price) {
v = layoutInflater.inflate(R.layout.price_layout, null)
now fill fields of your price layout
...
return v
The instanceOf operator is considered bad style by some people. So the immaculate way is to define a common superclass for Log and Price that offers an operation public Boolean isLog() from which the caller can decide which type of object it got.
In my app application i have an API that parsing JSON updating 500 rows is the list view. In a row I have id,name,number and status. Through the pushnotification am getting an id out of the 500 and I want update the status of that id having row.
Am using getter/setter method here so if getting the view position i can update the row.
This is the way am parsing
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject c = jsonArray.getJSONObject(i);
String phone = c.getString("phone");
String subDistributorStatus = c.getString("status");
String name = c.getString("firstName");
subDistributerId = c.getString("subDistributerId");
SubdistributorItem item = new SubdistributorItem();
item.setSubDistributorName(name);
item.setSubDistributorNumber(phone);
item.setSubDistributorStatus(subDistributorStatus);
item.setSubDistributorId(subDistributerId);
}
This is the way am updating single row
SubdistributorItem subdistributorItem = subdistributorItemList.get(Integer.parseInt(getFromPreference("Sub_position")));
String phone= subdistributorItem.getSubDistributorNumber();
String id= subdistributorItem.getSubDistributorId();
String status= subdistributorItem.getSubDistributorStat
Here am getting the position by clicking the view.
Now if i get one of the id in the row is there any chance to get the position in the view.
I tried HashMap.
**HashMap newmap = new HashMap(); // in global
newmap.put(subDistributerId,i); // in loop
Log.e("Tag ","hash map positon "+ newmap.get(43)); // in onResume**
But failed.
can any please help to get the position of the row ,if get id of the row.
You can use ArrayList along with the getter/setter class. You also have to extend the BaseAdapter class to get the string values of a particular position and map it to the view.
You can check the following example --
The below code will loop through the JSON and set the values using Setter methods and then it will add them to the ArrayList.
ArrayList<SubdistributorItem> listitem = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject c = jsonArray.getJSONObject(i);
String phone = c.getString("phone");
String subDistributorStatus = c.getString("status");
String name = c.getString("firstName");
subDistributerId = c.getString("subDistributerId");
SubdistributorItem item = new SubdistributorItem();
item.setSubDistributorName(name);
item.setSubDistributorNumber(phone);
item.setSubDistributorStatus(subDistributorStatus);
item.setSubDistributorId(subDistributerId);
listitem.add(item);
}
Then extend the BaseAdapter class to get the individual position and the values associated with it.
public class MyBaseAdapter extends BaseAdapter {
public Context ba_context;
public ArrayList<SubdistributorItem> listitem = new ArrayList<>();
public LayoutInflater inflater;
ListRowItem currentlistitem;
public MyBaseAdapter(Context ma_context, ArrayList<SubdistributorItem> ma_listitem) {
super();
this.ba_context = ma_context;
this.listitem = ma_listitem;
inflater = (LayoutInflater) ba_context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return this.listitem.size();
}
#Override
public Object getItem(int position) {
return this.listitem.get(position);
}
#Override
public long getItemId(int position) {
return (long) position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (convertView == null)
vi = inflater.inflate(R.layout.listview_item_layout, parent, false);
TextView carrier = (TextView) vi.findViewById(R.id.layout_textview1);
currentlistitem = listitem.get(position);
String str_carrier = currentlistitem.getCarrier();
carrier.setText(str_carrier);
return vi;
}
}
Finally call this class and set the adapter in the listview somewhere in your code as per your requirement.
baseAdapter = new MyBaseAdapter(context,listitem);
listView.setAdapter(baseAdapter);
Hope this helps!!
I am using this to retreive a list of items and place them in a list. The URL is retrieved also for each item. I am using ListActivity
// Get all td's that are a child of a row - each game has 4 of these
Elements games = doc.select("tr> td.indexList1, tr > td.indexList2");
Elements links = doc.getElementsByTag("a"); // or getElementsByClass("b1");
// Iterator over those elements
ListIterator<Element> postIt = games.listIterator();
while (postIt.hasNext()) {
// ...It
while (postIt.hasNext()) {
// Add the game text to the ArrayList
Element name = postIt.next();
String nameString = name.text();
String platform = postIt.next().text();
Element url = name.select("a").first();
//Here i retreive the url string for each item
String urlString = url.attr("href");
String genre = postIt.next().text();
String releaseDate = postIt.next().text();
gameList.add(new GameRelease(nameString, platform, genre, releaseDate, urlString));
Log.v(TAG, urlString);
}
this.setListAdapter(new GameReleaseAdapter(this, gameList));
}
I created my own ArrayAdapter here...
private class GameReleaseAdapter extends ArrayAdapter<GameRelease> {
private ArrayList<GameRelease> items;
public GameReleaseAdapter(Context context, ArrayList<GameRelease> items) {
// TODO: make a layout for each item which you'd call (for example) itemLayout
super(context, R.layout.item, items);
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO: return an item view styled however you want or as shown in the tutorial
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
GameRelease o = items.get(position);
TextView tt = (TextView) v.findViewById(R.id.toptext);
TextView bt = (TextView) v.findViewById(R.id.bottomtext);
TextView plat = (TextView)v.findViewById(R.id.platform);
TextView genre = (TextView)v.findViewById(R.id.genre);
tt.setText(o.getName());
bt.setText("RELEASE DATE: " +o.getReleaseDate());
plat.setText("PLATFORM: " + o.getPlatform());
genre.setText("GENRE: " + o.getGenre());
return v;
}
}
}
How could i store the url for each item so when the item is clicked the url is sent with a extra to another activity? How can i set each item to its own url? How can i let android know that this item in the list was clicked and it should be This url for that particular item?
EDIT - Like this? It gives me tons of syntax errors
while (postIt.hasNext()) {
// Add the game text to the ArrayList
Element name = postIt.next();
String nameString = name.text();
String platform = postIt.next().text();
Element url = name.select("a").first();
String urlString = url.attr("href");
String genre = postIt.next().text();
String releaseDate = postIt.next().text();
gameList.add(new GameRelease(nameString, platform, genre, releaseDate, urlString));
Log.v(TAG, urlString);
}
this.setListAdapter(new GameReleaseAdapter(this, gameList));
final GameReleaseAdapter myGameReleaseAdapter =new GameReleaseAdapter(this,gameList);
setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
GameRelease selectedGameRelease =myGameReleaseAdapter .getItem(position);
String urlString=selectedGameRelease.getUrlString();
//Make what you like with the url
}
});
}
when you create the GameReleaseAdapter in your Activity, make sure you have a reference to it like
in onCreate
1- read your gameList
2- after reading it, do this line:
final GameReleaseAdapter myGameReleaseAdapter =new GameReleaseAdapter(this,gameList);
3-
getListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
GameRelease selectedGameRelease =myGameReleaseAdapter .getItem(position);
String urlString=selectedGameRelease.getUrlString();
//Make what you like with the url
}
});
OnItemClickListener can be found with AdapterView.OnItemClickListener
ok so i have an array adapted listview (the array adapting is done in another class).. i just got the click listener working for the list but now i want set it up so that when i click an item it pulls the strings from the clicked item and piggybacks them on the intent to a new activity.. i figure im supposed to use intent.putextra however im not sure how to pull the correct strings corresponding to the item that i click on.. my code is below.. im simply lost to be honest
//Initialize the ListView
lstTest = (ListView)findViewById(R.id.lstText);
//Initialize the ArrayList
alrts = new ArrayList<Alerts>();
//Initialize the array adapter notice with the listitems.xml layout
arrayAdapter = new AlertsAdapter(this, R.layout.listitems,alrts);
//Set the above adapter as the adapter for the list
lstTest.setAdapter(arrayAdapter);
//Set the click listener for the list
lstTest.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView adapterView, View view, int item, long arg3) {
Intent intent = new Intent(
HomePageActivity.this,
PromotionActivity.class
);
finish();
startActivity(intent);
}
});
my alerts class..
public class Alerts {
public String cityid;
public String promoterid;
public String promoshortcontent;
public String promocontent;
public String promotitle;
public String locationid;
public String cover;
#Override
public String toString() {
return "City: " +cityid+ " Promoter: " +promoterid+ "Short Promotion: " +promoshortcontent+ "Promotion: " +promocontent+ "Title: " +promotitle+ "Location: " +locationid+ "Cover: " +cover+ "$";
}
}
anddddd my alertsadapter class..
public class AlertsAdapter extends ArrayAdapter<Alerts> {
int resource;
String response;
Context context;
//Initialize adapter
public AlertsAdapter(Context context, int resource, List<Alerts> items) {
super(context, resource, items);
this.resource=resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LinearLayout alertView;
//Get the current alert object
Alerts al = getItem(position);
//Inflate the view
if(convertView==null)
{
alertView = new LinearLayout(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater vi;
vi = (LayoutInflater)getContext().getSystemService(inflater);
vi.inflate(resource, alertView, true);
}
else
{
alertView = (LinearLayout) convertView;
}
//Get the text boxes from the listitem.xml file
TextView textPromo =(TextView)alertView.findViewById(R.id.txtPromo);
TextView textPromoter =(TextView)alertView.findViewById(R.id.txtPromoter);
TextView textLocation =(TextView)alertView.findViewById(R.id.txtLocation);
//Assign the appropriate data from our alert object above
textPromo.setText(al.promocontent);
textPromoter.setText(al.promoterid);
textLocation.setText(al.locationid);
return alertView;
}
}
You need to use the onItemClick event's parameters
a full more readable param enum with param name is
(AdapterView<?> parent, View view, int pos, long id)
that means you have the pos param that indicated the position in the adapter.
What you have to do is:
jump to pos in the adapter
read out the values from the adapter
use putExtra to signup for the intent
had an epiphany over the weekend about how to fix this problem and i finally found a good work around for my app.. i know it isnt optimal because i hard coded the number 100 into it but for my uses as of now i know i wont ever have that many list items..
i added these 2 bits of code to my alertsadapter class
int startzero = 0;
public static String[][] promomatrix = new String[6][100];
and
promomatrix[0][startzero] = al.cityid;
promomatrix[1][startzero] = al.promoterid;
promomatrix[2][startzero] = al.promocontent;
promomatrix[3][startzero] = al.promotitle;
promomatrix[4][startzero] = al.locationid;
promomatrix[5][startzero] = al.cover;
startzero++;
then went to my homepageactivity class and added this to the click listener
Intent intent = new Intent(
HomePageActivity.this,PromotionActivity.class);
intent.putExtra("listitemcity", AlertsAdapter.promomatrix[0][pos]);
intent.putExtra("listitempromoter", AlertsAdapter.promomatrix[1][pos]);
intent.putExtra("listitemcontent", AlertsAdapter.promomatrix[2][pos]);
intent.putExtra("listitemtitle", AlertsAdapter.promomatrix[3][pos]);
intent.putExtra("listitemlocation", AlertsAdapter.promomatrix[4][pos]);
intent.putExtra("listitemcover", AlertsAdapter.promomatrix[5][pos]);
finish();
startActivity(intent);
and finally went to my promotionactivity (where i was trying to send the strings) and added this
Bundle extras = getIntent().getExtras();
if (extras == null){
return;
}
String listitemcity = extras.getString("listitemcity");
String listitempromoter = extras.getString("listitempromoter");
String listitemcontent = extras.getString("listitemcontent");
String listitemtitle = extras.getString("listitemtitle");
String listitemlocation = extras.getString("listitemlocation");
String listitemcover = extras.getString("listitemcover");
worked like a charm.. i hope this helps someone :)