关山初度尘未洗,策马扬鞭再奋蹄!这篇文章主要讲述Kotlin编程开发Android运用程序(Volley+Gson依赖库)相关的知识,希望能为你提供帮助。
Kotlin编程开发Android运用程序的相关介绍:
- Kotlin编程之AndroidStudio( 包括3.0与2.x版本) 配置与使用
- Kotlin编程开发Android运用程序( Volley+ Gson依赖库)
- Kotlin编程之Kotlin Android Extensions( 扩展插件)
- Kotlin编程之Glide v4 Generated API(Unresolved reference GlideApp)
- Kotlin Android Extensions+ Android MVP项目(RxJava+ Rerotfit+ OkHttp+ Glide)
- Anko Layout+ MVP(Glide,Retrofit,OkHttp,RxJava)开发Android运用程序
文章图片
在2017年Google IO大会中, 宣布Kotlin 作为官方语言。跟着党走总没错的想法, 开始满怀激情的开始Kotlin之旅。
历经一个下午的探索Kotlin编程后。昨晚按耐不住激动心情, 边摸石头边过河的方式, 花了一个晚上时间, 撸了本项目代码。过完一段时间的后, Kotlin理解提高了, 再回头看下本项目, 肯定是左右嫌弃的, 但是这毕竟是本人的第一个Kotlin项目。
1. AndroidStudio支持Kotlin的配置:
若是使用的androidStudio3.0以下, 是默认不支持Kotlin语言的, 需要自行配置。
Androistudio 3.0以上是自带支持Kotlin。
具体配置与使用, 可以参考上篇讲解的文章, Kotlin编程之AndroidStudio( 包括3.0与2.x版本) 配置与使用。
2. 在Gralde中添加依赖库:
注意点: 这里展示的项目已经支持Kotlin编写, 在Project的Gralde 和Moudle的Gralde已经有Kotlin配置。
dependencies {
compile fileTree(include: ['
*.jar'
], dir: '
libs'
)
androidTestCompile('
com.android.support.test.espresso:espresso-core:2.2.2'
, {
exclude group: '
com.android.support'
, module: '
support-annotations'
})
compile '
com.android.support:appcompat-v7:25.3.1'
compile '
com.android.support.constraint:constraint-layout:1.0.2'
compile '
com.android.support:recyclerview-v7:25.3.1'
testCompile '
junit:junit:4.12'
compile "
org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
//官方框架
compile '
com.android.volley:volley:1.0.0'
compile '
com.google.code.gson:gson:2.8.0'
}
3. 根据需求开始用Kotlin编写:
使用AndroidStudio怎么创建Kotlin文件或者项目, 请阅读 Kotlin编程之AndroidStudio使用。
项目需求:
- 在豆豌API中搜索导演的电影
- 在里列表中加载电影
- Kotlin语言编写
- Volley+ Gson官方框架异步加载和解析
- RecyclerView中显示电影
1. 编写Volley的单例操作类:
object
关键字声明单例类
lateinit
关键字声明声明一个非空变量, 好处不需要设置初始值。
lazy()
延迟属性, 同步的产生一个单个对象。
Val
关键字声明一个只读对象,Var
关键字声明一个可写对象。
- 注意点:
创建对象不需要使用java中
new
关键字。
/***
*object 用于单例模式
*
*object声明对象名后,
通过对象名来访问,
但是不能使用 =
右边赋值。
*
*/
objectVolleySingletion{
/**
* lateinit 声明一个非空变量,
且不需要设置初始值。
*/
private lateinitvar context:Context/**
*这里使用 延迟属性(
lazy properties)
:
首次访问时计算结果,
以后再次访问时候,
将拷贝第一次记录的结果。
*
*
*使用形式:
var p: String by lazy {}
*
*lazy()返回一个lazy<
T>
的 T 对象.
*
*注意点:
lazy属性的计算结果的过程是同步锁的(
synchronized)
。
*
*作用:
单例对象
*/
valrequestQueque :RequestQueue by lazy {
Volley.newRequestQueue(context)
}valimageLoader :ImageLoader by lazy {
// 不需要调用new关键字才创建对象
ImageLoader(requestQueque,LruBtimapCache() )
}funinitConfi(context:Context){
this.context =
context.applicationContext
}}
2. 编写ImageLoader需要用到的LruCache:
- 一个类继承父类和实现接口的方式 :
class 类名 :超类名( ) ,接口名
- LruBitmapCache主构造函数中,
指定参数类型为Int,同时也指定一个默认值。
- LruBitmapCache带有主构造函数,
因此超类(
这里是LruCache)
必须在主构造函数中初始化。
Companion
关键字, 修饰伴生对象。伴生对象类名, 可以省略
/***
*LruBitmapCache主构造函数中,
指定一个默认值。
*
*LruBitmapCache带有主构造函数,
因此超类(
这里是LruCache)
必须在主构造函数中初始化。
*
*/
class LruBtimapCache (size: Int=
defaultSize ): LruCache<
String,Bitmap>
(size) ,ImageLoader.ImageCache{override fun getBitmap(url: String): Bitmap ?{
return get(url)
}
override fun putBitmap(url: String?, bitmap: Bitmap?) {
put(url,bitmap)
}
override fun sizeOf(key: String, value: Bitmap): Int {
returnvalue.rowBytes*value.height/1024
}
/**
* 使用Companion关键字,
伴生对象类名,
可以省略。
*/
companion object{
/**
*val声明一个只读的变量
*
*/
valdefaultSize: Int get() {
val maxMemory =
(Runtime.getRuntime().maxMemory() / 1024).toInt()
val cacheSize =
maxMemory / 8
return cacheSize
}
}
}
3. 编写自定义的Application:
override
关键字用于复写超类或者接口中存在的方法
class BaseApplication :Application(){
override fun onCreate() {
super.onCreate()
//初始化Volley配置
VolleySingletion.initConfi(this)
}
}
在AndroidManifest.xml中配置:
<
manifest xmlns:android=
"
http://schemas.android.com/apk/res/android"
package=
"
com.xingen.kotlindemo"
>
//联网权限
<
uses-permission android:name=
"
android.permission.INTERNET"
/>
<
application
android:allowBackup=
"
true"
android:icon=
"
@
mipmap/ic_launcher"
android:label=
"
@
string/app_name"
android:roundIcon=
"
@
mipmap/ic_launcher_round"
android:supportsRtl=
"
true"
android:name=
"
.BaseApplication"
//使用自定义的Application
android:theme=
"
@
style/AppTheme"
>
<
activity android:name=
"
.MainActivity"
>
<
intent-filter>
<
action android:name=
"
android.intent.action.MAIN"
/>
<
category android:name=
"
android.intent.category.LAUNCHER"
/>
<
/intent-filter>
<
/activity>
<
/application>
<
/manifest>
4. 编写实体类
这里也存在一个点疑问:
data
关键字修饰数据对象,
但是必须带有主构造器函数。 因此, 这里并未使用data修饰数据对象。
- 类型后面带有
?
是允许该对象为空
//https://api.douban.com/v2/movie/search?q=
张艺谋,
返回的数据结构。
class MovieList {lateinit var subjects: List<
Movie>
class Movie {
lateinit var year: String
var title: String? =
null
var id: String? =
null
lateinitvar images: Imagesclass Images {
var small: String?=
nullvar large: String? =
null
}
}
}
5. 编写RecyclerView的Adapter:
this
引用是最内层的对象, 若是引用外层对象, 需要使用this@ 类名
- 除开下文的初始化全局变量方式外,
还可以在主构造函数中声明类型的方式
class ImageListAdapter(movieList: List<
MovieList.Movie>
) : RecyclerView.Adapter<
ImageListAdapter.ViewHolder>
() {
/**
* 指定一个全局的变量,
从主构造函数中获取到参数,
进行初始化
*/
var list =
movieList/**
* 加载的数量
*/
override fun getItemCount(): Int {
return list.size
}/**
* 创建 ViewHolder
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {var rootView =
View.inflate(parent.context, R.layout.item_imagelist_layout, null)return ViewHolder(rootView)
}/**
*绑定ViewHolder,进行加载数据
*/
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.loadImage(position)
}
/**
*inner修饰内部类
*/
inner class ViewHolder(var rootView: View) : RecyclerView.ViewHolder(rootView) {/**
* 构建一个加载数据的方法,
参数为RecyclerView中的当前的位置
*/
fun loadImage(position: Int) {
var iv =
rootView.findViewById(R.id.imagelist_iv) as NetworkImageView
var title =
rootView.findViewById(R.id.imagelist_title) as TextView/**
*this@
类名的方式,
拿到需要对应类的this指向。
*/
varadapter=
this@
ImageListAdapter
/**
*NetWorkImageView开始加载图片
*/
iv.setDefaultImageResId(R.mipmap.ic_launcher)
iv.setErrorImageResId(R.mipmap.ic_launcher)
iv.setImageUrl(adapter.list[position].images.large,VolleySingletion.imageLoader)title.text=
adapter.list[position].title
}
}
}
6. 编写MainActivity, 进行发送请求和更新数据:
/**
*一个类继承父类和实现接口的方式;
class 类名 :超类名(
)
,接口名
*/
class MainActivity : AppCompatActivity() {
/**
* override用于覆写继承父类或者实现接口中方法。
*
* fun 用于标识方法
*
* 参数形式:
参数名:
类型
*
*? 是用于指定可以为空对象
*
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)shwoDiaglog()
this.initView()
this.sendRequest()}lateinit var recyclerView: RecyclerView
/**
* 初始化控件
*/
fun initView() {
recyclerView =
this.findViewById(R.id.main_recycler_view) as RecyclerView
}/**
*将网络数据加载到RecyclerView
*/
fun loadData(movieList: List<
MovieList.Movie>
) {
recyclerView.layoutManager =
LinearLayoutManager(this)
recyclerView.adapter =
ImageListAdapter(movieList)
}lateinit var progressDialog: ProgressDialog
/**
* 显示dialog
*/
fun shwoDiaglog() {
progressDialog =
ProgressDialog(this)
progressDialog.show()
}/**
* 取消dialog
*/
fun cancleDialog() {
progressDialog.dismiss()
}/**
* Toast显示
*/fun loadToast(content: String?) {
Toast.makeText(this, content, Toast.LENGTH_SHORT).show()
}/**
* 发送请求,这里使用douban公开的搜索电影的API
*/
fun sendRequest() {
var url =
"
https://api.douban.com/v2/movie/search?q=
张艺谋"
val request =
StringRequest(url, Response.Listener<
String>
{
response ->
//请求成功,
Gson解析json
var movilist =
Gson().fromJson(response, MovieList::class.java)
loadData(movilist.subjects)
cancleDialog()}, Response.ErrorListener {
error ->
loadToast(error.message)
cancleDialog()
})
// 单利类中对象的引用
VolleySingletion.requestQueque.add(request)
}
}
activity_main.xml代码如下:
<
android.support.constraint.ConstraintLayout xmlns:android=
"
http://schemas.android.com/apk/res/android"
xmlns:app=
"
http://schemas.android.com/apk/res-auto"
xmlns:tools=
"
http://schemas.android.com/tools"
android:layout_width=
"
match_parent"
android:layout_height=
"
match_parent"
tools:context=
"
com.xingen.kotlindemo.MainActivity"
>
<
android.support.v7.widget.RecyclerView
android:id=
"
@
+
id/main_recycler_view"
android:layout_width=
"
match_parent"
android:layout_height=
"
match_parent"
>
<
/android.support.v7.widget.RecyclerView>
<
/android.support.constraint.ConstraintLayout>
item_imagelist_layout.xml代码如下:
<
LinearLayout xmlns:android=
"
http://schemas.android.com/apk/res/android"
android:orientation=
"
horizontal"
android:layout_width=
"
match_parent"
android:layout_height=
"
wrap_content"
android:padding=
"
10dp"
>
<
com.android.volley.toolbox.NetworkImageView
android:layout_width=
"
100dp"
android:layout_height=
"
100dp"
android:scaleType=
"
centerCrop"
android:id=
"
@
+
id/imagelist_iv"
/>
<
TextView
android:layout_width=
"
wrap_content"
android:id=
"
@
+
id/imagelist_title"
android:layout_gravity=
"
center_vertical"
android:layout_marginLeft=
"
20dp"
android:layout_height=
"
wrap_content"
/>
<
/LinearLayout>
项目的最终目录结构, 如下:
文章图片
项目运行结果:
文章图片
项目代码: https://github.com/13767004362/KotlinVolleyDemo 资源参考:
- AndroidStudio的配置:
http://blog.csdn.net/hexingen/article/details/72621795
- Kotlin中英文比对的官网:
https://www.kotlincn.net/
- Kotlin中文:
https://huanglizhuo.gitbooks.io/kotlin-in-chinese/content/
- Kotlin中文翻译组:
https://github.com/huanglizhuo/kotlin-in-chinese
推荐阅读
- Win8.1系统网卡驱动更新失败后的处理办法
- android入门 — 多线程
- Android sdk 安装(ionic)
- GJM : 发布APK 到 Google Play(Android Market)官方市场
- Androidbuttonshape形状资源码实现
- android 搜索自动匹配关键字并且标红
- Android 如何保持屏幕常亮
- 优雅的App全然退出方案(没有不论什么内存泄漏隐患)
- install ubuntu on Android mobile phone