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

关山初度尘未洗,策马扬鞭再奋蹄!这篇文章主要讲述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运用程序
Kotlin编程开发Android运用程序(Volley+Gson依赖库)

文章图片

在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中显示电影
【Kotlin编程开发Android运用程序(Volley+Gson依赖库)】根据分析, 开始编写代码:
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>

项目的最终目录结构, 如下:
Kotlin编程开发Android运用程序(Volley+Gson依赖库)

文章图片

项目运行结果:
Kotlin编程开发Android运用程序(Volley+Gson依赖库)

文章图片

项目代码: 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

    推荐阅读