[Tutorial Fortgeschrittene Folge 1] RSS-Feed zu Json und Weiterverarbeitung in Apps

  • Antworten:6
Ludy
  • Admin
  • Forum-Beiträge: 7.958

08.07.2016, 20:05:48 via Website

Ich zeige euch heute wie man aus einem RSS-Feed einen Json-String erstellt und weiterverarbeitet.

TEIL 1

Was wird gebraucht?
- einen Server der PHP und DOMDocument beherrscht.
- einen Texteditor, ich nutze Notepad++ UTF-8 ohne BOM
- Android Studio

Nun geht es los:

Als erstes erstellen wir uns eine PHP-Datei (rss.php), mit den gewohnten PHP-Tags.

<?php 

?>

In dem PHP-Tag schreiben wir die Header-Information:

  • Type Json
  • encoding UTF-8.

    header("Content-type: application/json; charset=utf-8");
    

Nun erstellen wir die Variable ($rss_url) für die Url des Feeds und erstellen ein Objekt ($feed) der Klasse DOMDocument. Wenn das geschafft ist, laden wir die Informationen von der Seite des RSS-Feeds in $feed.

$rss_url = 'https://www.nextpit.de/feed/main.xml';

$feed = new DOMDocument();
$feed->load($rss_url);

Mit vier Codezeilen haben wir die halbe Miete, dann holen wir uns nun noch die zweite Hälfte.

Was wir jetzt brauchen, finden wir im Feed selber (er sollte als Quellcode betrachtet werden).

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>...</title>
    <link>https://www.nextpit.de/</link>
    <description>...</description>
    <language>de</language>
    <pubDate>Tue, 05 Jul 2016 09:52:04 GMT</pubDate>
    <dc:creator>AndroidPIT</dc:creator>
    <dc:date>2016-07-05T09:52:04Z</dc:date>
    <dc:language>de</dc:language>
    <item>
      <title>...</title>
      <link>https://...</link>
      <description>...</description>
      <pubDate>...</pubDate>
      <guid isPermaLink="false">...</guid>
      <dc:creator>...</dc:creator>
      <dc:date>...</dc:date>
    </item>
  </channel>
</rss>

Schematisch sieht das Ganze so aus, jetzt wird das wichtigste herausgesucht und das bleibt dann über.

  <channel>
    <title>...</title>
    <link>https://www.nextpit.de/</link>
    <description>...</description>
    <language>de</language>
    <pubDate>...</pubDate>
    <dc:creator>AndroidPIT</dc:creator>
    <item>
      <title>...</title>
      <link>https://...</link>
      <description>...</description>
      <pubDate>...</pubDate>
      <dc:creator>...</dc:creator>
    </item>
  </channel>

Okay, dann wissen wir das channel-Tag unser Eltern-Tag ist, von dem alles ausgeht.
Zunächst erstellen wir uns ein Array() ($json).

Channel besitzt mehrere „einfache“ (title, link, description, language, pubDate, dc:creator) Kinder und ein „kompliziertes“ (item) Kind. Da nachher ein Json-String entstehen soll, geben wir $json den title, link description, language, pubDate und dc:creator mit.

(!) An dc:creator seht ihr eine Besonderheit, es gibt keinen "normalen" TagName(creator) sondern einen TagName mit Namespace (dc). (!)

Die Namespace-URI findet ihr im Tag rss unter dem Attrebut xmls:{Namespace}=URI
sie lautet http://purl.org/dc/elements/1.1/, diese muss immer dort angewendet werden, wo kein normaler Tagname definiert ist, nun gut, noch eine Variable geschrieben.

<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">

$slashNS =             "http://purl.org/dc/elements/1.1/";

$parentElement =       $feed->getElementsByTagName('channel')->item(0);

$json = array();

$json['title'] =       $parentElement->getElementsByTagName('title')->item(0)->firstChild->nodeValue;
$json['link'] =        $parentElement->getElementsByTagName('link')->item(0)->firstChild->nodeValue;
$json['description'] = $parentElement->getElementsByTagName('description')->item(0)->firstChild->nodeValue;
$json['language'] =    $parentElement->getElementsByTagName('language')->item(0)->firstChild->nodeValue;
$json['pubDate'] =     $parentElement->getElementsByTagName('pubDate')->item(0)->firstChild->nodeValue;
$json['creator'] =     $parentElement->getElementsByTagNameNS($slashNS, 'creator')->item(0)->firstChild->nodeValue;

Der Header-Teil des RSS-Feed ist nun schon einmal fertig und könnte theoretisch Json encoded werden, aber ein Feed soll mehr sein, er soll die Infos der Seite widerspiegeln.
Nun werden wir die item Kinder-Tags untersuchen – enthalten ist 'title', 'link', 'description', 'pubDate' und 'dc:creator'.

Da so ein Feed bzw. Artikel mehrere Informationen liefert, werden die item auch mehrfach vorkommen.
Daher definieren wir eine Variabel items ($items) und dieser übergeben wir alle 'item'-Tags.
Dem Json-Array geben wir noch einen Array (item) mit.

$items = $parentElement->getElementsByTagName('item');
$json['item'] = array();

Um $json['item'] zu füllen brauchen wir eine 'foreach'-Schleife, sie wird solange ausgeführt bis kein 'item'-Tag mehr vorhanden ist. Jetzt gehen wir wie beim Headerteil vor - Variablen erstellen von 'title', 'link', 'description', 'pubDate' und 'dc:creator'.

$json['item'] wird in der Schleife befüllt, aber dass nicht immer wieder unserer Wert im Array überschrieben wird, ergänzen wir diesen mit einem Array() in der Schleife.

Aus 'title', 'link', 'description', 'pubDate' und 'dc:creator' erstellen wir innerhalb der Schleife einen assoziativen Array()

$json['item'][] = array("title"=>$title, "link"=>$link, "description"=>$description, "pubDate"=>$pubDate, "creator"=>$creator);

foreach ($items as $item) {
    $title =          $item->getElementsByTagName('title')->item(0)->firstChild->nodeValue;
    $link =           $item->getElementsByTagName('link')->item(0)->firstChild->nodeValue;
    $description =    $item->getElementsByTagName('description')->item(0)->firstChild->nodeValue;
    $pubDate =        $item->getElementsByTagName('pubDate')->item(0)->firstChild->nodeValue;
    $creator =        $item->getElementsByTagNameNS($slashNS, 'creator')->item(0)->firstChild->nodeValue;
    $json['item'][] = array("title"=>$title,"link"=>$link,"description"=>$description,"pubDate"=>$pubDate,"creator"=>$creator);
}

Und als letzten Schritt geben wir unser Resultat aus.

echo json_encode($json);

— geändert am 15.07.2016, 21:02:49

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

swa00Andy N.Pascal P.

Antworten
Ludy
  • Admin
  • Forum-Beiträge: 7.958

08.07.2016, 20:06:12 via Website

Das Resultat sollte nun so aussehen.

<?php 
    header("Content-type: application/json; charset=utf-8");

    $rss_url = 'https://www.nextpit.de/feed/main.xml';

    $feed = new DOMDocument();
    $feed->load($rss_url);

    $slashNS = "http://purl.org/dc/elements/1.1/";
    $parentElement = $feed->getElementsByTagName('channel')->item(0);

    $json = array();
    $json['title'] =       $parentElement->getElementsByTagName('title')->item(0)->firstChild->nodeValue;
    $json['link'] =        $parentElement->getElementsByTagName('link')->item(0)->firstChild->nodeValue;
    $json['description'] = $parentElement->getElementsByTagName('description')->item(0)->firstChild->nodeValue;
    $json['language'] =    $parentElement->getElementsByTagName('language')->item(0)->firstChild->nodeValue;
    $json['pubDate'] =     $parentElement->getElementsByTagName('pubDate')->item(0)->firstChild->nodeValue;
    $json['creator'] =     $parentElement->getElementsByTagNameNS($slashNS, 'creator')->item(0)->firstChild->nodeValue;

    $items = $parentElement->getElementsByTagName('item');

    $json['item'] = array();
    foreach ($items as $item) {
        $title =          $item->getElementsByTagName('title')->item(0)->firstChild->nodeValue;
        $link =           $item->getElementsByTagName('link')->item(0)->firstChild->nodeValue;
        $description =    $item->getElementsByTagName('description')->item(0)->firstChild->nodeValue;
        $pubDate =        $item->getElementsByTagName('pubDate')->item(0)->firstChild->nodeValue;
        $creator =        $item->getElementsByTagNameNS($slashNS, 'creator')->item(0)->firstChild->nodeValue;
        $json['item'][] = array("title"=>$title,"link"=>$link,"description"=>$description,"pubDate"=>$pubDate,"creator"=>$creator);
    }
    echo json_encode($json);
?>

.

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

swa00Andy N.Pascal P.

Antworten
Ludy
  • Admin
  • Forum-Beiträge: 7.958

08.07.2016, 20:06:35 via Website

TEIL 2

Die Verarbeitung eines Json-String ist einfacher als ein XML-String, die Fehlerquote beim Parsen durch GSON geht gegen Null.


Erstellt ein neues Projekt in Android Studio, wie das geht wird in diesem Thread nicht weiter erläutert.

Benötigte Library

  • compile 'com.android.support:appcompat-v7:25.3.1'
  • compile 'com.android.support:cardview-v7:25.3.1'
  • compile 'com.android.support:recyclerview-v7:25.3.1'
  • compile 'com.google.code.gson:gson:2.8.0'

Als erstes brauchen wir ein Layout, was RecyclerView beinhaltet. Das RecyclerView wird mit einem LinearLayout umschlossen.

activity_feed.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:background="#b65757">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"/>
</LinearLayout>

FeedActivity wird unsere Start-Activity sein. Initialisieren werden wir RecyclerView.

FeedActivity.java

public class FeedActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_feed);
        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    }

}

Okay, nun haben wir schon einmal die Bases.
Um das Json-Objekt in die Activity zu bekommen, brauchen wir eine Internetverbindung (Permission in der AndroidManifest.xml deklarieren).
Was brauchen wir noch, genau eine Schnittstelle! Zu beachten ist das solche Schnittstellen nicht in der Activity-Laufzeit ausgeführt werden dürfen, sie müssen immer in einem Thread() ausgeführt werden. In unserem Fall verwenden wir einen AsyncTask. Dazu erstellen wir uns eine neue Klasse LoadRss.java und erweitern diese mit

AsyncTask<String, String, String>

LoadRss.java

public class LoadRss extends AsyncTask<String, String, String> {

    @Override
    protected String doInBackground(String... params) {
        return null;
    }

    @Override
    protected void onPostExecute(String s) {

    }
}

Die FeedActivity#onCreate können wir nun mit new LoadRss().execute(); ausstatten.

FeedActivity.java

public class FeedActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // [...]
        // gekürtzt
        new LoadRss().execute();
    }

}

Bevor wir die LoadRss.java mit allem was dazu gehört ausstatten, erstellen wir ein Interface und eine Klasse, die dieses Implementiert.

RssResultInterface.java

public interface RssResultInterface {
    void onResult(String result);

    void onResponseCode(int responseCode);
}

Das onResult(String) wird uns später das Ergebnis von der #onPostExecute liefern und onResponseCode(int) den ResponseCode aus #doInBackground. Um den Code in der FeedActiviy.java übersichtlich zu halten, implementieren wir RssResultInterface.java in RssResult.java. Durch diese Implementierung müssen wir nicht alle Methoden in der FeedActivity.java implementieren, wenn RssResult aufgerufen wird. Was ich meine wird euch später klar.

RssResult.java

public class RssResult implements RssResultInterface {
    @Override
    public void onResult(String result) {

    }

    @Override
    public void onResponseCode(int responseCode) {

    }
}

Um das Interface nutzen zu können, initialisieren wir RssResult.java und übergeben wir dieses der LoadRss.java.

Nun seht ihr, dass das #onResponseCode nicht mit implementiert werden muss

private RssResult rssInterface = new RssResult() {
    @Override
    public void onResult(String result) {

    }
};

FeedActivity#onCreate

new LoadRss(rssInterface).execute();

So würde es mit dem "normalen" Interface (RssResultInterface.java) aussehen.

private RssResultInterface rssResultInterface = new RssResultInterface() {
    @Override
    public void onResult(String result) {

    }

    @Override
    public void onResponseCode(int responseCode) {

    }
};

Die LoadRss.java benötigt nun einen Konstruktor, der als Parameter RssResult beinhaltet.

private RssResult rssResultInterface;

public LoadRss(RssResult rssInterface) {
    this.rssResultInterface = rssInterface;
}

Das Interface und die fehlenden Komponenten in LoadRss.java werden wir nun hinzufügen. Wir verwenden HttpURLConnection und erstellen eine Hilfsklasse StreamToString.java.

LoadRss.java

public class LoadRss extends AsyncTask<String, String, String> {

    private RssResult rssResultInterface;
    private static final String TAG = LoadRss.class.getSimpleName();

    public LoadRss(RssResult rssInterface) {
        this.rssResultInterface = rssInterface;
    }

    @Override
    protected String doInBackground(String... params) {
        try {
            URL url = new URL(params[0]);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.connect();
            rssResultInterface.onResponseCode(connection.getResponseCode());
            return StreamToString.streamToString(connection.getInputStream());
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
        return null;
    }

    @Override
    protected void onPostExecute(String s) {
        rssResultInterface.onResult(s);
    }
}

Ihr seht richtig, mehr Text gibt es in der Klasse nicht.

URL url = new URL(params[0]);
// params[0] ist die Url, welche noch in der FeedActivity.java übergeben werden muss.

rssResultInterface.onResponseCode(connection.getResponseCode());
// die Methode vom Interface bekommt an dieser Stelle den ResponseCode übergeben

rssResultInterface.onResult(s);
// die Methode vom Interface bekommt an dieser Stelle den JsonObjekt übergeben als String

(!) Aber einen Fehler gibt es noch (!)

StreamToString.streamToString(connection.getInputStream());

Hier benötigen wir die Hilfsklasse StreamToString.java diese nun erstellt werden muss

StreamToString.java

public class StreamToString {
    public static String streamToString(InputStream is) throws IOException {
        StringBuilder sb = new StringBuilder();
        BufferedReader rd = new BufferedReader(new InputStreamReader(is));
        String line;
        while ((line = rd.readLine()) != null) {
            sb.append(line);
        }
        return sb.toString();
    }
}

FeedActivity

private static final String RSS_URL = "http://192.168.0.101/rss.php"; // Hier euren Server eintragen

FeedActivity#onCreate

new LoadRss(rssInterface).execute(RSS_URL);

— geändert am 16.05.2017, 21:43:42

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

swa00Andy N.Pascal P.

Antworten
Ludy
  • Admin
  • Forum-Beiträge: 7.958

08.07.2016, 20:07:00 via Website

TEIL 3

Im dritten Teil werden wir uns in der FeedActivity.java mit dem Interface weiter beschäftigen.

Als erstes sollte wir das ganze debuggen.

private static final String TAG = FeedActivity.class.getSimpleName();

private RssResult rssInterface = new RssResult() {
    @Override
    public void onResult(String result) {
        if (result != null) {
            Log.d(TAG, result);
        }
    }
};

Als Ergebnis sollte unser JsonObjekt als String in der Konsole auftauchen.

{title:"...","link":"...",..........}


Im nächsten Schritt kümmern wir uns um die item-Elemente, der Schlüssel "item" ist ein Array(), dessen Kinder sind Objekte und deren Kinder sind Strings.

Okay dann erstellen wir uns eine neue Klasse Item.java. Die Schlüssel in den einzelnen item-Objekten lauten:

title, link, description, pubDate und creator

dazu erstellen wir noch die einzelnen Getters.

Item.java

public class Item {

    private String title;
    private String link;
    private String description;
    private String pubDate;
    private String creator;

    public String getCreator() {
        return creator;
    }

    public String getDescription() {
        return description;
    }

    public String getLink() {
        return link;
    }

    public String getPubDate() {
        return pubDate;
    }

    public String getTitle() {
        return title;
    }
}

Erstellt eine Klasse (Parent) und implementiert Serializable um etwas flexibler zu sein.

Parent.java

public class Parent implements Serializable {

    @SerializedName("title")
    private String parentTitle;
    @SerializedName("link")
    private String parentLink;
    @SerializedName("description")
    private String parentDescription;
    @SerializedName("language")
    private String parentLanguage;
    @SerializedName("pubDate")
    private String parentPubDate;
    @SerializedName("creator")
    private String parentCreator;
    @SerializedName("item")
    private Item[] parentItems;

    public String getParentCreator() {
        return (parentCreator);
    }

    public String getParentDescription() {
        return parentDescription;
    }

    public Item[] getParentItems() {
        return parentItems;
    }

    public String getParentLanguage() {
        return parentLanguage;
    }

    public String getParentLink() {
        return parentLink;
    }

    public String getParentPubDate() {
        return parentPubDate;
    }

    public String getParentTitle() {
        return parentTitle;
    }
}

SerializedName ist der "echte" Schlüssel des Json-Objekt/-Array, darunter ist unser definierter String mit unserem Namen.


Wenn das Resultat stimmt, können wir weiter machen in der FeedActivity.java, und schmücken private RssResult rssInterface = new RssResult() {onResult} mit ein paar Zeilen Code. Wir werden nun den String in Json konvertieren und unseren Variablen deklarieren und die Daten übergeben.

Gson parentGson = new Gson();

Parent parent = parentGson.fromJson(result, Parent.class);
String parentTitle = parent.getParentTitle();
String parentLink = parent.getParentLink();
String parentDescription = parent.getParentDescription();
String parentLanguage = parent.getParentLanguage();
String parentPubDate = parent.getParentPubDate();
String parentCreator = parent.getParentCreator();

Eine ArrayList die unsere items beinhaltet fehlt uns noch, na dann erstellen und diese für den CustomAdapter übergabefähig machen.

Item[] items = parent.getParentItems();
final ArrayList<Item> list = new ArrayList<>();
Collections.addAll(list, items);

— geändert am 15.07.2016, 20:21:33

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

swa00Andy N.Pascal P.

Antworten
Ludy
  • Admin
  • Forum-Beiträge: 7.958

08.07.2016, 20:07:21 via Website

Teil 3.1

Wir brauchen jetzt einen CustomAdapter für unseren RecyclerView, dazu benötigen wir ein Layout für das CardView (card_view_row.xml).

card_view_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="8dp"
    android:paddingRight="8dp">

    <android.support.v7.widget.CardView
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:card_view="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardUseCompatPadding="true"
        card_view:cardCornerRadius="8dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="8dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/textViewCreator"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="textViewCreator"
                android:textAppearance="?android:attr/textAppearanceSmall"/>

            <TextView
                android:id="@+id/textViewTitle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="textViewTitle"
                android:textAppearance="?android:attr/textAppearanceMedium"/>

            <TextView
                android:id="@+id/textViewDescription"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:maxLines="4"
                android:text="textViewDescription"/>

            <TextView
                android:id="@+id/textViewPubDate"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="textViewPubDate"
                android:textAppearance="?android:attr/textAppearanceSmall"/>
        </LinearLayout>
    </android.support.v7.widget.CardView>
</LinearLayout>

Das Layout ist zwar nicht wirklich schön soll aber für uns erst einmal reichen. Jetzt kommen wir zum Adapter (RssFeedAdapter.java) dieser wird erweitert mit

RecyclerView.Adapter<RssFeedAdapter.ViewHolder>

RssFeedAdapter.ViewHolder ist eine innen liegende Klasse, die erweitert wird mit

RecyclerView.ViewHolder

In der onCreateViewHolder wird das Layout card_view_row.xml inflated und dem RssFeedAdapter.ViewHolder bei der Erstellung mitgegeben.

Die onBindViewHolder ist die Methode, in der aus der Arrayliste von items, die einzelnen Item's ausgelesen werden und je einer CardView zugewiesen wird. Da es eine Arraylist ist, können wir bequem über die Position des Views, die Position des Item bzw. des Inhalt abfragen.

Item items = item.get(position);

Als nächsten Schritt, werden wir die einzelnen View füllen und dem Adapter mitteilen wie viele ArrayObjecte vorhanden sind.

holder.title.setText(items.getTitle());
holder.creator.setText(items.getCreator());
holder.description.setText(items.getDescription());
holder.pubDate.setText(items.getPubDate());


@Override
public int getItemCount() {
    return itemList.size();
}

RssFeedAdapter.java

public class RssFeedAdapter extends RecyclerView.Adapter<RssFeedAdapter.ViewHolder> {

    private ArrayList<Item> itemList;

    public RssFeedAdapter(ArrayList<Item> itemList) {
        this.itemList = itemList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.card_view_row, null, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Item items = itemList.get(position);
        holder.title.setText(items.getTitle());
        holder.creator.setText(items.getCreator());
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            holder.description.setText(Html.fromHtml(items.getDescription(), Html.FROM_HTML_MODE_LEGACY));
        } else {
            holder.description.setText(Html.fromHtml(items.getDescription()));
        }
        holder.pubDate.setText(items.getPubDate());
    }

    @Override
    public int getItemCount() {
        return itemList.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder {

        private TextView title;
        private TextView creator;
        private TextView description;
        private TextView pubDate;

        public ViewHolder(View itemView) {
            super(itemView);
            this.title = (TextView) itemView.findViewById(R.id.textViewTitle);
            this.creator = (TextView) itemView.findViewById(R.id.textViewCreator);
            this.description = (TextView) itemView.findViewById(R.id.textViewDescription);
            this.pubDate = (TextView) itemView.findViewById(R.id.textViewPubDate);
        }
    }
}

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

swa00Andy N.Pascal P.

Antworten
Ludy
  • Admin
  • Forum-Beiträge: 7.958

08.07.2016, 20:07:39 via Website

TEIL 4

Das Ende naht, wir erweitern den Teil:

Item[] items = parent.getParentItems();
final ArrayList<Item> list = new ArrayList<>();
Collections.addAll(list, items);

Die Adapter Variable dürfen wir nicht vergessen!

private RssFeedAdapter rssFeedAdapter;

rssFeedAdapter noch initialisieren mit new RssFeedAdapter und die Liste nicht vergessen - Adapter dem RecyclerView zuweisen.

rssFeedAdapter = new RssFeedAdapter(list);
mRecyclerView.setAdapter(rssFeedAdapter);

Item[] items = parent.getParentItems();
final ArrayList<Item> list = new ArrayList<>();
Collections.addAll(list, items);
rssFeedAdapter = new RssFeedAdapter(list);
mRecyclerView.setAdapter(rssFeedAdapter);

Das Ganze nun debuggen und schau ob es läuft.

— geändert am 15.07.2016, 20:21:53

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

swa00Andy N.Pascal P.

Antworten
Ludy
  • Admin
  • Forum-Beiträge: 7.958

08.07.2016, 20:08:38 via Website

TEIL 5

Aus einer ListView sind wir gewohnt, den Eintrag an zu klicken und eine Aktion wird ausgeführt, beim RecyclerView gibt es nicht den OnItemClickListener, hm unschön.
Aber die Jungs von Little Robots haben eine Hilfsklasse vorgestellt und die werden wir uns zu eigen machen.

ItemClickSupport.java

/**
 * http://www.littlerobots.nl/blog/Handle-Android-RecyclerView-Clicks/
 */
public class ItemClickSupport {
    private final RecyclerView mRecyclerView;
    private OnItemClickListener mOnItemClickListener;
    private OnItemLongClickListener mOnItemLongClickListener;
    private View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mOnItemClickListener != null) {
                RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
                mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
            }
        }
    };
    private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            if (mOnItemLongClickListener != null) {
                RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
                return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
            }
            return false;
        }
    };
    private RecyclerView.OnChildAttachStateChangeListener mAttachListener
            = new RecyclerView.OnChildAttachStateChangeListener() {
        @Override
        public void onChildViewAttachedToWindow(View view) {
            if (mOnItemClickListener != null) {
                view.setOnClickListener(mOnClickListener);
            }
            if (mOnItemLongClickListener != null) {
                view.setOnLongClickListener(mOnLongClickListener);
            }
        }

        @Override
        public void onChildViewDetachedFromWindow(View view) {

        }
    };

    private ItemClickSupport(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
        mRecyclerView.setTag(R.id.item_click_support, this);
        mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
    }

    public static ItemClickSupport addTo(RecyclerView view) {
        ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
        if (support == null) {
            support = new ItemClickSupport(view);
        }
        return support;
    }

    public static ItemClickSupport removeFrom(RecyclerView view) {
        ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
        if (support != null) {
            support.detach(view);
        }
        return support;
    }

    public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
        mOnItemClickListener = listener;
        return this;
    }

    public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
        mOnItemLongClickListener = listener;
        return this;
    }

    private void detach(RecyclerView view) {
        view.removeOnChildAttachStateChangeListener(mAttachListener);
        view.setTag(R.id.item_click_support, null);
    }

    public interface OnItemClickListener {

        void onItemClicked(RecyclerView recyclerView, int position, View v);
    }

    public interface OnItemLongClickListener {

        boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
    }
}

In values brauchen wir noch die ids.xml.

ids.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="item_click_support" type="id"/>
</resources>

Okay, nun ab in die FeedActivity.java und den Listener ans RecyclerView binden.

private RssResult rssInterface = new RssResult() {
    @Override
    public void onResult(String result) {
        if (result != null) {
           //
           // gekürzt
           //
            mRecyclerView.setAdapter(rssFeedAdapter);

            ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
                @Override
                public void onItemClicked(RecyclerView recyclerView, int position, View v) {

                }
            });

        }
    }
};

Wir werden den Link, des einzelnen Artikels, per Intent in das Android System "feuern". Dazu nutzen wir die ArrayList(), die einzelnen Elemente können wir durch die Nennung der Position auslesen.

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(list.get(position).getLink()));
startActivity(intent);

Das vollständige Projekt findet ihr hier und die Fortsetzung findet ihr hier.

Danke an Pascal für den ein oder anderen Denkanstoß (cool)

— geändert am 15.07.2016, 21:17:58

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

swa00Andy N.Pascal P.

Antworten