初学Kotlin MVP+Retofit2+Rxjava2

kotlin项目 需要配置 build.gradle
如下:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 26
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "com.xwkotlindemo"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    productFlavors {
        free {
            versionName "1.0-free"
        }
    }
}

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:26.0.0-alpha1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"



    compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'

    //retrofit2+rxjava2 网络请求框架
    compile 'io.reactivex.rxjava2:rxjava:2.0.1'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
    compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'
    compile 'eu.the4thfloor.volley:com.android.volley:2015.05.28'
    compile 'com.google.code.gson:gson:2.8.0'
    compile 'org.litepal.android:core:1.3.2'
    compile 'com.squareup.okhttp3:okhttp:3.4.1'

}

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

buildscript {

    ext.kotlin_version = "1.0.0-rc-1036"

    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

2.上面配置好后可以开始进入主题了,首先创建网络配置如下代码:

object NetConfig {
    val BASEURL = "http://192.168.0.229:8080/HappyTeamService/"
}

3.创建Retofit2+Rxjava2
首先配置Retofit2以及网络拦截
这段代码是java的 因为java和kotlin可以组合使用 使用的是百度上的代码

public class HttpCommonInterceptor implements Interceptor{
    private Map<String,String> mHeaderParamsMap = new HashMap<>();
    Map<String, String> queryParamsMap = new HashMap<>();
    Map<String, String> paramsMap = new HashMap<>();
    Map<String, String> headerParamsMap = new HashMap<>();
    List<String> headerLinesList = new ArrayList<>();
    public HttpCommonInterceptor() {

    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Log.d("HttpCommonInterceptor","add common params");
        Request oldRequest = chain.request();
        // Request request = chain.request();
        Headers.Builder headerBuilder = oldRequest.headers().newBuilder();
        Request.Builder requestBuilder = oldRequest.newBuilder();

        // 添加新的参数,添加到url 中
       /* HttpUrl.Builder authorizedUrlBuilder = oldRequest.url()
                .newBuilder()
                .scheme(oldRequest.url().scheme())
                .host(oldRequest.url().host());*/

        if (headerParamsMap.size() > 0) {
            Iterator iterator = headerParamsMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                headerBuilder.add((String) entry.getKey(), (String) entry.getValue());
            }
        }

        if (headerLinesList.size() > 0) {
            for (String line: headerLinesList) {
                headerBuilder.add(line);
            }
            requestBuilder.headers(headerBuilder.build());
        }

        // 新的请求

        //Request.Builder requestBuilder =  oldRequest.newBuilder();
        requestBuilder.method(oldRequest.method(), oldRequest.body());
        //添加公共参数,添加到header中
        if(mHeaderParamsMap.size() > 0){
            for(Map.Entry<String,String> params:mHeaderParamsMap.entrySet()){
                requestBuilder.header(params.getKey(),params.getValue());
            }
        }

        // process post body inject
        if (paramsMap.size() > 0) {
            if (canInjectIntoBody(oldRequest)) {
                FormBody.Builder formBodyBuilder = new FormBody.Builder();
                for(Map.Entry<String, String> entry : paramsMap.entrySet()) {
                    formBodyBuilder.add((String) entry.getKey(), (String) entry.getValue());
                }

                RequestBody formBody = formBodyBuilder.build();
                String postBodyString = bodyToString(oldRequest.body());
                postBodyString += ((postBodyString.length() > 0) ? "&" : "") +  bodyToString(formBody);
                requestBuilder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyString));
            }
        }

        Request newRequest = requestBuilder.build();

        return chain.proceed(newRequest);
    }

    public static class Builder{
        HttpCommonInterceptor mHttpCommonInterceptor;

        public Builder(){
            mHttpCommonInterceptor = new HttpCommonInterceptor();
        }

        public Builder addHeaderParams(String key, String value){
            mHttpCommonInterceptor.mHeaderParamsMap.put(key,value);
            return this;
        }

        public Builder  addHeaderParams(String key, int value){
            return addHeaderParams(key, String.valueOf(value));
        }

        public Builder  addHeaderParams(String key, float value){
            return addHeaderParams(key, String.valueOf(value));
        }

        public Builder  addHeaderParams(String key, long value){
            return addHeaderParams(key, String.valueOf(value));
        }

        public Builder  addHeaderParams(String key, double value){
            return addHeaderParams(key, String.valueOf(value));
        }


        public HttpCommonInterceptor build(){
            return mHttpCommonInterceptor;
        }
    }

    private boolean canInjectIntoBody(Request request) {
        if (request == null) {
            return false;
        }
        if (!TextUtils.equals(request.method(), "POST")) {
            return false;
        }
        RequestBody body = request.body();
        if (body == null) {
            return false;
        }
        MediaType mediaType = body.contentType();
        if (mediaType == null) {
            return false;
        }
        if (!TextUtils.equals(mediaType.subtype(), "x-www-form-urlencoded")) {
            return false;
        }
        return true;
    }

    private static String bodyToString(final RequestBody request){
        try {
            final RequestBody copy = request;
            final Buffer buffer = new Buffer();
            if(copy != null)
                copy.writeTo(buffer);
            else
                return "";
            return buffer.readUtf8();
        }
        catch (final IOException e) {
            return "did not work";
        }
    }
}

封装一个RetrofitServiceManager


class RetrofitServiceManager {
    val mRetrofit: Retrofit
    val DEFAULT_TIME_OUT = 5//超时时间 5s
    val DEFAULT_READ_TIME_OUT = 10

    init {
        val builder = OkHttpClient.Builder()
        builder.connectTimeout(DEFAULT_TIME_OUT.toLong(), TimeUnit.SECONDS)
        builder.writeTimeout(DEFAULT_READ_TIME_OUT.toLong(), TimeUnit.SECONDS)
        builder.readTimeout(DEFAULT_READ_TIME_OUT.toLong(), TimeUnit.SECONDS)

        //添加公共拦截参数
        val commonInterceptor = HttpCommonInterceptor.Builder()
                .addHeaderParams("palthform", "adnroid")
                .addHeaderParams("userToken", "12345678912")
                .addHeaderParams("userId", "123")
                .build()

        builder.addInterceptor(commonInterceptor)


        mRetrofit = Retrofit.Builder()
                .client(builder.build())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(NetConfig.BASEURL)
                .build()

    }

    //单列模式
    object SingletonHolder {
        val INSTANCE = RetrofitServiceManager()
    }

    /**
     * 获取对应的Service
     * @param service Service 的 class
     * *
     * @param <T>
     * *
     * @return
    </T> */
    fun <T> create(service: Class<T>): T {
        return mRetrofit.create(service)
    }

    /**
     * 用 companion 修饰单列
     */
    companion object {
        /**
         * 获取RetrofitServiceManager
         * @return
         */
        val instance: RetrofitServiceManager
            get() = SingletonHolder.INSTANCE
    }
}

4.设置Service
相对于单独使用Retrofit,该处返回的是Observable对象

interface ILoginService {
    @POST("JsonServlet")
    fun getLoginRxJava(@QueryMap params:MutableMap<String,Any>):Observable<UserBean>
}

5.RxJava Observable 订阅需要传入一个Observer对象,此处封装一个ObjectLoader

open class ObjectLoader {
    protected fun <T> observe(observable: Observable<T>): Observable<T>{
        return observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
    }
}

接下来创建一个登录的 我返回的直接是bean类型 方便使用

class LoginLoader :ObjectLoader(){
    val iLoginService:ILoginService

    init {
        iLoginService = RetrofitServiceManager.instance.create(ILoginService::class.java)
    }

    fun getLoginBean(params: MutableMap<String,Any>):Observable<UserBean>{
        return observe(iLoginService.getLoginRxJava(params)).map{userBean -> userBean}
    }

}

以上已经把Retofit2与Rxjava2已经配置完成。

6.接下来我们需要实现 MVP
(1).我创建model层

创建Bean

class UserBean{
    var code: String? = null
    var user: List<User>? = null
    class User {
        var age: Int = 0
        var emial: String? = null
        var hobby: String? = null
        var password: String? = null
        var phone: String? = null
        var sex: String? = null
        var username: String? = null
    }
}

创建登录Listener接口

interface ILoginListener {
    /**
     * 登录成功
     */
    fun onLoginSuccess()

    /**
     * 登录失败
     */
    fun onLoginFail(message:String)

    /**
     * 登录错误
     */
    fun onLoginError(message:String)

}

接着创建登录Model方法

interface ILoginModel {
    /**
     * 提取一个登录方法
     * @param username  用户名
     * @param password   密码
     * @param loginListener 登录接口
     */
    fun Login(username:String,password:String,loginListener:ILoginListener)
}

实现该ILoginModel

注意的地方主要是 val params:MutableMap<String,Any> = mutableMapOf()这里面重要的是 我刚开始运用的是 Map<String,Any> 这么写就会null报错

class LoginModel :ILoginModel{

    var loginLoader:LoginLoader ? = null
    var userBean:UserBean ? = null
    var ErrorMsg:String ? = null

    override fun Login(username: String, password: String, loginListener: ILoginListener) {
        loginLoader = LoginLoader()
        userBean = UserBean()
        ErrorMsg = ""

        if(TextUtils.isEmpty(username)||TextUtils.isEmpty(password)){
            loginListener.onLoginFail("输入不能为空!")
            return
        }

        val params:MutableMap<String,Any> = mutableMapOf()
        params.put("action","loginUser")
        params.put("username",username)
        params.put("password",password)

        loginLoader!!.getLoginBean(params).subscribe(object:Observer<UserBean>{

            override fun onSubscribe(d: Disposable?) {
                /**
                 * Disposable是1.x的Subscription改名的,因为Reactive-Streams规范用这个名称,为了避免重复
                 * 这个回调方法是在2.0之后新添加的
                 * 可以使用d.dispose()方法来取消订阅
                 */
            }

            override fun onNext(value: UserBean) {
                if(value.code=="200"&& value.user!!.size>0){
                    loginListener.onLoginSuccess()
                }else{
                    loginListener.onLoginFail("账号或者密码不正确")
                }
            }

            override fun onError(e: Throwable) {
                Log.e("TAG", "error message:" + e.message)
                ErrorMsg = "网络出现错误!"
                loginListener.onLoginError(ErrorMsg!!)
            }

            override fun onComplete() {
                //可以干一些别的事情
                Log.e("onComplete", "complete")
            }

        })

    }
}

(2).创建view层 主要有2个方法 账号和密码

interface ILoginView {
    fun getUserName():String
    fun getPassword():String
}

(3).创建presenter方法 连接M层和V层

class LoginPresenter (val iLoginView:ILoginView){
    val iLoginModel:ILoginModel

    init {
        iLoginModel = LoginModel()
    }

    /**
     * 登录方法,建立M,V层的关系
     */
    fun Login(iLoginListener: ILoginListener){
        iLoginModel.Login(iLoginView.getUserName(),iLoginView.getPassword(),iLoginListener)
    }

}

7.创建UI
里面包含 Activity 或者Fragment

class LoginActivity : AppCompatActivity() ,View.OnClickListener,ILoginView{

    var llusername:LinearLayout?=null
    var llpassword:LinearLayout?=null
    var username:EditText? = null
    var password:EditText? = null
    var login:Button?=null
    var llforgetpwd:LinearLayout?=null
    var lljoinus:LinearLayout?=null
    var loginPresenter:LoginPresenter?=null
    var dialog: ProgressDialog? = null
    var errorMsg: String? = null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.login_layout)

        initView()
    }

    private fun initView() {
        llusername = findViewById(R.id.ll_username) as LinearLayout

        llpassword = findViewById(R.id.ll_password) as LinearLayout

        username = findViewById(R.id.username) as EditText

        password = findViewById(R.id.password) as EditText

        login = findViewById(R.id.login) as Button

        llforgetpwd = findViewById(R.id.ll_forget_pwd) as LinearLayout
        lljoinus = findViewById(R.id.ll_join_us) as LinearLayout

        llusername!!.background.alpha = 100

        llpassword!!.background.alpha = 100

        loginPresenter = LoginPresenter(this)

        login!!.setOnClickListener(this)
        llforgetpwd!!.setOnClickListener(this)
        lljoinus!!.setOnClickListener(this)


    }

    val iloginListener = object :ILoginListener{
        override fun onLoginSuccess() {
            handler.sendEmptyMessage(200)
        }

        override fun onLoginFail(message: String) {
            errorMsg = message
            handler.sendEmptyMessage(1)
        }

        override fun onLoginError(message: String) {
            errorMsg = message
            handler.sendEmptyMessage(0)
        }

    }

    val handler = object :Handler(){
        override fun handleMessage(msg: Message?) {
            when(msg!!.what){
                0->{
                    if (dialog != null) {
                        dialog!!.dismiss()
                        dialog = null
                    }
                    Toast.makeText(application, "登录失败! 原因:" + errorMsg!!, Toast.LENGTH_SHORT).show()
                }

                1->{
                    if (dialog != null) {
                        dialog!!.dismiss()
                        dialog = null
                    }
                    Toast.makeText(application, "登录失败! 原因:" + errorMsg!!, Toast.LENGTH_SHORT).show()
                }

                200->{
                    if (dialog != null) {
                        dialog!!.dismiss()
                        dialog = null
                    }
                    //存储账号和密码
                    //saveKeepPwd(username!!.text.toString().trim { it <= ' ' }, password!!.text.toString().trim { it <= ' ' })
                    val intent = Intent(this@LoginActivity, MainActivity::class.java)
                    startActivity(intent)
                    finish()
                }
            }
        }
    }



    override fun onClick(v: View?) {
        when(v!!.id){
            R.id.login->{
                if(dialog==null){
                    dialog = ProgressDialog(this)
                    dialog!!.setTitle("加载中")
                    dialog!!.setMessage("正在加载中...")
                    dialog!!.setCanceledOnTouchOutside(false)
                    dialog!!.setCancelable(true)
                    dialog!!.show()
                }

                loginPresenter!!.Login(iloginListener)

            }

            R.id.ll_forget_pwd->{

            }

            R.id.ll_join_us->{

            }
        }
    }

    override fun getUserName(): String {
        return username!!.text.toString().trim { it <= ' ' }
    }

    override fun getPassword(): String {
        return password!!.text.toString().trim { it <= ' ' }
    }
}

在这里面出现了?和 !!
? 代表的可以为null
!!代表不能为空当为空的时候就会抛出异常
还有 kotlin里面利用when else取代了java switch default,使用都差不多。

8.当需要使用 Adapter的时候 可以这么写

class ListAdapter(var context: Context?, val list: List<UserBean.User>):RecyclerView.Adapter<ListAdapter.MainViewHolder>(){

    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MainViewHolder {
        if (context == null) {
            if (parent != null) {
                context = parent.context
            }
        }
        var v:View = LayoutInflater.from(parent?.context).inflate(R.layout.list_adapter_item,parent,false)

        return MainViewHolder(v)
    }

    override fun getItemCount(): Int {
        return list?.size!!

    }

    override fun onBindViewHolder(holder: MainViewHolder?, position: Int) {
        //数据获取在这里
        var user = list.get(position)
        holder?.mtxtname?.text = "${user.username}"
        holder?.mtxtcon?.text = "${user.password}"

    }


    class MainViewHolder(itemview: View) : RecyclerView.ViewHolder(itemview){
        var mtxtname: TextView? = null
        var mtxtcon: TextView? = null

        init {
            mtxtname = itemview.findViewById(R.id.txt_name)

            mtxtcon = itemview.findViewById(R.id.txt_con)
        }

    }
}

以上就是所有的代码
感谢 泓洋 的mvp理论
源代码如下

http://download.csdn.net/download/a1989214/9953125

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

面包超人吧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值