How to put Element text on one row in ListActivity with this
I am using this code to retrieve a set of game titles platform and release dates:
public class HtmlparserExampleActivity extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayList<String> gameList = new ArrayList<String>();
Document doc = null;
try {
doc = Jsoup.connect("http://www.gamespy.com/index/release.html").get();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 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");
// Iterator over those elements
ListIterator<Element> postIt = games.listIterator();
while (postIt.hasNext()) {
// Add the game text to the ArrayList
gameList.add(postIt.next().text());
Log.v(TAG, games.text());
}
String[] items = new String[gameList.size()];
gameList.toArray(items);
this.setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, items));
}
}
It works perfectly like this. The only problem is if you go to the webpage I'm retrieving the items from. It displays the game title, release date, and the platform all on separate list rows.
How could I put the title, platform release date and all in one row for EACH game I retrieve?
EDIT - ClassCast Exception error:
08-15 16:35:12.310: ERROR/AndroidRuntime(21589): FATAL EXCEPTION: main 08-15 16:35:12.310: ERROR/AndroidRuntime(21589): java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams 08-15 16:35:12.310: ERROR/AndroidRuntime(21589): at android.widget.ListView.setupChild(ListView.java:1790) 08-15 16:35:12.310: ERROR/AndroidRuntime(21589): at android.widget.ListView.makeAndAddView(ListView.java:1759) 08-15 16:35:12.310: ERROR/AndroidRuntime(21589): at android.widget.ListView.fillDown(ListView.java:656) 08-15 16:35:12.310: ERROR/AndroidRuntime(21589): at android.widget.ListView.fillFromTop(ListView.java:716) 08-15 16:35:12.310: ERROR/AndroidRuntime(21589): at android.widget.ListView.layoutChildren(ListView.java:1609) 08-15 16:35:12.310: ERROR/AndroidRuntime(21589): at android.widget.AbsListView.onLayout(AbsListView.java:1800) 08-15 16:35:12.310: ERROR/AndroidRuntime(21589): at android.view.View.layout(View.java:9581)
Here is the code I constructed following the tutorial and your answer:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.l开发者_JAVA技巧ayout.main);
ArrayList<GameRelease> gameList = new ArrayList<GameRelease>();
Document doc = null;
try {
doc = Jsoup.connect("http://www.gamespy.com/index/release.html").get();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 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");
// Iterator over those elements
ListIterator<Element> postIt = games.listIterator();
while (postIt.hasNext()) {
// ...
while (postIt.hasNext()) {
// Add the game text to the ArrayList
String name = postIt.next().text();
String platform = postIt.next().text();
String genre = postIt.next().text();
String releaseDate = postIt.next().text();
gameList.add(new GameRelease(name, platform, genre, releaseDate));
Log.v(TAG, games.text());
}
this.setListAdapter(new GameReleaseAdapter(this, gameList));
}
}
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);
tt.setText(o.getName());
bt.setText(o.getReleaseDate());
return bt;
}
}
}
EDIT - Layout item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip">
<LinearLayout
android:orientation="vertical"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent">
<TextView
android:id="@+id/toptext"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center_vertical"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:id="@+id/bottomtext"
android:singleLine="true"
android:ellipsize="marquee"
/>
</LinearLayout>
</LinearLayout>
What it's doing is getting each HTML <td>
(table cell) as a separate String as opposed to each <tr>
. You probably already know this.
You probably want to make a custom adapter that takes in multiple Strings (a couple elements from your List), and has an overrided getView()
to display the contents exactly however you want them (lined up as if in a table, or in two-line format, with bigger text showing the game name, and smaller text saying "Platform: X Genre: Y Release Date: Z", for two examples).
Here is a tutorial on making your own custom list adapter (this is as opposed to your current ArrayAdapter<String>
).
Let's have an object, GameRelease
, for each item (what you probably want in place of Orders in the tutorial):
public class GameRelease {
private String name;
private String platform;
private String genre;
private String releaseDate;
public String getName() {
return name;
}
public String getPlatform() {
return platform;
}
public String getReleaseDate() {
return releaseDate;
}
public String getGenre() {
return genre;
}
public GameRelease(String name, String platform, String genre, String releaseDate) {
this.name = name;
this.platform = platform;
this.genre = genre;
this.releaseDate = releaseDate;
}
}
Then, I would write an adapter that looks something like this, taking your new GameRelease object:
private class GameReleaseAdapter extends ArrayAdapter<GameRelease> {
private ArrayList<GameRelease> items;
public GameReleaseAdapter(Context context, ArrayList<Order> items) {
// TODO: make a layout for each item which you'd call (for example) itemLayout
super(context, R.layout.itemLayout, 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
}
}
Now once you have that all set, you can instead of your while loop adding only one String element per <td>
, take the GameRelease and fill it with multiple <td>
elements (four, in the same order the site gives them), ex:
ArrayList<GameRelease> gameList = new ArrayList<GameRelease>();
Document doc = null;
try {
doc = Jsoup.connect("http://www.gamespy.com/index/release.html").get();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 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");
// Iterator over those elements
ListIterator<Element> postIt = games.listIterator();
while (postIt.hasNext()) {
// Add the game text to the ArrayList
String name = postIt.next().text();
String platform = postIt.next().text();
String genre = postIt.next().text();
String releaseDate = postIt.next().text();
gameList.add(new GameRelease(name, platform, genre, releaseDate));
Log.v(TAG, games.text());
}
this.setListAdapter(new GameReleaseAdapter(this, gameList));
Just a note: since ArrayAdapter<T>
has a constructor for List<T>
(instead of T[]
), which is a superclass of ArrayList<T>
, you can pass in your ArrayList<String>
or ArrayList<GameRelease>
instead of converting it into an array.
You could just iterate over the <tr>s, and then in the loop iterate over <td>s and build the string along the way, pushing it out only when you've got all <td>s from the row.
精彩评论