在Kotlin中阅读rss轻松进行android编程

RSS reading is one of the most important and widely used features across software apps in web or mobile techs. To keep the things in control we would be concentrating our blog to kotlin.

RSS阅读是Web或移动技术中所有软件应用程序中最重要且使用最广泛的功能之一。 为了控制一切,我们将把博客集中在kotlin上。

To start with I would like to emphasize on a saying

首先,我想强调一句话

You can’t build a great building on a weak foundation

您不能在薄弱的基础上建造一幢好建筑物

Therefore, we will first be creating a very basic app for exploring RSS Reading functionality in Kotlin. In the later part of this blog, we would be using MVVM to improve our code structure.

因此,我们将首先创建一个非常基本的应用程序,以探索Kotlin中的RSS阅读功能。 在本博客的后半部分,我们将使用MVVM改进代码结构。

During our journey, we will encounter a few helper libraries like CardView, RecyclerView, Glide, Jsoup in between.

在我们的旅途中,我们将在它们之间遇到一些帮助程序库,例如CardViewRecyclerViewGlideJsoup

So Let’s start the process, you may like to see what we are going to develop

因此,让我们开始这个过程,您可能想看看我们将要开发什么

Image for post

处理 (Process)

I assume that readers know how to checkout projects from a Github repository. Even if they don’t know, they may read more at this and this link. Once you git checkout public repository available at the link and open it in your Android Studio, you will see below code structure in the src folder.

我假设读者知道如何从Github存储库中检出项目。 即使他们不知道,他们可能更多在这个这个链接。 一旦您在链接上可用git checkout公共存储库并在Android Studio中打开它,您将在src文件夹中看到以下代码结构。

Further, this blog is not about recycler view or any other UI component. If required I will write another blog for explaining them.

此外,此博客与回收者视图或任何其他UI组件无关。 如果需要,我将写另一个博客来解释它们。

So we have

所以我们有

Activity called MainActivity

活动称为MainActivity

Fragment called RSSFragment (kind of list fragment)

称为RSSFragment的片段(列表片段的种类)

Recyclerview Adapter called MyItemRecylcerviewAdapter

Recyclerview适配器称为MyItemRecylcerviewAdapter

Model class RSSItem to hold particular RSS item data.

模型类RSSItem以保存特定的RSS项数据。

Parser class for parsing inputstream.

用于解析输入流的解析器类。

Then we have AppGlideModule class required by Glide.

然后,我们有了Glide所需的AppGlideModule类。

Image for post

Below is the code for different files , I will explain them one by one

以下是不同文件的代码,我将一一解释

MainActivity.kt

MainActivity.kt

/*
* Copyright (c) 2020. Relsell Global
*/package com.relsellglobal.kotlinrssreadingimport android.os.Bundle
import androidx.appcompat.app.AppCompatActivityclass MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) supportFragmentManager.beginTransaction().replace(R.id.fragment_root,RSSFragment()).commit(); }
}

we are mere invoking RSSFragment in onCreate method.

我们只是在onCreate方法中调用RSSFragment。

在片段之间分配代码 (Distributing code among fragments)

Fragments are Lightweight, reusable UI components that can be used for creating UI in Android. Invoking an activity is a heavy process for Android OS as compared to fragment. Android OS may choose to reject activity invoking requests by the application.

片段是轻量级,可重用的UI组件,可用于在Android中创建UI。 与片段相比,调用活动对于Android OS是一个繁重的过程。 Android OS可以选择拒绝应用程序的活动调用请求。

You must have encountered the above scenario in real life when your phone stops responding to touch events on screen. Moreover, only the activity is not the only culprit here.

当您的手机停止响应屏幕上的触摸事件时,您必须在现实生活中遇到上述情况。 而且,只有活动不是这里的唯一罪魁祸首。

As per android docs

根据android文档

You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a “sub-activity” that you can reuse in different activities).

您可以将片段视为活动的模块化部分,该片段具有自己的生命周期,接收自己的输入事件,并且可以在活动运行时添加或删除(类似于“子活动”可以在不同的活动中重复使用)。

Therefore we will be using fragment here to build our application.

因此,我们将在这里使用片段来构建我们的应用程序。

/*
* Copyright (c) 2020. Relsell Global
*/package com.relsellglobal.kotlinrssreadingimport android.os.AsyncTask
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.io.IOException
import java.io.InputStream
import java.lang.ref.WeakReference
import java.net.HttpURLConnection
import java.net.URL
/**
* A fragment representing a list of Items.
* Activities containing this fragment MUST implement the
* [RSSFragment.OnListFragmentInteractionListener] interface.
*/
class RSSFragment : Fragment() { // TODO: Customize parameters
private var columnCount = 1 private var listener: OnListFragmentInteractionListener? = null val RSS_FEED_LINK = "http://www.relsellglobal.in/feed/"; var adapter: MyItemRecyclerViewAdapter? = null
var rssItems = ArrayList<RssItem>() var listV : RecyclerView ?= null override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_item_list, container, false) listV = view.findViewById(R.id.listV)
return view
} override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
adapter = MyItemRecyclerViewAdapter(rssItems, listener,activity)
listV?.layoutManager = LinearLayoutManager(activity,LinearLayoutManager.VERTICAL,false)
listV?.adapter = adapter val url = URL(RSS_FEED_LINK)
RssFeedFetcher(this).execute(url) } fun updateRV(rssItemsL: List<RssItem>) {
if (rssItemsL != null && !rssItemsL.isEmpty()) {
rssItems.addAll(rssItemsL)
adapter?.notifyDataSetChanged()
}
}
class RssFeedFetcher(val context: RSSFragment) : AsyncTask<URL, Void, List<RssItem>>() {
val reference = WeakReference(context)
private var stream: InputStream? = null;
override fun doInBackground(vararg params: URL?): List<RssItem>? {
val connect = params[0]?.openConnection() as HttpURLConnection
connect.readTimeout = 8000
connect.connectTimeout = 8000
connect.requestMethod = "GET"
connect.connect(); val responseCode: Int = connect.responseCode;
var rssItems: List<RssItem>? = null
if (responseCode == 200) {
stream = connect.inputStream;
try {
val parser = RssParser()
rssItems = parser.parse(stream!!) } catch (e: IOException) {
e.printStackTrace()
}
} return rssItems } override fun onPostExecute(result: List<RssItem>?) {
super.onPostExecute(result)
if (result != null && !result.isEmpty()) {
reference.get()?.updateRV(result)
} } } interface OnListFragmentInteractionListener {
// TODO: Update argument type and name
fun onListFragmentInteraction(item: RssItem?)
}}

Once you scan the above code, you will find it’s very simple. No complex task is going on, but yet few lines may increase your thrust to know more. 🙂

扫描了上面的代码后,您会发现它非常简单。 没有复杂的任务在进行,但是几行代码可能会增加您了解更多内容的动力。 🙂

In our onActivityCreated method, we are calling an AsyncTask to bring the RSS feed data from the network so that UI Thread remains free for doing some cool things like showing animations. More specifically, below is the asynctask class.

在我们的onActivityCreated方法中,我们正在调用AsyncTask来从网络中获取RSS feed数据,以便UI Thread保持自由,可以进行一些很酷的事情,例如显示动画。 更具体地说,下面是asynctask类。

Nothing complex here, we are just making a network request for getting input stream from the given URL. Please ensure you have given proper permissions in Android Manifest.xml to access the internet.

这里没有什么复杂的,我们只是发出网络请求以从给定的URL获取输入流。 请确保您已在Android Manifest.xml中授予适当的访问互联网的权限。

class RssFeedFetcher(val context: RSSFragment) : AsyncTask<URL, Void, List<RssItem>>() {
val reference = WeakReference(context)
private var stream: InputStream? = null;
override fun doInBackground(vararg params: URL?): List<RssItem>? {
val connect = params[0]?.openConnection() as HttpURLConnection
connect.readTimeout = 8000
connect.connectTimeout = 8000
connect.requestMethod = "GET"
connect.connect(); val responseCode: Int = connect.responseCode;
var rssItems: List<RssItem>? = null
if (responseCode == 200) {
stream = connect.inputStream;
try {
val parser = RssParser()
rssItems = parser.parse(stream!!) } catch (e: IOException) {
e.printStackTrace()
}
} return rssItems } override fun onPostExecute(result: List<RssItem>?) {
super.onPostExecute(result)
if (result != null && !result.isEmpty()) {
reference.get()?.updateRV(result)
} } }

In the above code, we get an inputstream from a server on hitting the given RSS link. To make the code easy to understand we are not ignoring network error conditions here.

在上面的代码中,我们在点击给定的RSS链接时从服务器获得了输入流。 为了使代码易于理解,我们在这里不忽略网络错误情况。

Once we get inputstream we pass it to our parser class

一旦获得输入流,就将其传递给解析器类

/*
* Copyright (c) 2020. Relsell Global
*/package com.relsellglobal.kotlinrssreadingimport org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import org.xmlpull.v1.XmlPullParserFactory
import java.io.IOException
import java.io.InputStream
class RssParser {
private val rssItems = ArrayList<RssItem>()
private var rssItem : RssItem ?= null
private var text: String? = null fun parse(inputStream: InputStream):List<RssItem> {
try {
val factory = XmlPullParserFactory.newInstance()
factory.isNamespaceAware = true
val parser = factory.newPullParser()
parser.setInput(inputStream, null)
var eventType = parser.eventType
var foundItem = false
while (eventType != XmlPullParser.END_DOCUMENT) {
val tagname = parser.name
when (eventType) {
XmlPullParser.START_TAG -> if (tagname.equals("item", ignoreCase = true)) {
// create a new instance of employee
foundItem = true
rssItem = RssItem()
}
XmlPullParser.TEXT -> text = parser.text
XmlPullParser.END_TAG -> if (tagname.equals("item", ignoreCase = true)) {
// add employee object to list
rssItem?.let { rssItems.add(it) }
foundItem = false
} else if ( foundItem && tagname.equals("title", ignoreCase = true)) {
rssItem!!.title = text.toString()
} else if (foundItem && tagname.equals("link", ignoreCase = true)) {
rssItem!!.link = text.toString()
} else if (foundItem && tagname.equals("pubDate", ignoreCase = true)) {
rssItem!!.pubDate = text.toString()
} else if (foundItem && tagname.equals("category", ignoreCase = true)) {
rssItem!!.category = text.toString()
} else if (foundItem && tagname.equals("description", ignoreCase = true)) {
rssItem!!.description = text.toString()
}
}
eventType = parser.next()
} } catch (e: XmlPullParserException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
return rssItems
}
}

Our RSS Parser is based on XMLPullparser in android. To know more about XMLPullparser

我们的RSS解析器基于android中的XMLPullparser。 进一步了解XMLPullparser

So now RSSParser call will parse inputstream and stuff all the items in an ArrayList. If we put focus on the parse method we will see, XMLPullparser raised events for the start and end XML tags present in RSS feed.

因此,现在RSSParser调用将解析输入流并将所有项目填充到ArrayList中。 如果我们将重点放在解析方法上,我们将看到,XMLPullparser引发了RSS提要中存在的开始和结束XML标签的事件。

while (eventType != XmlPullParser.END_DOCUMENT) {
val tagname = parser.name
when (eventType) {
XmlPullParser.START_TAG -> if (tagname.equals("item", ignoreCase = true)) {
// create a new instance of employee
foundItem = true
rssItem = RssItem()
}
XmlPullParser.TEXT -> text = parser.text
XmlPullParser.END_TAG -> if (tagname.equals("item", ignoreCase = true)) {
// add employee object to list
rssItem?.let { rssItems.add(it) }
foundItem = false
} else if ( foundItem && tagname.equals("title", ignoreCase = true)) {
rssItem!!.title = text.toString()
} else if (foundItem && tagname.equals("link", ignoreCase = true)) {
rssItem!!.link = text.toString()
} else if (foundItem && tagname.equals("pubDate", ignoreCase = true)) {
rssItem!!.pubDate = text.toString()
} else if (foundItem && tagname.equals("category", ignoreCase = true)) {
rssItem!!.category = text.toString()
} else if (foundItem && tagname.equals("description", ignoreCase = true)) {
rssItem!!.description = text.toString()
}
}
eventType = parser.next()
}

At last here are the Gradle files that show different dependencies used in our application. below is root level Gradle file

最后,这是Gradle文件,显示了我们的应用程序中使用的不同依赖项。 以下是根级别的Gradle文件

// Top-level build file where you can add configuration options common to all sub-projects/modules.buildscript {
ext.kotlin_version = '1.3.61'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}allprojects {
repositories {
google()
jcenter()
}
}task clean(type: Delete) {
delete rootProject.buildDir
}

app-level Gradle file

应用程序级Gradle文件

apply plugin: 'com.android.application'apply plugin: 'kotlin-android'apply plugin: 'kotlin-android-extensions'apply plugin: 'kotlin-kapt'android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.relsellglobal.kotlinrssreading"
minSdkVersion 22
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' // gson
implementation 'com.google.code.gson:gson:2.8.6' //cardview
implementation 'androidx.cardview:cardview:1.0.0' // recyclerview
implementation "androidx.recyclerview:recyclerview:1.1.0" // glide
implementation 'com.github.bumptech.glide:glide:4.9.0'
kapt 'com.github.bumptech.glide:compiler:4.9.0' // parsing html
implementation 'org.jsoup:jsoup:1.11.2'
}

Code improvement using MVVM would be explained in another blog. Soon I will update the link here.

使用MVVM进行代码改进将在另一个博客中进行说明。 很快我将在这里更新链接。

Thanks for reading RSS Reading in Kotlin blog.

感谢您在Kotlin博客中阅读RSS阅读。

The post originally published at Link.

该帖子最初发表在Link上

Happy Coding.

编码愉快。

翻译自: https://medium.com/swlh/rss-reading-in-kotlin-easy-android-programming-bebefd12f65d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值