Rxjava 跳坑日记1

分析

我感觉这是我最近一段时间以来入的最深的一个坑[捂脸][捂脸],这几天在做一个根据坐标获取位置信息的一个接口,通过Retrofit+Rxjava实现。
输入是一个坐标信息的长字符串,包含N个坐标,由于高德、百度等地图一次性最多处理20个坐标,所以如果N>20,需要将该字符串分成每20个一组,分批处理。
问题在于,如果仅处理一组,那么我只需要直接将这些参数传给服务器,通过retrofit从服务器获取包含位置信息的json,将它数据解析,然后将解析完的位置信息利用回调接口回传即可。然而,如果是需要处理多组数据,那么需要等到所有数据都返回之后再一起回传,这有些难以实现,因为每次调用回调接口时,都是在CallBack中的OnSuccess中完成的,然而多次请求会多次调用CallBack的OnSuccess方法,并不能实现统一回传(当然我可以用一些特殊技巧保证只在最后一次调用OnSuccess方法时统一将数据回传,但是这个方法显然不是我想要的)。
因此,我去网上找了Rxjava的东西看了看,地址:,里面讲述了Rxjava的大部分精髓,就开始学着用了下,我发现可以通过同步和异步两种方式实现。
同步方式:
将传入的坐标封装成ArrayList<String> 的数组,用.map()的方式将其元素String转为最后返回的类型ArrayList<String>,然后绑定Subscriber即可。
异步方式:
将传入的坐标封装成ArrayList<String> 的数组,用flatMap()将Observable<String> 转化成Observable<Arraylist<String>> ,然后绑定Subscriber即可。
这里最主要的问题是线程问题,当我使用同步方式的时候,发现请求服务器总是没有返回给我位置信息,调试后说不应该在主线程执行请求,然而我在前边已经添加了.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) 两行代码来处理线程,照理说不应该报错的。经过各种调试,我把这两行代码放到了.map()之后,结果就正常运行了!所以问题就在于,为何线程控制在变换之前就没有起到作用呢?我在上述网页中查到了这样一段内容:变换原理
每次变换之后相当于重新create了一个被观察者,可能是之前的线程控制就因此丢掉了?这是我的个人的推测,不知道是否正确,如果有懂的大牛知道可以留言纠正,万分感谢!
下面记录下接口的实现过程:

同步实现

首先是从服务器获取位置信息的接口:

interface LocationInterface {
    @GET("/v3/geocode/regeo")
    fun getLocation(@Query("location")location:String,@Query("key")key:String,@Query("batch")batch :String,@Query("poitype")poitype:String,@Query("extensions")ext:String): Call<AddressBean>
}

这里主要是要进行批量请求,所以需要批量处理参数batch要设置为true;
然后是主要实现类:

class LocationUtil {

    companion object {
        fun getCitys(coordinates:ArrayList<LocalMedia>,observer:Observer<ArrayList<String>>){
            var location:String=""
            val addrs=ArrayList<String>()
            val addrMap=LinkedHashMap<Int,ArrayList<String>>()
            val url="http://restapi.amap.com"
            val key="fd2cf5bbfa5e4a5b88ded7ed74c9351c"
            val poitype="风景名胜"
            val retrofit = Retrofit.Builder()
                    .addConverterFactory(GsonConverterFactory.create())//解析方法
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .baseUrl(url)
                    .build()
            val locationInterface:LocationInterface=retrofit.create(LocationInterface::class.java)
            val EACHLENGTH=20

            LogUtils.i("coordinates.size=="+coordinates.size)
            val splitedList=ArrayList<String>()
            for (i in 0..(coordinates.size-1)/EACHLENGTH) {
                location=""
                for (j in EACHLENGTH*i..minOf(EACHLENGTH*i+EACHLENGTH-1,coordinates.size-1))
                {
                    val coordinate=coordinates[j]
                    location=location+coordinate.longitude+","+coordinate.latitude+"|"
                    LogUtils.i("location.length=="+location.length)
                }
                location=location.substring(0,location.length-1)
                splitedList.add(location)
            }
            Observable.from(splitedList)
                    .map(object :Func1<String,ArrayList<String>>{
                        override fun call(locat: String?): ArrayList<String> {
                            LogUtils.i("LOCAT!!!"+locat)
                            val result=locationInterface.getLocation(locat!!, key,"true",poitype,"all").execute().body()
                            val tmpAddrs = ArrayList<String>()
                            LogUtils.i("COMMMMMIN???2222")
                            LogUtils.i("result.info=="+result?.info)
                            for (i in 0..result?.regeocodes?.asJsonArray?.size()!! - 1) {
                                var addr = ""
                                if (result.regeocodes?.asJsonArray?.get(i)?.asJsonObject?.get("pois")?.asJsonArray?.size()!! >0) {
                                    LogUtils.i("NOTNULL!")
                                    addr = result.regeocodes?.asJsonArray?.get(i)?.asJsonObject?.get("pois")?.asJsonArray?.get(0)?.asJsonObject?.get("name").toString()
                                } else {
                                    addr = result.regeocodes?.asJsonArray?.get(i)?.asJsonObject?.get("formatted_address").toString()
                                }
                                tmpAddrs.add(addr.substring(1, addr.length - 1))
                                LogUtils.i("ADDRESS:" + result.regeocodes?.asJsonArray?.get(i)?.asJsonObject?.get("formatted_address"))
                            }
                            return tmpAddrs
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(observer)



        }
    }
}

大致步骤就是:先创建retrofit,然后绑定接口LocationInterface,将传入的参数坐标数组coordinates每20个一组进行分组保存到ArrayList<String>的 数组splitedList 中,然后放到Observable.from()中构造出Observable<String>类型的对象,我们需要得到的是最后为ArrayList<String> 的位置信息,所以通过.map()来转换,转换过程中调用接口的get方法从服务器获取位置信息,然后对其进行Gson解析得到我们要的筛选过的信息。最后设置线程,绑定观察者即可。

异步实现

接口返回类型改成Observable<AddressBean> :

interface LocationInterface {
    @GET("/v3/geocode/regeo")
    fun getLocation(@Query("location")location:String,@Query("key")key:String,@Query("batch")batch :String,@Query("poitype")poitype:String,@Query("extensions")ext:String): Observable<AddressBean>
}

主要实现类里主要更改Observable这块:

.flatMap(object :Func1<String,Observable<ArrayList<String>>>{
                        override fun call(locat: String?): Observable<ArrayList<String>> {
                            LogUtils.i("LOCAT!!!"+locat)
                            return locationInterface.getLocation(locat!!, key,"true",poitype)
                                    .map(object :Func1<AddressBean,ArrayList<String>>{
                                        override fun call(result: AddressBean?): ArrayList<String> {
                                            var tmpAddrs = ArrayList<String>()
                                            LogUtils.i("COMMMMMIN???")
                                            LogUtils.i("result.info=="+result?.info)
                                            for (i in 0..result?.regeocodes?.asJsonArray?.size()!! - 1) {
                                                var addr = ""
        //                                if (result.regeocodes?.asJsonArray?.get(i)?.asJsonObject?.get("pois") != null) {
        //                                    addr = result.regeocodes?.asJsonArray?.get(i)?.asJsonObject?.get("pois")?.asJsonArray?.get(0)?.asJsonObject?.get("name").toString()
        //                                } else {
                                                addr = result.regeocodes?.asJsonArray?.get(i)?.asJsonObject?.get("formatted_address").toString()
        //                                }
                                                tmpAddrs.add(addr.substring(1, addr.length - 1))
                                                LogUtils.i("ADDRESS:" + result.regeocodes?.asJsonArray?.get(i)?.asJsonObject?.get("formatted_address"))
                                            }
                                            return tmpAddrs
                                        }

                                    })
                        }
            })
            .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(observer)

主要是通过.flatMap()异步将Observable<String>类型对象转换为Observable<ArrayList<String>> 类型。

最后再总结下回调机制:被观察者A类在内部方法C(setXXXListener)的参数中提供接口入口(XXXListener),并在内部类中声明接口,在内部方法中调用接口方法;观察者B类在调用被观察者的方法时,将作为参数的监听接口具体实现,更改自身的属性D。
例如:

class A{
        var c:Int=1
        fun setXXXListener(listener:XXXListener){
            ...
            ...
            listener.onXXX(c)
        }
        interface XXXListener{
            fun onXXX(c:Int)
        }
    }
    class B{
        var a:A?=null
        var d:Int=0
        fun YYY(){
            a=A()
            a?.setXXXListener(object:A.XXXListener{
                override fun onXXX(c: Int) {
                    d=c
                }

            })
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容越多,也需要更多的人来对数据进行整理,并且数据的汇总查询方面效率也是极其的低下,并且数据安全方面永远不会保证安全性能。结合数据内容管理的种种缺点,在互联网时代都可以得到有效的补充。结合先进的互联网技术,开发符合需求的软件,让数据内容管理不管是从录入的及时性,查看的及时性还是汇总分析的及时性,都能让正确率达到最高,管理更加的科学和便捷。本次开发的高校科研信息管理系统实现了操作日志管理、字典管理、反馈管理、公告管理、科研成果管理、科研项目管理、通知管理、学术活动管理、学院部门管理、科研人员管理、管理员管理等功能。系统用到了关系型数据库中王者MySql作为系统的数据库,有效的对数据进行安全的存储,有效的备份,对数据可靠性方面得到了保证。并且程序也具备程序需求的所有功能,使得操作性还是安全性都大大提高,让高校科研信息管理系统更能从理念走到现实,确确实实的让人们提升信息处理效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值