Kotlin编程开发Android运用程序(Volley+Gson依赖库)

Posted 新根

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin编程开发Android运用程序(Volley+Gson依赖库)相关的知识,希望对你有一定的参考价值。

Kotlin编程开发Android运用程序的相关介绍


image

在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

资源参考:

以上是关于Kotlin编程开发Android运用程序(Volley+Gson依赖库)的主要内容,如果未能解决你的问题,请参考以下文章

荐书 | Kotlin开发快速入门与实战

Kotlin 编程语言成为其 Android 应用程序开发人员的首选语言

Kotlin-First !谷歌正式宣布 Kotlin 成为 Android 开发首选编程语言!

Java vs Kotlin 应该使用Kotlin进行Android开发吗

在Android上运用Anko和Kotlin开发数据库:SQLite从来不是一件轻松的事(KAD25)

安卓app主要用啥编程语言的