# First acquaintance with Kotlin, the new Android language

At THE IO Conference in May 2017,Google announced that Kotlin would become a tier 1 programming language for Developing Android.

Not only can Kotlin run on the JVM, it can also directly convert Kotlin source code into JavaScript. In theory, Kotlin can run in any environment that supports JavaScript, such as WEB applications,reactNatice(Android and IOS), and wechat official accounts In addition, there are some places that JavaScript cannot do, such as developing local applications, but Kotlin can do it. Kotlin can not only generate JavaScript code, but also directly compile local code, such as Windows exe files,iOS As a result, Kotlin can develop almost any kind of APP.


## Kotlin’s advantages:

  • Easy to learn

    Kotlin is a face object programming language with many functional programming ideas

  • lightweight

    Compared to other programming languages, Kotlin has a smaller library of functions, less than 7,000

  • High interoperability:

    Kotlin interoperates with other Java class libraries in a friendly and simple way

  • Inherit Androidstudio and gradle

    Specialized plug-ins, and tools

  • Other syntactic level features, such as data model classes, null type safety, extension functions, etc

What can Kotlin do

  • Server-side development

    Kotlin is a JVM-based programming language, so naturally you can use all jVM-based server-side frameworks such as Spring

  • Run in JavaScript

    Kotlin provides the ability to generate JavaScript source code

  • To develop an Android App

    Kotlin and Java source code can be in the same project and can be debugged jointly

Basic syntax for ## Kotlin

  • Define variables

    Var m: Int? Var n = 10 var f = 30 var arr1 = arrayOf(1, 2, 3, 4) var arr3: IntArray? Var list1 = arrayListOf<String>() var list2: ArrayList<String>? = null // Define string var s1 ="Hello \nworld"
    var s2: String = "Hello world \n"
    var s3 = """ hello world I love you. """
    Copy the code
  • Define methods

    // Define the normal method funtest() {} // define fun with a return valuetest1(): String {
        return "Return value"
    }
    Copy the code
  • The get and set methods

    var address: String = ""
        get() {
            println("get Method is run")
            return if (field.contains("Beijing")) {
                field.replace("Beijing"."Xuchang")}else {
                field
            }
    
        }
        set(value) {
            println("setMethod is run")
            field = value
        }
    
    Copy the code
  • Define constructor

    // The first-class constructor class KotlinBeanconstructor() {} // Secondary constructor class KotlinBeanconstructor() {
        constructor(index: Int) : this()
    }
    Copy the code
  • Numeric types

The data type Occupied bytes
Double 8
Float 4
Long 8
Int 4
Short 2
Byte 1
  • String template

    $override fun toString(): String {return "KotlinBean(m=$m, n=$n, f=$f, arr1=${Arrays.toString(arr1)}, arr3=${Arrays.toString(arr3)}, list1=$list1, list2=$list2)"
        }
    
    Copy the code
  • If statement

    // Define method fun with return valuetest1(): String {
        return if (n > 10) {
            "ssss"
        } else {
            "Return value"}}Copy the code
  • When statement (instead of switch statement)

      rg_navigation.setOnCheckedChangeListener { group, checkedId ->
            when (checkedId) {
                R.id.rb_home -> {
                    switchTab(0)
                }
                R.id.rb_mirror -> {
                    switchTab(1)
                }
                R.id.rb_bbs -> {
                    switchTab(2)
                }
                R.id.rb_mine -> {
                    switchTab(3)
                }
    
            }
        }
        
           fun test2(n: Int) {when (n) {1 -> {} 2 -> {} // useinThe keywordin3.. 5 -> {} // Use the return value of the function expressiontest(3) - > {}else-> {}}}Copy the code
  • The for loop

    fun test4() {// strong loop, directly through list1.forEach {t: String? -> println(t) }for (s: String inList1) {println(s)for (i inList1.indices (list1[I]) {println(list1[I])for ((index, value) in list1.withIndex()) {
            println(index)
            println(value)
        }
    }
    Copy the code
  • The modifier

    1. Private is only accessible inside a class
    2. Protected is similar to private, but is also accessible in subclasses
    3. Internal Is accessible by any class inside a module
    4. Public Any class can be accessed
  • Class inheritance

    Unlike Java,kotlin class inheritance requires a colon (:) followed by a call to the parent class’s constructor

    Note that kotlin default class is final, that is, the default class does not allow inheritance, the need to display class inheritance using the open keyword

    open class KotlinBean constructor() {
    
    constructor(index: Int) : this()
    
    }
    
    Copy the code
  • Override methods & override properties

    In Kotlin, not only are classes non-inheritable by default, but methods are also non-overridden by default. Therefore, if you want to override a method in a subclass, you need to add the open keyword in front of the corresponding method in the parent class, and the Override keyword in front of the method overridden by the subclass

  • interface

    Interfaces in Kotlin are similar to those in Java, declared using the interface keyword. A class can implement multiple interfaces, and the properties and methods in the interfaces are open

    Interface KotlinInterfaceTest {fun getUserInfo() // In Kotlin, methods that allow interfaces contain the default method body funsetUserInfo(name: String) {
        val userBean = UserBean()
        userBean.name = name
    }
    Copy the code

}

  • Null value security

    Java is plagued by null exceptions, and Kotlin attempts to solve this problem

    Kotlin causes the NPE condition

    1. Explicitly calling throw NullPointerException()
    2. Use!!!!! The operator
    3. External Java code causes
    4. Some data is inconsistent during initialization. Procedure
  • Started using Kotlin for Android development

    1. Creating an application

      Check the Kotlin option and click Next until the project is created

    1. Writing an XML file

    1. Set up the UI display in the activity

  • Other examples

    class HomeFragment @SuppressLint("ValidFragment")
    private constructor() : Fragment() {
        var value: HomeFragment? = null
        var imageList = arrayListOf<Int>()
        lateinit var mContext: Context
        lateinit var mHomeAdapter: HomeAdapter
    
        private object Holder {
            val INSTANCE = HomeFragment()
        }
    
        companion object Factory {
            fun getInstance(): HomeFragment {
                returnHolder.INSTANCE } } override fun onAttach(context: Context?) { super.onAttach(context) mContext = context!! } override fun onCreateView(inflater: LayoutInflater? , container: ViewGroup? , savedInstanceState: Bundle?) : View? {returninflater!! .inflate(R.layout.fragment_home, container,false) } override fun onViewCreated(view: View? , savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initView() initData() } private funinitView() {
            banner.setImageLoader(GlideImageLoader())
            imageList.add(R.mipmap.ic_driver)
            imageList.add(R.mipmap.ic_police)
            imageList.add(R.mipmap.ic_trance)
            banner.setImages(imageList).start()
            rv_top_lines.setHasFixedSize(true)
            rv_top_lines.layoutManager = LinearLayoutManager(mContext)
        }
    
        class MyLinear2(context: Context?) : LinearLayoutManager(context) {
            override fun canScrollVertically(): Boolean {
                return false
            }
    
        }
    
        private fun initData() {
            mHomeAdapter = HomeAdapter()
            rv_top_lines.adapter = mHomeAdapter
    
            HttpManager.getInstance().getRetrofit().create(IApiServices::class.java).getHostList()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnNext { t: BaseBean<List<MovieBean>>? ->
                        if(t ! = null) { val data = t.data data.forEach { t -> println(t.toString()) } } }.subscribe(object : Observer<BaseBean<List<MovieBean>>> { override fun onSubscribe(d: Disposable) { println("onSubscribe")
                }
    
                override fun onError(e: Throwable) {
                    println("onError" + e.message)
                    Toast.makeText(mContext, e.message, Toast.LENGTH_SHORT).show()
                }
    
                override fun onNext(t: BaseBean<List<MovieBean>>) {
                    println("onNext" + t.toString())
                    mHomeAdapter.setNewData(t.data)
                }
    
                override fun onComplete() {
                    println("onComplete")
                    Toast.makeText(mContext, "onComplete", Toast.LENGTH_SHORT).show()
    
                }
            })
        }
    
        override fun onStart() {super.onstart () // start banner.startautoplay ()} override funonStop() {super.onstop () // End of the rotation banner.stopAutoplay ()}}Copy the code

  • Home TAB switch
    package com.bidostar.kotlindemo.activity import android.os.Bundle import android.support.v7.app.AppCompatActivity import  com.bidostar.kotlindemo.R import com.bidostar.kotlindemo.fragment.BbsFragment import com.bidostar.kotlindemo.fragment.HomeFragment import com.bidostar.kotlindemo.fragment.MineFragment import com.bidostar.kotlindemo.fragment.MirrorFragment import kotlinx.android.synthetic.main.activity_home.* class HomeActivity :AppCompatActivity() {// 1. Lateinit () {// 2. Lateinit () {// 1. HomeFragment lateinit var mMirrorFragment: MirrorFragment lateinit var mBbsFragment: BbsFragment lateinit var mMineFragment: MineFragment override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)setContentView(R.layout.activity_home)
            initView()
            val transaction = supportFragmentManager.beginTransaction()
            transaction.add(R.id.fl_content, mHomeFragment, "home")
            transaction.add(R.id.fl_content, mMirrorFragment, "mirror")
            transaction.add(R.id.fl_content, mBbsFragment, "bbs")
            transaction.add(R.id.fl_content, mMineFragment, "mine")
            transaction.commitAllowingStateLoss()
    
            rg_navigation.setOnCheckedChangeListener { group, checkedId ->
                when (checkedId) {
                    R.id.rb_home -> {
                        switchTab(0)
                    }
                    R.id.rb_mirror -> {
                        switchTab(1)
                    }
                    R.id.rb_bbs -> {
                        switchTab(2)
                    }
                    R.id.rb_mine -> {
                        switchTab(3)
                    }
    
                }
            }
            switchTab(0)
    
        }
    
        private fun initView() { mHomeFragment = HomeFragment.getInstance() mMirrorFragment = MirrorFragment.getInstance() mBbsFragment = BbsFragment.getInstance() mMineFragment = MineFragment.getInstance() } private fun switchTab(index: Int) { val transaction = supportFragmentManager.beginTransaction() when (index) { 0 -> { transaction.show(mHomeFragment)  .hide(mMirrorFragment) .hide(mBbsFragment) .hide(mMineFragment) .commitAllowingStateLoss() } 1 -> { transaction.show(mMirrorFragment) .hide(mHomeFragment) .hide(mBbsFragment) .hide(mMineFragment) .commitAllowingStateLoss() } 2 -> { transaction.show(mBbsFragment) .hide(mHomeFragment) .hide(mMirrorFragment) .hide(mMineFragment) .commitAllowingStateLoss() } 3 -> { transaction.show(mMineFragment) .hide(mHomeFragment) .hide(mMirrorFragment) .hide(mBbsFragment) .commitAllowingStateLoss() } } } }Copy the code
  • Adapter to use
    package com.bidostar.kotlindemo.adapter import com.bidostar.kotlindemo.R import com.bidostar.kotlindemo.bean.MovieBean import com.bumptech.glide.Glide import com.chad.library.adapter.base.BaseQuickAdapter import com.chad.library.adapter.base.BaseViewHolder /** * @author zsh27 * @date 2017/12/14. * description . * @since 0 */ class  HomeAdapter(layoutResId: Int) : BaseQuickAdapter<MovieBean, BaseViewHolder>(layoutResId) { init { } constructor() : this(R.layout.home_movie_item) override fun convert(helper: BaseViewHolder? , item: MovieBean?) {if(item ! = null) { helper? .setText(R.id.tv_name, item.movieName) helper? .setText(R.id.tv_desc, item.name) Glide.with(mContext) .load(item.img) .into(helper?.getView(R.id.iv_cover)) } } }Copy the code

The project of actual combat

Kotlin&java mix

  1. Project configuration

    Gradle configuration dependencies {classpath'com. Android. Tools. Build: gradle: 3.0.1'
            classpath 'com. Tencent. Bugly: tinker - support: 1.1.1'
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
            classpath 'com. Jakewharton: butterknife - gradle - plugin: 8.4.0'
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"} Module gradle configures the apply plugin:'com.android.application'
    apply plugin: 'kotlin-android'
    apply plugin: 'kotlin-android-extensions'
    apply plugin: 'kotlin-kapt'
    
    dependencies {
        implementation fileTree(include: ['*.jar'], dir: 'libs')
        testImplementation "junit:junit:$rootProject.dependVersion.junit"
        implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
        implementation "com.android.support:design:$rootProject.dependVersion.support"
        implementation "com.android.support.constraint:constraint-layout:$rootProject.dependVersion.constraint_layout"
        }
    
    Copy the code
  2. Constant class

    Object NetConstant {/** * connection timeout */ const val DEFAULT_CONNECT_TIME_OUT = 15L /** * read timeout */ const val */ const val DEFAULT_WRITE_TIME_OUT = 30L}Copy the code
  3. Singleton class

    class HttpManager private constructor() {/** * constructor private */ init {logger.d ()"HttpManager:" + "init:" + "_debug:"+ Debug) initRetrofit()} Companion object {/** * singleton */ var BaseUrl: String? = null var BaseResourceUrl: String? = null var Debug =falsevar InterceptorList: List<Interceptor>? = null var NetworkInterceptorList: List<Interceptor>? = null /** * get HttpManager ** @returnHttpManager instance */ val instance: HttpManagerget() {
                return Holder.INSTANCE
            }
    
        fun paramsBuild(): HttpManager.ParamsBuild {
            returnHttpmanager.paramsbuild ()} /** * custom Retrofit examples * you can set some custom parameters to buildRetrofit instances by buildRetrofit() * Or build a network request interface directly with buildApiService()returnBuild RetrofitBuilder */ fun newBuilder(): httpBuilder.builder {returnHttpBuilder. Builder ()}}} using method 1. Java file using HttpManager.Com panion. GetInstance (). The create (IAppServices. Class) .getDeviceActivateStatus() .compose(RxSchedulers.INSTANCE.<com.bidostar.netlibrary.BaseResponse<DeviceStatusBean>>applyIoSchedulers()) .compose(this.<com.bidostar.netlibrary.BaseResponse<DeviceStatusBean>>bindHttpmanager.instance.create (IAppServices::class.java).deleteDevicepic (mDeviceCode, bean.id.toLong()) .compose(RxSchedulers.applyIoSchedulers()) .compose(this.bindToLifecycle())Copy the code
  4. View controls

    1. findViewById()

          var mTvTitle = findViewById(R.id.tv_title)
          var mIvBack = findViewById(R.id.iv_back)
      
      Copy the code
    2. Kotlin annotation mode

      import kotlinx.android.synthetic.main.activity_mirror_album_detail.* mAdapter = AlbumPagerAdapter(mContext) view_pager.adapter = mAdapter view_pager.addOnPageChangeListener(this) mAdapter!! .setNewData(mItemList) view_pager.currentItem = mIndex mIvBack.setOnClickListener { finish() } tv_delete.setOnClickListener(this) tv_download.setOnClickListener(this)Copy the code
  5. Using the MVP

    M layer Class DeviceCaptureModelImpl: BaseModel(), DeviceCaptureContract.IDeviceCaptureModel { override fun getLastPicture(alarmId: Int, deviceCode: Long, alarmDay: String, pageSize: Int, respType: String): Observable<BaseResponse<List<MirrorAlbumBean>>> {return HttpManager.instance
                    .create(IAppServices::class.java)
                    .getDeviceAlarm(alarmId, deviceCode, alarmDay, pageSize, respType)
                    .compose(RxSchedulers.applyIoSchedulers())
        }
    
        override fun getDeviceStatus(deviceCode: Long, rousing: Boolean): Observable<BaseResponse<Int>> {
            return HttpManager.instance.create(IAppServices::class.java)
                    .deviceStatus(deviceCode, rousing)
                    .compose(RxSchedulers.applyIoSchedulers())
        }
    
        override fun devicecapture(deviceCode: Long): Observable<BaseResponse<CaptureBean>> {
            return HttpManager.instance.create(IAppServices::class.java)
                    .deviceCapture(deviceCode)
                    .compose(RxSchedulers.applyIoSchedulers())
        }
    
        override fun sendMessage(deviceCode: Long, content: String): Observable<BaseResponse<String>> {
            returnHttpManager.instance.create(IAppServices::class.java) .sendTextToDevice(deviceCode, The content). Compose (RxSchedulers applyIoSchedulers ())}} P class DeviceCapturePresenterImpl: BasePresenter<DeviceCaptureContract.IDeviceCaptureView, DeviceCaptureModelImpl>(), DeviceCaptureContract.IDeviceCapturePresenter { override fun getDeviceStatus(deviceCode: Long, rousing: Boolean) { m.getDeviceStatus(deviceCode, rousing) .compose(RxSchedulers.applyIoSchedulers()) .subscribe(object : BaseObserver<Int>() { override fun handleResult(response: BaseResponse<Int>) { when (response.resultCode) { BaseResponse.RET_HTTP_STATUS_OK -> { when (response.data) { BaseResponse.RET_HTTP_STATUS_OK -> { v.onLine() } BaseResponse.RET_MIRROR_STATUS_NO -> { v.offLine() } BaseResponse.RET_MIRROR_STATUS_YES -> { v.onStarting() } } } BaseResponse.RET_TIMEOUT_CODE -> { v.timeOut() }else-> {v.nerror () v.howErrorTip (response.errormsg)}}}})}} V layer @route (path = arouterconstant.device_capture) class DeviceCaptureActivity : BaseMvpActivity<DeviceCapturePresenterImpl>(), DeviceCaptureContract.IDeviceCaptureView, Handler.Callback, DeviceConnectDialog.onMirrorConnectClickListener { private lateinit var mTvTitle: TextView private lateinit var mIvBack: ImageView private var mCar: Car? = null private var mHandler: WeakRefHandler? = null private var mIsCapture =false
        private var mContent = ""
        private var mConnectDialog: DeviceConnectDialog? = null
        override fun newPresenter(): DeviceCapturePresenterImpl {
            returnDeviceCapturePresenterImpl() } override fun getLayoutView(savedInstanceState: Bundle?) : Int {return R.layout.activity_device_capture
        }
    
        override fun initView(savedInstanceState: Bundle?) {
            mIvBack = findViewById(R.id.iv_back)
            mTvTitle = findViewById(R.id.tv_title)
            mIvBack.setOnClickListener {
                finish()
            }
            mTvTitle.text = "Remote rearview mirror control."
            mIvBack.setOnClickListener {
                finish()
            }
            ivCapture.setOnClickListener {
                mIsCapture = true
                if(mCar? .deviceType ! = 1) { DialogUtils.showBindDialog(mContext)return@setOnClickListener
                }
                ivCapture.isClickable = falseshowMirrorConnectDialog() p.getDeviceStatus(mCar!! .deviceCode,true)
            }
            ivAlbum.setOnClickListener {
                if(mCar? .getDeviceType() ! = 1) { DialogUtils.showBindDialog(mContext)return@setOnClickListener
                }
                ARouter.getInstance().build(ARouterConstant.DEVICE_CAPTURE_ALBUM)
                        .navigation()
            }
            tvSendMessage.setOnClickListener {
                mIsCapture = false
                if(mCar!! .deviceType ! = 1) { DialogUtils.showBindDialog(mContext)return@setOnClickListener
                }
                mContent = etMessage.text.toString().trim()
                if (TextUtils.isEmpty(mContent)) {
                    showToast("Message content cannot be empty")
                    return@setOnClickListener
                }
                tvSendMessage.isClickable = falseshowMirrorConnectDialog() p.getDeviceStatus(mCar!! .deviceCode,true)
            }
        }
    
        override fun initData() {
            mCar = ApiCarDb.getCar(mContext)
            mHandler = WeakRefHandler(this)
            if(mCar? .deviceType == 1) { p.getLastPicture(207, mCar!! .deviceCode,"", 1, "list")}}}Copy the code
  6. Java files are converted to kotlin

    Public Class AlbumPagerAdapter extends PagerAdapter {private List<MirrorAlbumItemBean> mDataList; private Context mContext; private final LayoutInflater mInflater; public AlbumPagerAdapter(Context context) { mContext = context; mInflater = LayoutInflater.from(mContext);if (mDataList == null) {
                mDataList = new ArrayList<>();
            }
        }
    
        public void setNewData(List<MirrorAlbumItemBean> list) {
            if (mDataList == null) {
                mDataList = new ArrayList<>();
            }
            mDataList.clear();
            mDataList.addAll(list);
            notifyDataSetChanged();
        }
    
        @Override
        public int getCount() {
            return mDataList.size();
        }
    
        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return object == view;
        }
    
        @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            MirrorAlbumItemBean bean = mDataList.get(position);
            View inflate = mInflater.inflate(R.layout.device_album_viewpager_item_layout, container, false);
            ImageView imageView = inflate.findViewById(R.id.pv_image);
            TextView tvLocation = inflate.findViewById(R.id.tv_location);
    
            TextView tvTime = inflate.findViewById(R.id.tv_time);
            tvLocation.setText(TextUtils.isEmpty(bean.getLocation()) ? "Position position" : bean.getLocation());
            tvTime.setText(bean.getAlarmTime());
    
            Glide.with(mContext)
                    .load(bean.getUrl())
                    .into(imageView);
            container.addView(inflate);
            returninflate; } @Override public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { container.removeView((View) object); }}Copy the code

class AlbumPagerAdapter(private val mContext: Context) : PagerAdapter() { private var mDataList: MutableList<MirrorAlbumItemBean>? = null private val mInflater: LayoutInflater = LayoutInflater.from(mContext) init { if (mDataList == null) { mDataList = ArrayList() } } fun setNewData(list: List<MirrorAlbumItemBean>) { if (mDataList == null) { mDataList = ArrayList() } mDataList!! .clear() mDataList!! .addAll(list) notifyDataSetChanged() } fun removeData(position: Int) { if (mDataList!! .size > position) { mDataList!! .removeAt(position) } notifyDataSetChanged() } override fun getCount(): Int { return mDataList!! .size } override fun isViewFromObject(view: View, `object`: Any): Boolean { return `object` === view } override fun instantiateItem(container: ViewGroup, position: Int): Any { val bean = mDataList!! [position] val inflate = mInflater.inflate(R.layout.device_album_viewpager_item_layout, container, false) val imageView = inflate.findViewById<ImageView>(R.id.pv_image) val tvLocation = inflate.findViewById<TextView>(R.id.tv_location) val tvTime = inflate.findViewById<TextView>(R.id.tv_time) Tvlocation. text = if (textutils.isEmpty (bean.location)) "unknown location" else bean.location tvTime.text = bean.alarmTime Glide.with(mContext) .load(bean.url) .into(imageView) container.addView(inflate) return inflate } override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { container.removeView(`object` as View) } override fun getItemPosition(`object`: Any): Int { return PagerAdapter.POSITION_NONE } }Copy the code
  • Nuggets network address