首页 文章 精选 留言 我的

精选列表

搜索[android things],共10000篇文章
优秀的个人博客,低调大师

Android响应式编程时代——RxJava

个人博客CoorChice,https://chenbingx.github.io/ ,最新文章将会首发CoorChice的博客,欢迎探索哦 ! 同时,搜索微信公众号CoorChice,或扫描文章末尾二维码,可以关注我的微信公众号。同期文章也将会优先推送到微信公众号中,以提醒您有新鲜文章出炉。 中文官方文档 教程 一、为什么要使用响应式编程 1.尽管响应式编程代码量比普通线程处理方式代码量大,但是响应式的突出特点就是更符合人的逻辑思维,更容易被理解。 2.响应式编程目的是为了处理线程工作的,它有一个观察者(Observer)在随时待命,准备接收可观察对象(Observable)发送的数据。 3.响应式编程的代码能够按照顺序一步步执行。 二、预备概念 1.Subscriber订阅者(本质上也是一个观察者),它可以订阅一个可观察对象Observable,通常这个可观察对 象可能会是一个异步任务。2.Observable可观察对象,一个异步任务可作为一个可观察对象。可观察对象分为热和冷:热的可观察对象一创建就能够发射数据,因此订阅它的观察者Observer可能就会因为创建的比较晚而错过一些数据。冷的可观察对象需要等到有一个观察者观察它时,它才开始发射数据。 还有一种比较特 DZ殊的Observable是connectable类型的,它只有在connect()方法被调用之后才会开 始发射数据。3.Subject这是一个十分特殊的类型,它相当于一个桥梁。可以说,它既是一个Observer,又是一个 Observable。4.Scheculer调度器,用于指定工作线程。SubscribeOn()用于指定可观察者的逻辑线程,ObserveOn()用于指定订阅者的逻辑线程。 当二者都没指定时,在当前线程中工作。 当只指定了SubscribeOn(),那么就都在这个线程中工作。 当指定了ObserveOn(),那么可观察者运行在默认线程,而订阅者运行在指定线程。 操作符 一、创建操作符 create:从头开始创建可观察对象。 Log.e("MainActivity", " -> initData: " + Thread.currentThread().getName()); //使用Create操作符创建可观察者 Observable.create(new Observable.OnSubscribe<Integer>() { //发射前的逻辑处理 @Override public void call(Subscriber<? super Integer> observer) { try { if (!observer.isUnsubscribed()) { for (int i = 1; i < 3; i++) { observer.onNext(i); Thread.sleep(1000); Log.e("MainActivity", " -> call: " + Thread.currentThread().getName()); } observer.onCompleted(); } } catch (Exception e) { observer.onError(e); } } } ) //指定可观察者的逻辑线程 //.subscribeOn(Schedulers.newThread()) //指定订阅者的逻辑线程,没有指定则与subscribeOn()在同一个线程工作。如果两者都没指定,就在当前线程中工作。 .observeOn(Schedulers.io()) //可观察者发射数据 .subscribe( //创建订阅者 new Subscriber<Integer>() { @Override public void onNext(Integer item) { System.out.println("Next: " + item); Log.e("MainActivity", " -> onNext: " + Thread.currentThread().getName()); } @Override public void onError(Throwable error) { System.err.println("Error: " + error.getMessage()); } @Override public void onCompleted() { System.out.println("Sequence complete."); } }); from:通过一个集合创建可观察对象。 List<String> data = new ArrayList<>(); data.add("1"); data.add("2"); data.add("3"); // 把一个集合转化为数据按顺序发射 Observable.from(data) // 指定可观察者工作线程 .subscribeOn(Schedulers.newThread()) // 指定订阅者工作线程 .observeOn(AndroidSchedulers.mainThread()) .subscribe( s -> { Log.e("MainActivity", " ->Action1 call: " + s); Log.e("MainActivity", " -> Action1 call: thread" + Thread.currentThread()); }, throwable -> { Log.e("MainActivity", " ->Action1-Throwable call: " + throwable); Log.e("MainActivity", " -> Action1-Throwable call: thread" + Thread.currentThread()); }, () -> { Log.e("MainActivity", " ->Action0 call: "); Log.e("MainActivity", " -> Action0 call: thread" + Thread.currentThread()); }); just:同from类似,只是just的值是在()中指定的。 Observable.just(1, "3", true) // 按顺序发送三种不同类型的数据 // 订阅者的工作线程 .observeOn(Schedulers.newThread()) // 订阅 .subscribe( // 创建订阅者,范型是个可序列化对象。 new Subscriber<Serializable>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Serializable serializable) { if (serializable.equals(1)) { Log.e("MainActivity", " -> onNext: int = " + serializable.toString()); } if (serializable.equals("3")) { Log.e("MainActivity", " -> onNext: String = " + serializable.toString()); } if (serializable.equals(false)) { Log.e("MainActivity", " -> onNext: boolean = " + true); } } }); 输出结果: MainActivity: -> onNext: int = 1 MainActivity: -> onNext: String = 3 timer:在指定时间之后创建一个发射0的可观察者。 Observable.timer(2, TimeUnit.SECONDS) //通过timer创建延迟2s发射的可观察者,它会发射一个0 //指定订阅者的工作线程 .subscribeOn(Schedulers.newThread()) //订阅,并创建订阅者 .subscribe(new Subscriber<Long>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Long aLong) { Log.e("MainActivity", " -> onNext: along = " + aLong); } }); 变换操作符 变换操作符可以在发射过程中对发送的数据进行加工。 map:可在Observable发射前对初始的数据进行一次变换,通过Func1接口来进行。 Observable.just( "http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1503/17/c2/3974265_1426551589288_mthumb.jpg") .map(s -> { // 在这里使用map操作符,把String类型的数据转换成了Bitmap类型,继续往下传递 try { // 下载图片 URL url = new URL(s); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setDoInput(true); conn.setConnectTimeout(5000); conn.connect(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream is = conn.getInputStream(); byte[] bytes = new byte[1024]; ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); int length = 0; while ((length = is.read(bytes)) != -1) { byteBuffer.write(bytes, 0, length); byteBuffer.flush(); } byte[] bmpBytes = byteBuffer.toByteArray(); Log.e("MainActivity", " -> initData: byte.size = " + bmpBytes.length); return BitmapFactory.decodeByteArray(bmpBytes, 0, bmpBytes.length); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; }) .map(BitmapDrawable::new) // 这里再一次把Bitmap类型的数据转换成了Drawable往下传递 .subscribeOn(Schedulers.io()) // 指定可观察者工作线程 .observeOn(AndroidSchedulers.mainThread()) // 指定订阅者的工作线程 // 订阅 .subscribe( // 创建订阅者 new Subscriber<Drawable>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Drawable drawable) { displayImage.setImageDrawable(drawable); } }); flatMap:功能与map类似,但它返回的是一个Observable<转化类型>。 APIClient.getArticles() // 在调用OnNext()之前先调用这个方法,这里的OnNext()是由Retrofit去调用的。 .doOnNext(articles -> { Log.e("MainActivity", " -> initData: itemsSize = " + articles.items.size()); articles.items.remove(0); }) // 用上一个Observable返回的结果来创建一个新的Observable .flatMap(articles -> Observable.from(articles.items)) // 这里使用了from方法创建Observable // 指定接收者的工作线程 .observeOn(AndroidSchedulers.mainThread()) // 发射给订阅者 .subscribe( // 创建订阅者 new Subscriber<Articles.ItemsTestBean>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Articles.ItemsTestBean itemsTestBean) { Log.e("MainActivity", " -> onNext: item " + i++ + " = " + itemsTestBean.id); } }); 过滤操作符 filter:通过Func1接口来实现过滤掉数据源中不符合条件的数据。 Observable.just(1,2,3,4,5) //过滤出小于4的数据,并且发射它们 .filter(new Func1<Integer,Boolean>() { @Override public Boolean call(Integer item){ retrun (item<4); } }).subscribe(new Subscriber<Integer> (){ @Override public void onNext(Integer item) { System.out.println("Next: " + item); } @Override public void onError(Throwable error) { System.err.println("Error: " + error.getMessage()); } @Override public void onCompleted() { System.out.println("Sequence complete."); } }); first:只发射第一条数据,或者过滤出来的第一条数据。 Observable.just(1,2,3,4,5) //过滤出大于4的数据,并且发射只发射第一个数据 .first(new Func1<Integer,Boolean>() { @Override public Boolean call(Integer item){ retrun (item>4); } }).subscribe(new Subscriber<Integer> (){ @Override public void onNext(Integer item) { System.out.println("Next: " + item); } @Override public void onError(Throwable error) { System.err.println("Error: " + error.getMessage()); } @Override public void onCompleted() { System.out.println("Sequence complete."); } }); take:只发射前几条数据。 Observable.just(1,2,3,4,5) //只发射前3个数据 .take(3) .subscribe(new Subscriber<Integer> (){ @Override public void onNext(Integer item) { System.out.println("Next: " + item); } @Override public void onError(Throwable error) { System.err.println("Error: " + error.getMessage()); } @Override public void onCompleted() { System.out.println("Sequence complete."); } }); CoorChice的公众号

优秀的个人博客,低调大师

Android应用中MVP开发模式

所谓MVP(Model-View-Presenter)模式。是将APP的结构分为三层: view - UI显示层 view 层主要负责: 提供UI交互 在presenter的控制下修改UI。 将业务事件交由presenter处理。注意. View层不存储数据,不与Model层交互。 presenter - 逻辑处理层 presenter 层主要负责: 对UI的各种业务事件进行相应处理。也许是与Model层交互,也许自己进行一些计算,也许控制后台Task,Servic 对各种订阅事件进行响应,修改UI。 临时存储页面相关数据。注意. Presenter内不出现View引用。 model - 数据层 model层主要负责: 从网络,数据库,文件,传感器,第三方等数据源读写数据。 对外部的数据类型进行解析转换为APP内部数据交由上层处理。 对数据的临时存储,管理,协调上层数据请求。 如图示,里面的activity,presenter,model均为例子: mvp 将复杂的功能分割为各层内的小问题。各层内功能单一。这样易于功能修改拓展与Debug。解耦的设计,独立的模块,更有利于分工开发与测试。 Activity的异常重启 Activity会在少数情况下被系统重启: 当用户旋转屏幕在后台时内存不足改变语言设置 attache 一个外部显示器等。 正确的方式应该是:Presenter与Activity的绑定关系应由静态类管理。而不是由Activity管理。当Activity意外重启时Presenter不应重启。Activity重启时,Presenter与Activity重新绑定,根据数据恢复Activity状态。而当Activity真正销毁时。对应Presenter才应该跟随销毁。 当内存不足时,Activity被销毁其实是整个进程被销毁。所以Presenter也无能为力。还原时需要重建Presenter。 生命周期 Activity是一个上帝类,其实不适合作为View。所以有些MVP方案将Activity作为Presenter。最主要在于他的生命周期牵扯太多逻辑处理业务。这些由Presenter负责的话情况可以改善很多。我建议将在顶级父类中将activity的生命周期在Presenter中实现一遍,然后生命周期有关的业务逻辑直接由Presenter来实现。 Model的初始化 Model不仅仅是javabean。Model是负责提供各类数据模型。在此基础上我将Model拓展为数据层提供数据交互。将javabean单独为数据层的一部分。Model层的各个Model一般使用单例。这样的好处在于这个唯一对象可以管理一些数据供所有上层使用。Model的单例对象 public class UserModel extends AbsModel{ public static UserModel getInstance() { return getInstance(UserModel.class); } @Override protected void onAppCreate(Context ctx) { super.onAppCreate(ctx); //初始化 } public void login(String number,String password,DataCallback<UserDetail> callback){ //进行登录请求与回调,并保存返回账号 } public void register(String tel,String password,String code,int gender,String nickname,StatusCallback callback){ //进行注册请求与回调 } public void findPassword(String number,String code,String password,DataCallback<User> callback){ //进行找回密码请求与回调 } public void certification(String number,String school,String realName,String stuCard,DataCallback<User> callback){ //进行认证请求与回调 } public void LoginOut(){ //登出操作 } } 既然Model层管理数据,并且是单例。他就有初始化的需求,比如在APP启动时就请求数据,记录信息,开始一个后台线程与服务器同步信息等。这些操作与Presenter无关。是数据层自发的的功能。所以需要在Application启动时进行Model的初始化。但又要注意不能在Application的onCreate()进行过多操作,否则会启动时间过长。所以可考虑在启动时创建一个后台线程,将即时性不强的初始化操作放到后台线程。 Adapter的处理 对于Adapter是放在View好还是Presenter好,这个问题确实难以解决。但在使用解耦的ViewHolder后这个问题便很明了。视图的创建与改变全由ViewHolder管理。然后Adapter仅仅处理面向ViewHolder的逻辑。然后ViewHolder属于View,Adapter属于Presenter。参考EasyRecyclerViewAdapter: public class PersonAdapter extends RecyclerArrayAdapter<Person> { public PersonAdapter(Context context) { super(context); } @Override public BaseViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) { return new PersonViewHolder(parent); } } ViewHolder: public class PersonViewHolder extends BaseViewHolder<Person> { private TextView mTv_name; private SimpleDraweeView mImg_face; private TextView mTv_sign; public PersonViewHolder(ViewGroup parent) { super(parent,R.layout.item_person); mTv_name = $(R.id.person_name); mTv_sign = $(R.id.person_sign); mImg_face = $(R.id.person_face); } @Override public void setData(final Person person){ mTv_name.setText(person.getName()); mTv_sign.setText(person.getSign()); mImg_face.setImageURI(Uri.parse(person.getFace())); } } Rx的参与 Rx订阅发布模式在MVP中作用很大。可以极大简化层间通讯的处理。View向Presenter订阅数据。Presenter可以向Model层订阅数据。形成一个数据链。数据可以直接链式到达View层。优雅易拓展。Presenter public class QuestionShowPresenter extends BeamDataActivityPresenter<QuestionShowActivity,Question> { @Override protected void onCreate(QuestionShowActivity view, Bundle savedState) { super.onCreate(view, savedState); QuestionModel.getInstance().getQuestion(1).subscribe(this); } } View public class QuestionShowActivity extends BeamDataActivity<QuestionShowPresenter,Question> { @Override public void setData(Question data) { //显示数据 } @Override public void setError(Throwable e) { //显示错误 } } Beam Beam是我做的一套基于MVP模式的快速开发框架。参考了nucleus。上面的示例代码都是使用了这个(为方便复制的这个框架demo代码.= =)。定义了一套开发规范。并提供了基于这套规范的Activity,Fragment,Presenter,Model等父类及控件和API等,完成APP开发过程中大量繁琐工作。并进行了一系列优化。详情看这里 文/Jude95(简书作者) 原文链接:http://www.jianshu.com/p/ed2aa9546c2c 著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

用户登录
用户注册