在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声明对象名后,通过对象名来访问,但是不能使用 = 右边赋值。 * */
object VolleySingletion{
/** * lateinit 声明一个非空变量,且不需要设置初始值。 */
private lateinit var context:Context
/** * 这里使用 延迟属性(lazy properties):首次访问时计算结果,以后再次访问时候,将拷贝第一次记录的结果。 * * * 使用形式: var p: String by lazy { } * * lazy()返回一个lazy<T> 的 T 对象. * * 注意点: lazy属性的计算结果的过程是同步锁的(synchronized)。 * * 作用: 单例对象 */
val requestQueque :RequestQueue by lazy {
Volley.newRequestQueue(context)
}
val imageLoader :ImageLoader by lazy {
// 不需要调用 new 关键字才创建对象
ImageLoader(requestQueque,LruBtimapCache() )
}
fun initConfi(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 {
return value.rowBytes*value.height/1024
}
/** * 使用Companion关键字,伴生对象类名,可以省略。 */
companion object{
/** * val声明一个只读的变量 * */
val defaultSize: 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
lateinit var images: Images
class Images {
var small: String?= null
var 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指向。 */
var adapter=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