android java项目到kotlin的转换

来源:互联网 发布:project是什么软件 编辑:程序博客网 时间:2024/05/20 14:22

最近公司一位安卓同时离职,我做为一个闲余人员自然接手了他的项目,这里我们且把这个项目叫做项目 B。项目 B 四月份开始,本来之前我打算独立完成这个项目,但是公司上面安排了一个团队来做,后面因为该团队能力比较薄弱,领导推掉这个团队后,由招了4个人,其中有一位大牛,也许是一些磨合上的问题,一位安卓同事于两周前辞职,接着自然我接手了这个项目。
本来以前就准备开始用 kotlin 做这个项目,来来回回过了半年这个项目也算终于落到了我的手上,文档什么的根本不存在,大牛表示用 kotlin 重构一下这个项目,我也正有此愿,在看过一周项目后,也算正式开始了。
其实本以为 kotlin 转换起来很简单,结果在实际转换中还是遇到了一些问题,也算是由于对于一些语法的不熟悉导致的把,下面也算是记录一周已来自己遇到的一些小坑,方便以后查阅,如果你也遇到了这些问题也算能有所帮助。

1 .首先自然是基本类型转换的问题

java中声明一个float 类型的变量并初始化值为0时是没有问题的,代码如下:

float translationY = 0;

转换到 kotlin 中:

var translationY: Float = 0  //错误

这样是不行的,这与 kotlin 的基本类型设置有关
我们可以这样声明:

var translationY = 0.toFloat() //正确

这个声明表示的是定义一个叫 translationY 的变量,这个变量的值为一个 0向float类型转换,当然 直接写成 0f 也可以.

2. 空安全的问题
在 java 中,我们可以声明一个变量,但不对它进行初始化,如:

private EditText editText; 

而在 kotlin 中,我们不能声明一个空变量

private  var editText: EditText //报错

我们需要对它进行一次初始化设置,如加上 lateinit 修饰符:

private lateinit var editText: EditText

这代表之后我们会对这个 edittext 进行初始化,当如你还可以这样声明:

private  var editText: EditText? =null 

这意味这你在以后的使用中都需要对这个editText进行判断如:

editText?.textSize = 0f

两种声明各有使用的地方,根据自己的需求来定。

3.位运算符加上类型转化

java中的几种位运算符在 kotlin 中都有了自己方法,但是这些方法对应的是 int 与 long 类型,我们且看下面这个示例:

在 java 中一段代码如下:

    private static final char[] HEX_DIGITS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};private static String toHexString(byte[] b) {        StringBuilder sb = new StringBuilder(b.length * 2);        for(int i = 0; i < b.length; ++i) {            sb.append(HEX_DIGITS[(b[i] & 240) >>> 4]);            sb.append(HEX_DIGITS[b[i] & 15]);        }        return sb.toString();    }

复制以上代码放入 kt 文件中,自动转化如下:

     private val HEX_DIGITS = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')        private fun toHexString(b: ByteArray): String {            val sb = StringBuilder(b.size * 2)            for (i in b.indices) {                sb.append(HEX_DIGITS[(b[i] and 240).ushr(4)]) //报错                sb.append(HEX_DIGITS[b[i] and 15]) //报错            }            return sb.toString()        }

表面来看是这个方法不能执行 ushr 方法 内部来看也有一些错误,实际上这都是一些类型转化的错误,修正后代码如下:

    private fun toHexString(b: ByteArray): String {            val sb = StringBuilder(b.size * 2)            for (i in b.indices) {                sb.append(HEX_DIGITS[(b[i] and 240.toByte()).toInt().ushr(4)])                sb.append(HEX_DIGITS[(b[i] and 15).toInt()])            }            return sb.toString()        }

这是因为 Java 语言提供了7个位操作运算符。这些运算符用于整型操作数,这些整数操作数包括long,int,short,char和byte,而 kotlin 的 char 并不直接支持位运算符

4.二维数组声明问题

让我们看看这个问题
在 java 中我们定义了这样一个类:

    public static class CellState {        int row;        int col;        float radius;        float translationY = 0;        float alpha = 1f;        public float lineEndX = Float.MIN_VALUE;        public float lineEndY = Float.MIN_VALUE;        public ValueAnimator lineAnimator;    }

我需要一个如下的数组,并对数组内的值进行一次初始化:

    private final CellState[][] mCellStates;    mCellStates = new CellState[3][3];        for (int i = 0; i < 3; i++) {            for (int j = 0; j < 3; j++) {                mCellStates[i][j] = new CellState();                mCellStates[i][j].radius = mDotSize / 2;                mCellStates[i][j].row = i;                mCellStates[i][j].col = j;            }        }

在 kotlin 中 直接转化不成功 手动转化如下:

        cellStates = Array(3) { Array(3) { CellState() } }        for (i in 0..2) {            for (j in 0..2) {                cellStates[i][j] = CellState()                cellStates[i][j].radius = (mDotSize / 2).toFloat()                cellStates[i][j].row = i                cellStates[i][j].col = j            }        }

这个数组初始化也是比较麻烦,因为 kotlin 的非空特性,需要在Array中做一个初始化的操作。

5.实体类继承问题

在网络请求中,我们通常会规定若干个同意的参数方便对请求结果作出一定的统一处理,在java中表示如下:

public class BaseResponse {    public String result;//结果    public String statusCode;//状态码    public String msg;//返回说明}

继承类如下:

public class ChuFangResponse extends BaseResponse {    public List<Data> data;    public String totalPage;    public static class Data {        public String v_content;      }}

在kotlin中有着一些改变:
被继承类

open class BaseRespone(var result: Int = 0,                       var statusCode: String = "",                       var msg: String = "")

继承类

data class UpdateInfo(var data: Data?) :BaseRespone() {    data class Data(var v_content: String                  )     }}

使用的数据类以data 开头,并且在基类中我们赋予了一些默认值方便重载

6.文件上传问题

在业务中我们有时需要上传一些图片啥的
java中表示如下:

 Observable<HttpResult<Doctor>> modifyHeadPortrait(@PartMap Map<String, RequestBody> params);

转换为kotlin后:

 fun modifyHeadPortrait(@PartMap params: Map<String, RequestBody>): Observable<Doctor>

此时使用会报错:

java.lang.IllegalArgumentException: Parameter type must not include a type variable or wildcard: java.util.Map<java.lang.String, ? extends okhttp3.RequestBody> (parameter #1)

这个是kotlin和java在 集合类型上的差异造成的

具体如下:https://github.com/square/retrofit/issues/1805

修正后:

fun modifyHeadPortrait(@Query( @PartMap params: MutableMap<String,RequestBody>): Observable<Doctor>

7.使用parcelable报错
用到parcelable来进行传值

  public static final Creator<CustReceiveMessage> CREATOR = new Creator<CustReceiveMessage>() {        @Override        public CustReceiveMessage createFromParcel(Parcel source) {            return new CustReceiveMessage(source);        }        @Override        public CustReceiveMessage[] newArray(int size) {            return new CustReceiveMessage[size];        }    };

转换为kotlin后:

 companion object {      val CREATOR: Parcelable.Creator<CustReceiveMessage> = object : Parcelable.Creator<CustReceiveMessage> {            override fun createFromParcel(source: Parcel): CustReceiveMessage {                return CustReceiveMessage(source)            }            override fun newArray(size: Int): Array<CustReceiveMessage?> {                return arrayOfNulls(size)            }        }    }

此时使用会报错:

BadParcelableException: Parcelable protocol requires a Parcelable.Creator...

修正后:

fun modifyHeadPortrait(@Query( @PartMap params: MutableMap<String,RequestBody>): Observable<Doctor>

接下来这篇文章会随着我的项目转化所遇到的问题逐渐更新,希望能对大家有所帮助