RxJava在Android移动端开发中的实战应用之一
响应式编程是以异步和数据流来构建事务关系的编程模型,异步和数据流是以构建事务关系而存在,异步是为了区分无关的事务,数据流是为了联系有关的事务
版权声明:本文来自门心叼龙的博客,属于原创内容,转载请注明出处
https://blog.csdn.net/geduo_83/article/details/89736624
文章目录
- 1.时间段选择器,把一天24小时,按照每半个小时作为一个时间段进行分割,共生成48个时间段字符串集合进行返回
- 思路如下
- 实现步骤
- 知识点
- 代码实现
- 2.地图加载完毕且定位成功之后,显示当前定位点
- 实现步骤
- 1.创建一个地图加载的发射器
- 2.创建一个地图定位的发射器
- 3.开启地图加载监听,加载成功发射事件
- 4.开启地图定位监听,定位成功发射事件
- 5. 对地图加载发射器和地图定位发射器的事件进行打包合并处理
- 知识点
- 3. 网络请求完毕数据返回之后,根据头像的url对头像bitmap数据进行下载,最后最终将结果数据返回
- 实现步骤
- 知识点
- 代码实现
- 4.进入首页要进行权限检查,检查完毕再进行升级检查
- 实现步骤
- 知识点
- 代码实现
- 5.多图片上传,先进行token请求,请求完毕再进行图片上传
- 实现步骤
- 知识点
- 6.对于请求的事件数据进行转换
- 实现步骤
- 知识点
- 7.车辆设备id过滤
- 实现步骤
- 知识点
1.时间段选择器,把一天24小时,按照每半个小时作为一个时间段进行分割,共生成48个时间段字符串集合进行返回
时间格式如下:
[00:00-00:30,
00:30-01:00,
01:00-01:30,
…
23:00-23:30,
23:30-00:00]
思路如下
- 1.首先我们需要得到48个时间点如:
2019-01-01 00:00
2019-01-01 00:30
2019-01-01 01:00
2019-01-01 01:30
…
…
2019-01-01 23:00
2019-01-01 23:30
2019-01-01 24:00 - 2.计算完毕,两两组合
实现步骤
- 1.创建了一个日期发射器
- 2.创建一个0-49范围的有序整数序列的合集发射器
- 3.通过combineLatest将两个两个发射器的事件进行两两结合
- 4.计算得到48个时间点的事件
- 5.通过buffer缓存48个时间点事件
- 6.将得到的事件(00:00,00:30) 转换为另外一个事件(00:00-00:30)
- 7.通过blockingFirst将计算结果返回
知识点
- 1.Observable.create创建一个发射器
- 2.Observable.range创建一个发射指定范围的整数序列的发射器
- 3.Observable.combineLatest组合两个发射器
- 4.Observable.buffer缓存事件
- 5.Observable.blockingFirst阻塞返回第一个事件
代码实现
public static List<String> getTimeData() {//创建了一个日期发射器Observable<Calendar> calendarObservable = Observable.create(new ObservableOnSubscribe<Calendar>() {@Overridepublic void subscribe(ObservableEmitter<Calendar> emitter) throws Exception {Calendar calendar = Calendar.getInstance();calendar.set(2019, 0, 1, 0, 0);emitter.onNext(calendar);}});//创建了一个发射0到48的一个数字发射器,目的是给日期做累加计算Observable<Integer> integerObservable = Observable.range(0, 49);//对日期发射器和数字发射器进行两两组合List<String> strings = Observable.combineLatest(calendarObservable, integerObservable, new BiFunction<Calendar, Integer, String>() {@Overridepublic String apply(Calendar calendar, Integer integer) throws Exception {calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + (integer == 0 ? 0 : 30));return DateUtil.formatDate(calendar.getTime(), DateUtil.FormatType.HHmm);}}).buffer(49).map(new Function<List<String>, List<String>>() {@Overridepublic List<String> apply(List<String> list) throws Exception {List<String> timeLine = new ArrayList<>();for (int i = 0; i < list.size() - 1; i++) {timeLine.add(list.get(i) + "-" + list.get(i + 1));}return timeLine;}}).blockingFirst();return strings;}
2.地图加载完毕且定位成功之后,显示当前定位点
在RxJava出现之前解决这类问题的确是一件很麻烦的事情,地图加载和定位成功两件事都完成之后才能进行显示当前点的操作,否则就有可能出现,当定位完成了,但是地图还没有加载完毕,而是导致定位点的缩放级别不能显示的问题,有了RxJava这些问题已经变得迎刃而解了。
实现步骤
1.创建一个地图加载的发射器
ObservableEmitter<Boolean> mMapLoadEmitter;
Observable<Boolean> mapLoadObservable = Observable.create(new ObservableOnSubscribe<Boolean>() {@Overridepublic void subscribe(ObservableEmitter<Boolean> emitter) throws Exception {mMapLoadEmitter = emitter;KLog.v(TAG,"mapLoadObservable succ");}
});
2.创建一个地图定位的发射器
ObservableEmitter<PoiInfo> mLocationEmitter;
Observable<PoiInfo> mapLocationObservable = Observable.create(new ObservableOnSubscribe<PoiInfo>() {@Overridepublic void subscribe(ObservableEmitter<PoiInfo> emitter) throws Exception {KLog.v(TAG,"mapLocationObservable succ");mLocationEmitter = emitter;}});
3.开启地图加载监听,加载成功发射事件
当地图加载成功的时候,发射地图加载成功的事件
mMap.setOnMapLoadedListener(new AMap.OnMapLoadedListener() {@Overridepublic void onMapLoaded() {KLog.v(TAG,"onMapLoaded succ");KLog.v(TAG,"mMapLoadEmitter:"+(mMapLoadEmitter == null ? "null":"not null"));if(mMapLoadEmitter != null){mMapLoadEmitter.onNext(true);}}});
4.开启地图定位监听,定位成功发射事件
当定位成功的时候,发射定位成功的事件
mMap.setOnMyLocationChangeListener(new AMap.OnMyLocationChangeListener() {@Overridepublic void onMyLocationChange(Location location) {KLog.json(TAG, location.toString());KLog.v(TAG,"onMyLocationChange succ");KLog.v(TAG,"mLocationEmitter:"+(mLocationEmitter == null ? "null":"not null"));mPoiInfo = new PoiInfo(location.getLatitude(), location.getLongitude());if(mLocationEmitter != null){mLocationEmitter.onNext(mPoiInfo);}}});
5. 对地图加载发射器和地图定位发射器的事件进行打包合并处理
当地图加载成功,且地图定位成功,则显示当前位置点信息
Observable.zip(mapLoadObservable, mapLocationObservable, new BiFunction<Boolean, PoiInfo, PoiInfo>() {@Overridepublic PoiInfo apply(Boolean aBoolean, PoiInfo poiInfo) throws Exception {return poiInfo;}}).subscribe(new Consumer<PoiInfo>() {@Overridepublic void accept(PoiInfo poiInfo) throws Exception {KLog.v(TAG,"zip succ");mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(poiInfo.getLat(), poiInfo.getLon()),14));}});}
知识点
- 1.Observable.create创建发射器
- 2.Observable.zip打包发射器
3. 网络请求完毕数据返回之后,根据头像的url对头像bitmap数据进行下载,最后最终将结果数据返回
实现步骤
- 1.将GetAppyDetailResponse事件转化为List事件
- 2.将List事件转为一个能发射多个事件的发射器
- 3.将每个ApprovalProgress事件都转换为另外一个能下载图片的发射器
- 4.图片下载完毕,将事件进行发射
- 5.将图片下载的事件进行缓存
- 6.所有的图片都下载完毕之后最终将所有数据返回
知识点
- 1.Observable.map 将一个事件转换为另外一个事件
- 2.Observable.flatMap 将一个事件转换为另外一个发射器
- 3.Observable.toList 将所有的发射事件进行打包
代码实现
public Single getApplyDetail(GetAppyDetailRequest request) {cacheAppyDetailResponse = null;return mUseCarService.getApplyDeatail(request).compose(RxAdapter.bindUntilEvent(getLifecycle())).compose(RxAdapter.schedulersTransformer()).compose(RxAdapter.exceptionTransformer())// 把一个事件转化为另外一个事件.map(new Function<GetAppyDetailResponse, List<ApprovalProgress>>() {@Overridepublic List<ApprovalProgress> apply(GetAppyDetailResponse getAppyDetailResponse) throws Exception {cacheAppyDetailResponse = getAppyDetailResponse;List<ApprovalProgress> handleprogress = getAppyDetailResponse.handleprogress;// count = handleprogress.size();// KLog.v(TAG,"count:"+count);for(int i = 0; i < handleprogress.size(); i++){handleprogress.get(i).orderid = i;}return handleprogress;}})// 把一个事件转化为另外一个发射器.flatMap(new Function<List<ApprovalProgress>, Observable<ApprovalProgress>>() {@Overridepublic Observable<ApprovalProgress> apply(List<ApprovalProgress> approvalProgresses)throws Exception {return Observable.fromIterable(approvalProgresses);}// 继续把一个事件转化为另外一个发射器}).flatMap(new Function<ApprovalProgress, ObservableSource<ApprovalProgress>>() {@Overridepublic ObservableSource<ApprovalProgress> apply(final ApprovalProgress approvalProgress)throws Exception {return Observable.create(new ObservableOnSubscribe<ApprovalProgress>() {@Overridepublic void subscribe(final ObservableEmitter<ApprovalProgress> emitter) throws Exception {String headphoto = approvalProgress.headphoto;int resid = R.drawable.usercar_pic_user_bg;KLog.v(TAG, "headurl:" + headphoto);GlideApp.with(getContext()).asBitmap().load(headphoto).into(new SimpleTarget<Bitmap>() {@Overridepublic void onResourceReady(Bitmap resource,Transition<? super Bitmap> transition) {KLog.v(TAG, "header bitmap download succ");approvalProgress.header = BitmapUtil.scaleTo(resource,DisplayUtil.dip2px(40), DisplayUtil.dip2px(40));emitter.onNext(approvalProgress);emitter.onComplete();}@Overridepublic void onLoadFailed(@Nullable Drawable errorDrawable) {//super.onLoadFailed(errorDrawable);approvalProgress.header = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.usercar_pic_user_bg);emitter.onNext(approvalProgress);emitter.onComplete();}});}});}}).toList().map(new Function<List<ApprovalProgress>, GetAppyDetailResponse>() {@Overridepublic GetAppyDetailResponse apply(List<ApprovalProgress> approvalProgresses) throws Exception {KLog.v(TAG, "emitter succ");Collections.sort(approvalProgresses);cacheAppyDetailResponse.handleprogress = approvalProgresses;return cacheAppyDetailResponse;}}).compose(RxAdapter.singleSchedulersTransformer()).compose(RxAdapter.singleExceptionTransformer()).compose(RxAdapter.<GetAppyDetailResponse> bindUntilEvent(getLifecycle())); // 最后返回到主线程;}
4.进入首页要进行权限检查,检查完毕再进行升级检查
实现步骤
- 1.创建一个权限检查的发射器
- 2.对检查的结果事件转换为另外一个升级的发射器
- 3.订阅该发射器处理事件结果
知识点
- 1.Observable.flatMap将一个事件转换为另外一个发射器
代码实现
@Overridepublic void checkPermisionAndUpgrade(FragmentActivity activity) {//先进行权限检查,在进行升级检查,避免同时出现权限授权对话框和升级对话框new RxPermissions(activity).request(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE).flatMap(new Function<Boolean, ObservableSource<ClientVersionResponse>>() {@Overridepublic ObservableSource<ClientVersionResponse> apply(Boolean aBoolean) throws Exception {if (!aBoolean) {ToastUtil.showToast("缺少定位权限、存储权限,这会导致地图、导航、拍照等部分功能无法使用");}int versionCode = EnvironmentUtil.getAppVersionCode(mContext);return mModel.getAppVersion(new ClientVersionRequest(String.valueOf(versionCode)));}}).subscribe(new Observer<ClientVersionResponse>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(ClientVersionResponse clientVersionResponse) {KLog.v(TAG,"upgrade check succ...");if (UpgradeType.MUST.type.equalsIgnoreCase(clientVersionResponse.getVersion().upgrade) || UpgradeType.SUGGEST.type.equalsIgnoreCase(clientVersionResponse.getVersion().upgrade)) {//存储版本升级信息VersionManagerUtils.setLastVersion(clientVersionResponse.getVersion());mView.showUpdateDialog(clientVersionResponse.getVersion());}}@Overridepublic void onError(Throwable e) {}@Overridepublic void onComplete() {}});}
5.多图片上传,先进行token请求,请求完毕再进行图片上传
图片上传可以说是一个在常见不过的功能了,在app的个人设置中上传一个个人头像,用微信发一个带几张图的朋友圈,都会用到图片上传的功能,一般情况下图片上传的时候,先要获取上传的权限,也就是先要获取Token才能进行进行下一步的图片上传操作
实现步骤
- 1.创建一个获取token的Observable
- 2.将token事件转换为另外一个发送多个事件的Observable
- 3.将每一个MediaRequest事件再转换为图片上传的Observable
- 4.图片上传完毕发射该事件
- 5.将图片下载成功的事件机型缓存
- 6.全部下载完毕再返回数据
知识点
- 1.Observable.flatMap
- 2.Obserable.create
/*** 批量上传文件,带进度条的** @param context* @param type : 上传的业务类型 详见UploadImageUtil.FILE_TYPE_BLOG* @param callback* @param urls* @param listener*/public static void uploadFile(final Context context, final int type, final String callback, final List<String> urls, final ResponseProgressListener listener) {Log.v(TAG, "uploadImages start...");final List<MediaResponse> list = new ArrayList<>();// 1.通过服务创建了一个请求Token的命令Observable<UserTokenResponse> observable = RetrofitManager.getInstance().getCommonService().getToken(new TokenRequest(type));// 2.将执行的结果和要上传的多条数据转化为一个新的Observableobservable.flatMap(new Function<UserTokenResponse, ObservableSource<MediaRequest>>() {@Overridepublic ObservableSource<MediaRequest> apply(UserTokenResponse userTokenResponse) throws Exception {Log.v(TAG, "get token succ...");Log.v(TAG, "thread id" + Thread.currentThread().getName());List<MediaRequest> mList = new ArrayList<>();STSV2 stsinfo = userTokenResponse.getStsinfo();for (int i = 0; i < urls.size(); i++) {Log.v(TAG, urls.get(i));mList.add(new MediaRequest(stsinfo, urls.get(i), i));}return Observable.fromIterable(mList);}}).flatMap(new Function<MediaRequest, ObservableSource<Object>>() {@Overridepublic ObservableSource<Object> apply(final MediaRequest mediaRequest) throws Exception {// 3.对发射过来的每一条数据再次进行转换成一个可以执行上传任务的发射器,并将执行结果进行发送return Observable.create(new ObservableOnSubscribe<Object>() {@Overridepublic void subscribe(final ObservableEmitter<Object> emitter) throws Exception {Log.v(TAG, "start upload...");Log.v(TAG, "thread id" + Thread.currentThread().getName());try {final STSV2 stsv2 = mediaRequest.getSTSV2();OSSCredentialProvider credentialProvider = new OSSStsTokenCredentialProvider(stsv2.keyid, stsv2.keysecret, stsv2.securitytoken);OSSLog.enableLog();final OSS oss = new OSSClient(context, stsv2.endpoint, credentialProvider);String currurl = mediaRequest.getUrl();final String fileName = MD5Util.MD5(UUID.randomUUID().toString()) + "." + currurl.substring(currurl.lastIndexOf(".") + 1);String fileOssName = stsv2.filepath + fileName;byte[] imageCompressByte;if (FileUtil.isImageFile(currurl)) {imageCompressByte = BitMapUtils.getImageCompressByte(currurl);} else {imageCompressByte = FileUtil.getFileByte(currurl);}final PutObjectRequest put = new PutObjectRequest(stsv2.bucket, fileOssName, imageCompressByte);ObjectMetadata metadata = new ObjectMetadata();metadata.setContentType("application/octet-stream");put.setMetadata(metadata);final StringBuilder backUrlSB = new StringBuilder();backUrlSB.append("bucket=").append(stsv2.bucket);backUrlSB.append("&filename=").append(fileOssName);backUrlSB.append("&filetype=").append(type);backUrlSB.append("&").append(callback);put.setCallbackParam(new HashMap<String, String>() {{put("callbackUrl", stsv2.callbackurl);put("callbackBody", backUrlSB.toString());}});put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {@Overridepublic void onProgress(PutObjectRequest putObjectRequest, long l, long l1) {if (l > 0 && l1 > 0) {emitter.onNext(l + "|" + l1 + "|" + urls.size() + "|" + mediaRequest.getId());}}});oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {@Overridepublic void onSuccess(PutObjectRequest putObjectRequest, PutObjectResult putObjectResult) {Log.v(TAG, "video upload succ...");Log.v(TAG, "thread id" + Thread.currentThread().getName());int[] imgSize = BitMapUtils.getImageSize(mediaRequest.getUrl());emitter.onNext(new MediaResponse(TextUtils.concat(stsv2.fileurl, fileName).toString(), imgSize[0], imgSize[1]));}@Overridepublic void onFailure(PutObjectRequest putObjectRequest, ClientException e, ServiceException e1) {Log.v(TAG, "video upload fail...");emitter.onError(e1);}});} catch (Exception e1) {e1.printStackTrace();}}});}}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Object>() {@Overridepublic void onSubscribe(Disposable d) {Log.v(TAG, "onSubscribe start...");if (listener != null) {listener.onStart();}}@Overridepublic void onNext(Object object) {Log.v(TAG, "onNext start...");Log.v(TAG, "thread id" + Thread.currentThread().getName());if (listener != null) {if (object instanceof String) {String original = (String) object;if (original.contains("|")) {String[] split = original.split("\\|");int progress = Integer.parseInt(split[0]);int total = Integer.parseInt(split[1]);int size = Integer.parseInt(split[2]);int position = Integer.parseInt(split[3]);//当前的图片所占自己的百分比float v = (float) progress / total;//当前图片所占所有图片的百分比float v1 = (float) 1 / size * v;//之前上传过得百分比float v2 = (float) 1 / size * position;//所占总的百分比int v3 = (int) ((v1 + v2) * 100);Log.v(TAG, "progress:" + progress + ";total:" + total + ";present:" + v3);listener.onProgress(v3, 100);}} else if (object instanceof MediaResponse) {list.add((MediaResponse) object);if (list.size() == urls.size()) {listener.onSuccess(list);}Log.v(TAG, "observer receive succ");}}}@Overridepublic void onError(Throwable e) {Log.v(TAG, "onError start...");if (listener != null) {listener.onError(e);}}@Overridepublic void onComplete() {Log.v(TAG, "onComplete start...");if (listener != null) {listener.onComplete();}}});}
6.对于请求的事件数据进行转换
实现步骤
- 将GetUseStatusListResponse事件转化为List事件
- 2.List事件转换为另外一个Observable
- 3.对VehicleUseStatus事件进行操作
- 4.缓存 VehicleUseStatus事件
- 5.订阅Observable并返回处理的最终结果
知识点
- Observable.map
- Observable.flatMap
- Observable.toList
mModel.getCarStateList(new GetUseStatusListRequest(currDate, enterpriseid, stardid)).map(new Function<GetUseStatusListResponse, List<VehicleUseStatus>>() {@Overridepublic List<VehicleUseStatus> apply(GetUseStatusListResponse getUseStatusListResponse) throws Exception {stardid = getUseStatusListResponse.nextid;return getUseStatusListResponse.statuslist;}}).flatMap(new Function<List<VehicleUseStatus>, ObservableSource<VehicleUseStatus>>() {@Overridepublic ObservableSource<VehicleUseStatus> apply(List<VehicleUseStatus> vehicleUseStatuses) throws Exception {return Observable.fromIterable(vehicleUseStatuses);}}).map(new Function<VehicleUseStatus, VehicleUseStatus>() {@Overridepublic VehicleUseStatus apply(VehicleUseStatus o) throws Exception {String usetime = o.usetime;if (!TextUtils.isEmpty(usetime)) {String[] split = usetime.split("\\|");if (split != null && split.length > 0) {o.useposition = getTimePositon(Arrays.asList(split));}}return o;}}).toList().subscribe(new SingleObserver<List<VehicleUseStatus>>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onSuccess(List<VehicleUseStatus> vehicleUseStatuses) {isfirst = false;if (isrefresh) {String nowDate = DateUtil.formatDate(new Date(), DateUtil.FormatType.MMdd);String tempDate = DateUtil.formatDate(currDate, DateUtil.FormatType.yyyyMMdd,DateUtil.FormatType.MMdd);mView.showTopBarCurrDate(nowDate.equals(tempDate) ? tempDate + "今天" : tempDate);mView.enableTopBarLeftBtn(nowDate.equals(tempDate) ? false : true);if(vehicleUseStatuses != null && vehicleUseStatuses.size() > 0){mView.refreshData(vehicleUseStatuses,currDate);}else{mView.showNoDataView();}mView.stopRefresh();} else {mView.loadMoreData(vehicleUseStatuses);mView.stopLoadMore();}}@Overridepublic void onError(Throwable e) {if (isrefresh) {mView.stopRefresh();if(isfirst){if(e instanceof ResponseThrowable){ResponseThrowable throwable = (ResponseThrowable) e;if(throwable.code == ExceptionHandler.SYSTEM_ERROR.TIMEOUT_ERROR){mView.showNetWorkErrView();}}else{mView.showNoDataView();}}} else {mView.stopLoadMore();}}});
7.车辆设备id过滤
实现步骤
- 1.对车辆集合中的车辆进行过滤,过滤有设备的车辆
- 2.对过滤后的车辆事件进行转换为设备事件
- 3.将设备集合事件转换为一个Observable
- 4.对设备事件进行过滤,过滤为0的设备
- 5.对设备事件转换为设备的id事件
- 6.缓存设备id事件
- 7.订阅这个事件并返回结果
知识点
- 1.Observable.fromIterable
- 2.Observable.filter
- 3.Observable.map
- 4.Obserable.flatMap
- 5.Obserable.buffer
@Overridepublic void filterVehicleDevice(List<VehicleInfo> vehicleInfoList, final VehicleInfo vehicleInfo) {Observable.fromIterable(vehicleInfoList).filter(new Predicate<VehicleInfo>() {@Overridepublic boolean test(VehicleInfo vehicleInfo) throws Exception {// 将有设备的车辆过滤下来return vehicleInfo.getDevices() != null&& vehicleInfo.getDevices().size() > 0;}}).map(new Function<VehicleInfo, List<DeviceInfo>>() {@Overridepublic List<DeviceInfo> apply(VehicleInfo vehicleInfo) throws Exception {// 对事件进行转换,将VehicleInfo转化为DeviceInforeturn vehicleInfo.getDevices();}}).flatMap(new Function<List<DeviceInfo>, ObservableSource<DeviceInfo>>() {@Overridepublic ObservableSource<DeviceInfo> apply(List<DeviceInfo> deviceInfos) throws Exception {// 再次将device事件转化为Observablereturn Observable.fromIterable(deviceInfos);}}).filter(new Predicate<DeviceInfo>() {@Overridepublic boolean test(DeviceInfo deviceInfo) throws Exception {// 对传递过来的DeviceInfo进行过滤return "0".equals(deviceInfo.devicetype);}}).map(new Function<DeviceInfo, String>() {@Overridepublic String apply(DeviceInfo deviceInfo) throws Exception {// 再次对事件进行转换return deviceInfo.deviceid;}}).buffer(Integer.MAX_VALUE).subscribe(new Observer<List<String>>() {ArrayList<String> listBox;@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(List<String> strings) {// 对过滤的数据把它缓存起来,然后进行打包输出if (mView == null) {return;}listBox = new ArrayList<>(strings);}@Overridepublic void onError(Throwable e) {mView.filterVehicleDeviceComplete(listBox, vehicleInfo);}@Overridepublic void onComplete() {limView.filterVehicleDeviceComplete(listBox, vehicleInfo);}});}
RxJava在Android移动端开发中的实战应用之一相关推荐
- CSS3: 移动端开发中 max-device-width 与 max-width 的区别
翻译自stackoverflow.com,源地址:http://stackoverflow.com/questions/6747242/what-is-the-difference-between-m ...
- Android短视频开发中的sdk接入方案
目前短视频平台非常火,云豹科技作为优质的app源码提供商,在短视频开发领域有丰富的经验和完善的技术.下面以云豹短视频为例,概述Android短视频开发中的sdk接入方案,这里我们选择腾讯云的sdk进行 ...
- Android零基础开发到项目实战
Android零基础开发到项目实战(目录) 前言:本教程适合零基础学习安卓开发的伙伴,下面是目录,本博主会每天定时更新每一章节的教程,未完..... 一.Java基础阶段 day01_Java语言概述 ...
- Android Studio安卓开发中使用json来作为网络数据传输格式
如果你是在安卓开发中并且使用android studio,要使用json来作为数据传输的格式,那么下面是我的一些经验. 一开始我在android studio中导入那6个包,那6个包找了非常久,因为放 ...
- 记 vue 移动端开发 中的经验
项目背景 手上的 vue移动端 项目已经开发了大几个月了,遇到了一些很有意思的坑,也让自己学习了很多:写此文主要目的是记下一些我遇到的坑,以及自己的解决方案,分享的同时也方便以后复习. 项目的底层是上 ...
- Android之---项目开发中网络框架的选择
项目开发中网络框架的选择 Android常用的网路框架: 大多数应用程序基本都需要连接网络,发送一些数据给服务端,或者从服务端获取一些数据.通常在 Android 中进行网络连接一般使用 Scoket ...
- Android直播软件开发中接入腾讯IM大概流程是怎样的
现阶段来看,直播软件中的即时通讯是非常重要的一个部分,毕竟直播过程中的交流和沟通是非常重要的,所以在Android直播软件开发时需要接入相关的IM服务. 通常我们选择的即时聊天服务,会选择集成简单方便 ...
- 【Android】iOS开发中xconfig和script脚本的使用
利用Xcode进行开发时需要进行很多build setting的设置以便能让项目按照设置的进行编译,同时有时候需要在编译时利用script脚本进行一些设置,本文主要介绍xconfig文件和script ...
- Android移动端开发代码规范与格式化工具
原则 有几个原则可以帮助大家不看文档也能写出符合规范的代码: 如果是修改已有的代码,跟周围的风格一致 如果是使用系统SDK来开发,除非特别说明,风格要和系统SDK一致 新建文件写代码都按规范来写:旧文 ...
最新文章
- python处理心电图_ECG心电信号处理:使用WFDB对MIT-BIH数据集进行读取(Python)
- python培训班那家好-python培训班那个好?
- 云计算之KVM虚拟化实战
- 香农定理和奈奎斯特定理区别_这一切都从指数函数开始(4)——采样定理
- mysql多图怎么同时上传,小程序如何同时上传多张图片?
- WPF XAML 为项目设置全局样式
- 六元均匀直线阵的各元间距为_给棉花地选购滴灌带时记住这几点,不再为棉花滴水时发愁...
- 解决 spring mvc 3.0 结合 hibernate3.2 使用tx:annotation-driven声明式事务无法提交的问题(转载)...
- Open3D 欧式聚类
- linux系统下制作启动u盘,在Linux系统下如何制作创建win10启动盘U盘启动?
- 单反相机的一般入门设置建议
- 三十四、Expandable grid 可扩展的表格
- HDU 5294 - Tricks Device(最短路+最小割)
- Win10兼容性怎么设置详细的步骤
- 百度AI平台申请使用流程
- windows10计算机放桌面,将win10计算器放在桌面上的操作方法
- 编程初学者看不懂程序的几点建议
- Blender无法找到安装的插件
- 使用ViewPager实现帖子列表
- 博图V15安装授权问题
热门文章
- 新浪服务器mysql_php新浪云链接mysql与storage
- Feature Tools:自动特征工程(翻译)
- Oracle误删除表空间的恢复
- 为什么阿里巴巴禁止使用 Executors 创建线程池,而是通过 ThreadPoolExecutor 方式?...
- 16种设计思想 - Design for failure
- 小程序开发实战学习笔记 1
- 科大讯飞往届生招聘_我从飞往西雅图的最后一波设计采访中学到的东西
- 32岁的程序员被裁,java宿舍管理系统源码jsp
- 多媒体技术 第一章 多媒体技术概述
- 网页游戏制作html5,利用HTML5 Canvas制作一个简单的打飞机游戏