Сделать мой CustomView ArrayAdapter ListView расширяемым?
У меня есть собственный ListView, который я заполняю своим собственным ArrayAdapter. Я читаю и анализирую данные json по URL и заполняю ListView этим. Это прекрасно работает, когда я читаю первый файл. Теперь я хочу иметь возможность добавлять больше данных (старые сообщения) в мой ListView. Я добавил кнопку "Загрузить еще" в качестве нижнего колонтитула в ListView, когда я загрузил новые данные и попытался прокрутить их, я получил эту ошибку:
java.lang.IndexOutOfBoundsException: неверный индекс 25, размер 25
Сначала я вообще не понимал, почему это так, теперь я понимаю, что мой ListView не расширяется. Когда я ищу в Google расширяемые ListView, пользовательские адаптеры расширяют BaseExpandableListAdapter, но я не уверен, как реализовать это в моем приложении. Мой настраиваемый адаптер массива определяется следующим образом:
private class StreamAdapter extends ArrayAdapter<Message>
Сообщение является одним из моих классов.
Вот как я отображаю данные:
private void DisplayData() {
// If the request was successfull then notify the adapter to display the data
if(success) {
if(dataAdapter.isEmpty())
{
dataAdapter.addAll(dataList);
dataAdapter.notifyDataSetChanged();
}
// If the listview isn't empty we want to erase what's there and then add the older posts to display
else
{
/** Add currently displayed messages to a temporary arraylist, clear the listview, then add both arraylists in the correct order **/
int size = messageList.getTop();
ArrayList<Message> temp = new ArrayList<Message>();
for(int i = 0; i < size; i++)
{
temp.add(dataAdapter.getItem(i));
}
dataAdapter.clear();
temp.addAll(dataList);
dataAdapter.addAll(temp);
dataAdapter.notifyDataSetChanged();
}
}
}
Вся вещь temp-ArrayList была единственным способом, которым я мог придумать, чтобы получить недавно загруженные данные (но самые старые сообщения) внизу списка, а не вверху.
Есть ли способ легко сделать мой ListView расширяемым или мне нужно переписать весь мой класс StreamAdapter?
Кристина
РЕДАКТИРОВАТЬ: Вот код для моего класса StreamAdapter, но я не учел некоторые части, так как я уверен, что это не актуально и просто добавляет к куче кода.
закрытый класс StreamAdapter расширяет ArrayAdapter {
public StreamAdapter(Context context, int textViewResourceId, ArrayList<Message> dataList)
{
super(context,textViewResourceId, dataList);
}
private class ViewHolder {
ImageView thumbnail;
TextView display_name;
TextView username;
TextView created_at;
TextView text;
ImageView comments;
TextView nr_comments;
@SuppressWarnings("unused")
ImageView like;
TextView nr_likes;
@SuppressWarnings("unused")
ImageView starred;
TextView nr_starred;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if(convertView == null)
{
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.data_row, null);
holder = new ViewHolder();
holder.thumbnail = (ImageView) convertView.findViewById(R.id.thumbnail);
holder.display_name = (TextView) convertView.findViewById(R.id.display_name);
holder.username = (TextView) convertView.findViewById(R.id.username);
holder.created_at = (TextView) convertView.findViewById(R.id.created_at);
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.comments = (ImageView) convertView.findViewById(R.id.comments);
holder.nr_comments = (TextView) convertView.findViewById(R.id.nr_comments);
holder.like = (ImageView) convertView.findViewById(R.id.like);
holder.nr_likes = (TextView) convertView.findViewById(R.id.nr_likes);
holder.starred = (ImageView) convertView.findViewById(R.id.starred);
holder.nr_starred = (TextView) convertView.findViewById(R.id.nr_starred);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
final Message data = dataList.get(position);
holder.thumbnail.setImageDrawable(getResources().getDrawable(R.drawable.owl_thumbnail));
holder.display_name.setText(data.created_by.getDisplay_name());
holder.username.setText("@"+data.created_by.getUsername());
holder.created_at.setText(data.getCreated_at());
holder.nr_comments.setText(Integer.toString(data.getComments().length));
holder.nr_likes.setText(Integer.toString(data.getLiked_by().length));
holder.nr_starred.setText(Integer.toString(data.getStarred_by().length));
// Code to make certain text in the text-textview clickable
// Clickhandler for the username (display_name)
holder.display_name.setOnClickListener(new OnClickListener() {
// Code
});
// Clickhandler for comments
holder.comments.setOnClickListener(new OnClickListener() {
//Code
});
return convertView;
}
}
3 ответа
Вместо добавления новых данных в элементы адаптера попробуйте получить ссылку на ваш список данных из адаптера и добавить эти данные в него, например:
private class StreamAdapter extends ArrayAdapter {
private ArrayList<Message> dataList;
public StreamAdapter(Context context, int textViewResourceId, ArrayList<Message> dataList)
{
super(context,textViewResourceId, dataList);
this.dataList=dataList;
}
public ArrayList<Message> getDataList(){
return dataList;
}
public void setDataList(ArrayList<Message> dataList){
this.dataList=dataList;
}
...
...
}
И когда вы обновите его
private void DisplayData() {
// If the request was successfull then notify the adapter to display the data
if(success) {
ArrayList<Message> temp = dataAdapter.getDataList();
for(int i = 0; i < dataList.size(); i++)
{
temp.add(i,dataList.get(i));
}
dataAdapter.notifyDataSetChanged();
}
}
Это должно сработать, попробуйте и дайте мне знать.
Также переопределить следующую функцию внутри адаптера
@Override
public int getCount() {
return dataList.size();
}
РЕДАКТИРОВАТЬ
private void DisplayData() {
// If the request was successfull then notify the adapter to display the data
if(success) {
ArrayList<Message> temp = dataAdapter.getDataList();
dataList.addAll(temp);
dataAdapter.setDataList(dataList);
dataAdapter.notifyDataSetChanged();
}
}
РЕДАКТИРОВАТЬ 2
private void DisplayData() {
// If the request was successfull then notify the adapter to display the data
if(success) {
ArrayList<Message> temp = dataAdapter.getDataList();
temp.addAll(dataList);
dataAdapter.notifyDataSetChanged();
}
}
Нет, вы не должны использовать ExpandableListAdapter, и вам не нужно предоставлять новую реализацию адаптера. Исключение, которое вы получаете, вероятно, связано с плохой обработкой массива, как вы уже догадались. У меня была похожая проблема, но я использовал адаптеры с Cursor (запрашивающим базу данных), поэтому я думаю, что notifydataSetChanged() должно быть достаточно, чтобы адаптер перезагрузил данные и отобразил их после того, как адаптер был заполнен дополнительными данными.
ExpandableListAdapter используется, когда вам нужно отобразить данные способом PARENT -> CHILDREN, поэтому с ExpandableListView вы видите список родительских элементов, каждый из которых имеет несколько дочерних элементов, каждый родительский элемент раскрывается / сворачивается (и, таким образом, показывает / скрывает дочерние элементы), когда вы нажмите здесь.
Попробуй заменить
int size = messageList.getTop();
с
int size = dataAdapter.getCount();