Добавление текста подпункта ListView в Android

#java #android #listview #android-layout

#java #Android #listview #android-макет

Вопрос:

Я создал программу чтения RSS, в которой перечислены элементы в listview. Мне также нужна дата под каждым элементом, но я понятия не имею, как это сделать. Мне нужна чья-то помощь, чтобы в тексте подпункта отображалась дата публикации, полученная из RSS-канала.

Это код, который у меня есть для моего класса:

 public class RSSReader extends Activity implements OnItemClickListener
{
    public final String RSSFEEDOFCHOICE = "http://app.calvaryccm.com/mobile/android/v1/devos";

    public final String tag = "RSSReader";
    private RSSFeed feed = null;

    /** Called when the activity is first created. */

    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);

        // go get our feed!
        feed = getFeed(RSSFEEDOFCHOICE);

        // display UI
        UpdateDisplay();
    }

    private RSSFeed getFeed(String urlToRssFeed)
    {
        try
        {
            // setup the url
           URL url = new URL(urlToRssFeed);

           // create the factory
           SAXParserFactory factory = SAXParserFactory.newInstance();
           // create a parser
           SAXParser parser = factory.newSAXParser();

           // create the reader (scanner)
           XMLReader xmlreader = parser.getXMLReader();
           // instantiate our handler
           RSSHandler theRssHandler = new RSSHandler();
           // assign our handler
           xmlreader.setContentHandler(theRssHandler);
           // get our data via the url class
           InputSource is = new InputSource(url.openStream());
           // perform the synchronous parse           
           xmlreader.parse(is);
           // get the results - should be a fully populated RSSFeed instance, or null on error
           return theRssHandler.getFeed();
        }
        catch (Exception ee)
        {
            // if we have a problem, simply return null
            System.out.println(ee.getMessage());
            System.out.println(ee.getStackTrace());
            System.out.println(ee.getCause());
            return null;
        }
    }
    public boolean onCreateOptionsMenu(Menu menu) 
    {
        super.onCreateOptionsMenu(menu);
        menu.add(Menu.NONE, 0, 0, "Refresh");
        Log.i(tag,"onCreateOptionsMenu");
        return true;
    }

    public boolean onOptionsItemSelected(MenuItem item){
        switch (item.getItemId()) {
        case 0:

            Log.i(tag,"Set RSS Feed");
            return true;
        case 1:
            Log.i(tag,"Refreshing RSS Feed");
            return true;
        }
        return false;
    }

    private void UpdateDisplay()
    {
        TextView feedtitle = (TextView) findViewById(R.id.feedtitle);
        TextView feedpubdate = (TextView) findViewById(R.id.feedpubdate);
        ListView itemlist = (ListView) findViewById(R.id.itemlist);


        if (feed == null)
        {
            feedtitle.setText("No RSS Feed Available");
            return;
        }

        if(feedtitle != null)
            feedtitle.setText(feed.getTitle());
        if(feedpubdate != null)
            feedpubdate.setText(feed.getPubDate());


        ArrayAdapter<RSSItem> adapter = new ArrayAdapter<RSSItem>(this,android.R.layout.simple_list_item_1,feed.getAllItems());

        itemlist.setAdapter(adapter);

        itemlist.setOnItemClickListener(this);

        itemlist.setSelection(0);
    }

    @Override
    public void onItemClick(AdapterView parent, View v, int position, long id)
    {
        //Log.i(tag,"item clicked! ["   feed.getItem(position).getTitle()   "]");       

        Intent itemintent = new Intent(this,ShowDescription.class);

        Bundle b = new Bundle();
        b.putString("title", feed.getItem(position).getTitle());
        b.putString("description", feed.getItem(position).getDescription());
        b.putString("link", feed.getItem(position).getLink());
        b.putString("pubdate", feed.getItem(position).getPubDate());

        itemintent.putExtra("android.intent.extra.INTENT", b);

        startActivity(itemintent);
    }
}
 

Это мой XML:

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
 <TextView  
android:layout_width="fill_parent" 
android:layout_height="wrap_content" 
android:text="Android RSSReader"
android:id="@ id/feedtitle"/>
<TextView  
android:layout_width="fill_parent" 
android:layout_height="wrap_content" 
android:text=""
android:id="@ id/feedpubdate"/>
<ListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@ id/itemlist"

android:fastScrollEnabled="true"/>    
 </LinearLayout>
 

Вот как это выглядит сейчас в Eclipse:

Просмотр списка в настоящее время

Вот как это выглядит при запуске:

В процессе

Как заставить текст подпункта отображать дату публикации, полученную из RSS-канала?

Ответ №1:

Вероятно, самым простым решением является замена ArrayAdapter и android.R.layout.simple_list_item_1 , которые вы используете, SimpleAdapter и android.R.layout.simple_list_item_2 предопределенным макетом. Этот макет состоит из двух TextView s с идентификаторами android.R.id.text1 («элемент») и android.R.id.text2 («подпункт») соответственно, которые вам понадобятся в качестве ссылки для SimpleAdapter работы.

<a rel=»noreferrer noopener nofollow» href=»https:///developer.android.com/reference/android/widget/SimpleAdapter.html#SimpleAdapter(android.content.Context, java.util.List<? extends java.util.Map>, int, java.lang.String[], int[])» rel=»noreferrer»>Взглянув на конструктор for SimpleAdapter , вы заметите, что, помимо Context экземпляра и идентификатора ресурса макета, он принимает три параметра, которые могут быть новыми для вас:

  • List<? extends Map<String, ?>> экземпляр, в который вы помещаете элементы, которые хотите ListView отобразить. Элементы имеют форму a Map , то есть что-то похожее на структуру, состоящую из свойств в виде пар имя / значение. Например, вы можете использовать "title" и "date" как ключи для заголовка и даты каждого элемента RSS соответственно.
  • массив строк, куда помещаются имена ключей в каждой карте, которые вы хотите отобразить на ListView .
  • массив целых чисел, в который вам нужно поместить идентификаторы частей в представлении элемента списка, где вы хотите, чтобы отображались отдельные элементы, на которые ссылаются ключи в предыдущем массиве строк. Например, если вы хотите отобразить заголовок и дату элемента RSS в представлениях «элемент» и «подпункт» соответственно, вы используете new String[] { "title", "date" } в качестве аргумента array of strings и new int[] { android.R.id.text1, android.R.id.text2 } в качестве аргумента this .

Пример приблизительного кода, просто чтобы дать вам представление:

 List<Map<String, String>> data = new ArrayList<Map<String, String>>();
for (RSSItem item : feed.getAllItems()) {
    Map<String, String> datum = new HashMap<String, String>(2);
    datum.put("title", item.getTitle());
    datum.put("date", item.getDate().toString());
    data.add(datum);
}
SimpleAdapter adapter = new SimpleAdapter(this, data,
                                          android.R.layout.simple_list_item_2,
                                          new String[] {"title", "date"},
                                          new int[] {android.R.id.text1,
                                                     android.R.id.text2});
itemList.setAdapter(adapter);
 

В документации указано, что «карты содержат данные для каждой строки и должны включать все записи, указанные в параметре from», поэтому всегда должны присутствовать как заголовок, так и дата.

Пожалуйста, обратите внимание, что все это не укладывается у меня в голове. На самом деле я не тестировал весь код, поэтому вы вполне можете столкнуться с какой-нибудь причудой или ошибкой, которые вам нужно исправить или исправить на своем пути.

Ответ №2:

У вас должен быть item_list.xml файл, подобный этому:

     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="6dp" >

    <TextView
        android:id="@ id/page_title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textColor="#D8000000"
        android:textSize="16sp"
        android:textStyle="bold" />

    <TextView
        android:id="@ id/page_date"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/page_title"
        android:ellipsize="marquee"
        android:lines="3"
        android:marqueeRepeatLimit="marquee_forever"
        android:textColor="#D8000000"
        android:textSize="12sp" />

</RelativeLayout>
 

и в вашем listadapter в методе getview :

 View row = convertView;
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
row = inflater.inflate(R.layout.item_list, parent, false);

TextView listTitle = (TextView) row.findViewById(R.id.page_title);
 listTitle.setText(title);

TextView date = (TextView) row.findViewById(R.id.page_date); 
date.setText( <here put your date from RSS feed>);

return row;
 

это должно сделать это!

Комментарии:

1. Это здорово, но параметр layout_below не работает в LinearLayout. Любое решение для этого?

2. Я знаю, что это далеко не поздно, но используйте android:orientation="vertical" в RelativeLayout amp; remove android:layout_below

Ответ №3:

Поскольку вы хотите сопоставить несколько элементов данных с несколькими представлениями, вы не можете использовать ArrayAdapter. Вместо этого вам придется использовать SimpleAdapter.

Кроме того, я заметил, что вы получаете RSS-канал в основном потоке пользовательского интерфейса. Это приведет к тому, что ваше приложение будет сильно не реагировать. Если вы не знаете, о чем я говорю, взгляните на статью Безболезненная потоковая обработка (я считаю ее обязательной для прочтения любым разработчиком Android). Вместо этого вам следует использовать загрузчик. Они были разработаны именно для вашего типа ситуации. Хотя они не были представлены до API-10, вы все равно можете использовать их на меньших уровнях API через пакет поддержки.

Комментарии:

1. Я поддерживаю предложение о переносе загрузки канала из потока пользовательского интерфейса. Просто хочу добавить, что другим способом сделать это, если OP не хочет нести бремя пакета поддержки, может быть использование AsyncTask .

2. Не бойтесь пакета поддержки! Это действительно просто в использовании, совсем не обременительно 🙂

3. Где я могу получить эту статью

Ответ №4:

создайте пользовательский ListView http://saigeethamn.blogspot.com/2010/04/custom-listview-android-developer.html