Web和Android中的Reactive

Posted IVWEB社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web和Android中的Reactive相关的知识,希望对你有一定的参考价值。


导语 笔者刚入行的时候,做的是android客户端开发。虽然从事的时间不长,但稍微了解一点基本的概念。后来阴差阳错从事Web开发,一直到现在,所以现在多多少少对Web领域有一丁点的见解。因为这样,所以有时候会思考下二者的共性,想找一下二者相同的点。最近有两个问题,

缘起

笔者刚入行的时候,做的是Android客户端开发。虽然从事的时间不长,但稍微了解一点基本的概念。后来阴差阳错从事Web开发,一直到现在,所以现在多多少少对Web领域有一丁点的见解。因为这样,所以有时候会思考下二者的共性,想找一下二者相同的点。最近有两个问题,一直萦绕着:

  1. React中有 stateprops的概念。组件 component的显示,数据的体现 大部分都是由state承载,props传递。而android基本都是通过 setXX去控制组件和数据。为什么会有这样的差异?
  2. 同时, redux等状态管理组件都是  flux架构的实现,也有很多开发者提出 FluxAndroid的概念,但google官方并不承认flux的架构。这是为什么?

Android开发中的常见写法

我们经常看到这样的写法,首先在xml文件中定义我们的布局文件,指定id等属性。

<TextView android:text="@string/hello_world" android:id="@+id/textview" android:layout_width="wrap_content"          android:layout_height="wrap_content" />

同时,在Activity中通过findViewById去获取控件的引用,然后进行一系列操作,比如setText

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.textview); TextView textView = new TextView(this); textView.setText("Hey, one more TextView");    }

除此之外,我们还经常看见这样的写法,比如:

setVisibility(View.VISIBLE);
imageview.setBackgroundColor(Color.rgb(213, 0, 0));

你有没有发现,这些写法有一个共性,就是都是通过setXXX去设定值。也就是说,我们开发者在操作的时候,有这样的一个模式:

  1. 获取到值(不管是从数据库还是网络拉取)
  2. 这个值经过处理,得到可以目标控件需要的值
  3. 通过 setXXX去设定该值
  4. 然后界面发生变化

后来我发现,这样的模式在JQuery中也是类似的。

JQuery中的常见写法

先看下这段代码。

<!DOCTYPE html><html lang="en"><head> <title>learn jQuery</title></head><body>
<h1>例子1</h1> <p>如果你点我,我就会消失。</p> <p>继续点我!</p> <p>接着点我!</p>
<script src="jquery-3.3.1.js"></script> <script type="text/javascript"> //例子1 $(document).ready(function () { console.log("document is ready"); $("p").click(function () { $(this).hide(); }); });</script></body></html>

首先,我们先写了四行HTML代码。然后,通过JQuery去操作,注意我们的操作方式。

我们通过$("p") 去获取document对象中的<p></p>元素,这是不是很像刚刚在上一节提到的findViewById,有木有?

获取到元素后,通过$(this).hide()对该元素进行操作。这像不像textView.setText("Hey, one more TextView");


如果觉得这段代码不直观,来看这个。

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Evan JQery</title> <script src="jquery-3.3.1.js"></script> <script> $(document).ready(function(){ $("#btn1").click(function(){ $("#test1").text("Hello world!"); }); $("#btn2").click(function(){ $("#test2").html("<b>Hello world!</b>"); }); $("#btn3").click(function(){ $("#test3").val("Dolly Duck"); }); });</script></head><body><p id="test1">这是段落。</p><p id="test2">这是另一个段落。</p><p>Input field: <input type="text" id="test3" value="Mickey Mouse"></p><button id="btn1">设置文本</button><button id="btn2">设置 HTML</button><button id="btn3">设置值</button>
</body></html>

同时,你可以在本地打开上面的代码,在浏览器中预览,然后打开开发者模式,在控制台中输入,

$("#test3").val("Dolly Ducrrrrk");

你会发现网页内容也随之发生了改变。

命令式编程

维基百科这样说:

Imperative programming is a programming paradigm that uses statements that change a program’s state.

简单理解,命令式编程,就是命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。

上述了两小节都是命令式编程。

声明式编程

提到命令式编程,不得不说下声明式编程。

声明式编程,就是告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。

打个比方:

Declarative Programming is like asking your friend to draw a landscape. You don’t care how they draw it, that’s up to them. Imperative Programming is like your friend listening to Bob Ross tell them how to paint a landscape. While good ole Bob Ross isn’t exactly commanding, he is giving them step by step directions to get the desired result.

声明式就像你告诉你朋友画一幅画,你不用去管他怎么画的细节

命令式就像按照你的命令,你朋友一步步把画画出来

如果你觉得有点分不清楚二者区别,别着急,先看下下面的案例。

React中的常见写法

'use strict';
const e = React.createElement;
class LikeButton extends React.Component { //https://www.cnblogs.com/johnzhu/p/9016277.html constructor(props) { super(props); this.state = { liked: false }; }
render() { if (this.state.liked) { return 'You liked this.'; }
return e( 'button', { onClick: () => this.setState({ liked: true }) }, 'Like' ); }}
const domContainer = document.querySelector('#like_button_container');ReactDOM.render(e(LikeButton), domContainer);

React是声明式的,以上就是体现声明式很好的例子。

在我们的render方法中,渲染一个按钮,按钮名字为“Like”。

按钮的状态(也就是文字内容)受state控制,初始化的state为一个JavaScript对象。

this.state = { liked: false };

点击按钮之后,触发事件,改变state

{ onClick: () => this.setState({ liked: true }) }

好,state在点击前后发生改变,按钮的文字是由state控制。换句话说,我们并没有直接操作DOM去改变按钮的文字内容,只是通过改变state的状态。而state不同的值描述了按钮在不同情况下应该如何表现不同的内容。

The differences here may be subtle. The React example never actually touches an element. it simply declares an element should be rendered given our current state. It does not actually manipulate the DOM itself.

和命令式的区别有点模糊。React没有直接操作元素,它只是声明了元素如何在给定的状态下渲染出特定的结果。

所以,React的思想和JQuery有很大不同。

When writing React, it’s often good not to think of how you want to accomplish a result, but instead what the component should look like in it’s new state.

使用React的时候,最好不同去想着如何实现某个结果,而是组件在新的状态下应该有什么样的表现。


歇一口气 ^ __ ^ 歇一口气


Vue的常见写法

看了React的写法,知道它是声明式,那我们来看看Vue是如何体现响应式的。

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>VueTest -- evan</title></head><body>
<div id="app"> <h2>{{product}} are in stock</h2> </div>
<script ></script> <script>
const app = new Vue({ el: '#app', /*element的缩写*/ data: { product: 'Boots' } })
</script>
</body></html>

我们在模板中指定

<h2>{{product}} are in stock</h2>

然后再Vue实例中只要product有值,立马就渲染出来。

为了更好的演示,请你打开上述代码,在浏览器中预览,然后打开控制台。输入

app.product = 'you input here'

你就会发现屏幕上的网页渲染立马发生了改变。

这就是响应式。

Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。

来我们简单解释下 Vue 响应式系统的底层细节。

第一,还记得我们通过下面的代码,把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项。

 const app = new Vue({ el: '#app', /*element的缩写*/ data: { product: 'Boots' } })

Vue 将遍历此对象所有的属性。

第二,Vue使用 Object.defineProperty 把这些属性全部转为 getter/setter。

第三,每个Vue Component的render函数,都都对应一个 watcher 实例。

第四,当 Vue Component render 函数被执行的时候, data 上会被 触碰(touch), 即被读, getter 方法会被调用, 此时 Vue 会去记录此 Vue component 所依赖的所有 data。(这一过程被称为依赖收集)。

第五,data 被改动时(主要是用户操作), 即被写, setter 方法会被调用, 此时 Vue 会去通知所有依赖于此 data 的组件去调用他们的 render 函数进行更新。

你肯定熟悉响应式

还记当时风靡一时的RxJavaRxAndroid嘛?如今又有了RxKotlin,RxDart。(提醒和我一样,做过Android开发的同学们,哈哈~) 他们都是ReactiveX家族的一员。

Web和Android中的Reactive

试着回答

React中有stateprops的概念。组件component的显示,数据的体现 大部分都是由state承载,props传递。而android基本都是通过setXX去控制组件和数据。为什么会有这样的差异?

个人愚见,Android客户端和Web开发中,有这么几点不同:

  1. Android的界面UI是有XML标签定义,和DOM有些不同。

  2. 浏览器刷新的时候,整个DOM结构都会更新,而Android没有刷新整个页面的概念,在Android中,你是通过measure(测量)、layout (定位)、draw (绘制)去显示一个View

  3. 不同于React中的Component,Android中的View,比如ImageViewTextView本身内置了很多方法来控制自身属性,比如setBackgroundsetText

  4. (欢迎大佬斧正、补充)


redux等状态管理组件都是 flux架构的实现,也有很多开发者提出FluxAndroid的概念,但google官方并不承认flux的架构。这是为什么?

先简单说明下,Android的架构。

Android架构合集 这篇文章中列举了很多Android架构,包括官方google的,同时也有Flux架构模式。

很多开发者受Flux的启发,写了适用Android的Flux架构模式。比如下面几篇文章。

AndroidFlux ——当ANDROID遇到了FLUX,架构ANDROID应用的新方式。Flux Architecture on Android

RxFlux Android Architecture

Flux Android Architecture Components using Kotlin

这个问题我还没有很好的答案。我自己以Flux的架构模式去做过了Android的实践,由于Android Activity等自身的组件,使得用Flux架构反而比较繁琐,有点过度设计的味道。但究竟为何Google官方不推荐,欢迎大家补充~

彩蛋

这就是 Dan 所说的,React 并不是完全的响应式设计的意思。React 需要你手动跟踪应用数据,并在数据变化时告诉 React,这也意味着你得做更多工作。

难道这就是Vue这个响应式框架近几年越来越流行的原因?

放出彩蛋,就是svelte

参考

Imperative programming —维基百科

Declarative vs Imperative Programming —Ian Mundy

声明式和命令式 —小猪ab

Reactivity in Depth —Vue官方文档

Vue 响应式原理白话版

React 不是真正的响应式编程,Svelte 才是 —Ovie Okeh



以上是关于Web和Android中的Reactive的主要内容,如果未能解决你的问题,请参考以下文章

如何从Android中的片段单击按钮打开片段

Spring boot加载REACTIVE程序过程

片段中的 Android 相机预览

如何在android中的地图片段内中心线性布局?

片段中gridview的Android文本和图像适配器

Android - 片段中的 getIntent()