本博客转自郭霖公众号:http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650236908&idx=1&sn=9e53f42e18a81795ef0cfe6fe3959ec2&scene=24&srcid=0910cK3vXJpNzY0CO28i1Qhs#wechat_redirect


什么是MVVM

说到DataBinding,就有必要先提起MVVM设计模式。
Model–View–ViewModel(MVVM) 是一个软件架构设计模式,相比MVVM,大家对MVC或MVP可能会更加熟悉。

  • MVC:(VIew-Model-Controller)
    早期将VIew、Model、Controller代码块进行划分,使得程序大部分分离,降低耦合。
  • MVP:(VIew-Model-Presenter)由于MVC中View和Model之间的依赖太强,导致Activity中的代码过于臃肿。为了他们可以绝对独立的存在,慢慢演化出了MVP。在MVP中View并不直接使用Model,它们之间的通信是通过 Presenter (MVC中的Controller)来进行的。
  • MVVM:(Model–View–ViewModel)
    MVVM可以算是MVP的升级版,将 Presenter 改名为 ViewModel。关键在于View和Model的双向绑定,当View有用户输入后,ViewModel通知Model更新数据,同理Model数据更新后,ViewModel通知View更新。

Data Binding

在Google I/O 2015上,伴随着Android M预览版发布的Data Binding兼容函数库。
不知道要扯什么了,还是直接上代码,来看看Data Binding的魅力吧。

  • 环境要求

    Data Binding对使用的环境还是有一定要求的(这货有点挑)
    Android Studio版本在1.3以上
    gradle的版本要在1.5.0-alpha1以上
    需要在Android SDK manager中下载Android Support repository
    然后在对应的Module的build.gradle中添加

    android {
    ....
    dataBinding {
    enabled =true
    }
    }

    Gradle需要升级版本的可以参考升级Gradle版本

  • 创建对象

    创建一个User类

    public class User {
    private String firstName;
    private String lastName; public User(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    } public String getFirstName() {
    return this.firstName;
    } public String getLastName() {
    return this.lastName;
    } public void setLastName(String lastName) {
    this.lastName = lastName;
    } public void setFirstName(String firstName) {
    this.firstName = firstName;
    }
    }
  • 布局

    在activity_main.xml中布局

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
    <import type="com.example.gavin.databindingtest.User"/>
    <variable
    name="user"
    type="User" />
    </data>
    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    >
    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstName}"
    android:textSize="20sp" />
    <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.lastName}"
    android:textSize="25sp" />
    </LinearLayout>
    </layout>

    这里跟平时的布局有点不同,最外层是layout,里面分别是是data以及我们的布局。
    data:声明了需要用到的user对象,type用于是定路径。
    可以在TextView中的看到android:text="@{user.firstName}", 这是什么鬼,没见过这么写的!!!
    (不急,继续往下看)

  • 绑定数据

    看看下面的MainActivity

    public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    User user = new User("Micheal", "Jack");
    binding.setUser(user);
    }
    }

    问我ActivityMainBinding哪来的?我怎么知道...
    ActivityMainBinding是根据布局文件的名字生成的,在后面加了Binding。
    运行下看看效果吧

    效果

有点懵逼了,就绑定了下而已,这些数据是怎么显示到界面上的。

懵逼

他是怎么工作的?
原来Data Binding 在程序代码正在编译的时候,找到所有它需要的信息。然后通过语法来解析这些表达式,最后生成一个类。
通过反编译我们可以看到,Data Binding为我们生成了databinding包,以及ActivityMainBinding类(反编译可以参考这里

 

看看我们在onCreate中最后调用的binding.setUser(user),在ActivityMainBinding中可以看到这个方法。

setUser方法

我想就是这个 super.requestRebind()对数据进行了绑定,至于里面怎么实现的,有待进一步研究。

更多用法

上面只是用一个简单的例子,展示了Data Binding的用法,如果想在实际项目中使用,可不是上面这例子可以搞定的。下面就来说说Data Bindig的更多用法。

  • 首先消除下大家对空指针的顾虑

    自动生成的 DataBinding 代码会检查null,避免出现NullPointerException。
    例如在表达式中@{user.phone}如果user == null 那么会为user.phone设置默认值null而不会导致程序崩溃(基本类型将赋予默认值如int为0,引用类型都会赋值null)

  • 自定义DataBinding名

    如果不喜欢自动生成的Data Binding名,我们可以自己来定义

    <data class="MainBinding">
    ....
    </data>

    class对应的就是生成的Data Binding名

  • 导包

    跟Java中的用法相似,布局文件中支持import的使用,原来的代码是这样

    <data>
    <variable name="user" type="com.example.gavin.databindingtest.User" />
    </data>

    使用import后可以写成这样:

      <data>
    <import type="com.example.gavin.databindingtest.User"/>
    <variable
    name="user"
    type="User" />
    </data>

    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    遇到相同的类名的时候:

    <data>
    <import type="com.example.gavin.databindingtest.User" alias="User"/>
    <import type="com.example.gavin.mc.User" alias="mcUser"/>
    <variable name="user" type="User"/>
    <variable name="mcUser" type="mcUser"/>
    </data>

    使用alias设置别名,这样user对应的就是com.example.gavin.databindingtest.User,mcUser就对应com.example.gavin.mc.User,然后

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.firstName}"/>

    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    当需要用到一些包时,在Java中可以自动导包,不过在布局文件中就没有这么方便了。需要使用import导入这些包,才能使用。如,需要用到View的时候

    <data>
    <import type="android.view.View"/>
    </data>
    ...
    <TextView
    ...
    android:visibility="@{user.isStudent ? View.VISIBLE : View.GONE}"
    />

    注意只要是在Java中需要导入包的类,这边都需要导入,如:Map、ArrayList等,不过java.lang包里的类是可以不用导包的

  • 表达式

    在布局中,不仅可以使用

    android:text="@{user.lastName}"

    还可以使用表达式如:

    三元运算

    在User中添加boolean类型的isStudent属性,用来判断是否为学生。

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text='@{user.isStudent? "Student": "Other"}'
    android:textSize="30sp"/>

    注意需要用到双引号的时候,外层的双引号改成单引号。
    还可以这样用

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="学生"
    android:visibility="@{user.isStudent ? View.VISIBLE : View.GONE}"
    android:textSize="30sp"/>

    这里用到的View需要在data中声明

    <data>
    <import type="android.view.View"/>
    </data>

    注意:android:visibility="@{user.isStudent ? View.VISIBLE : View.GONE}",可能会被标记成红色,不用管它编译会通过的

    ??

    除了常用的操作法,另外还提供了一个 null 的合并运算符号 ??,这是一个三目运算符的简便写法。

    contact.lastName ?? contact.name

    相当于

    contact.lastName != null ? contact.lastName : contact.name

    所支持的操作符如下:
    数学运算符 + - / * %
    字符串拼接 +
    逻辑运算 && ||
    二进制运算 & | ^
    一元运算符 + - ! ~
    位运算符 >> >>> <<
    比较运算符 == > < >= <=
    instanceof
    Grouping ()
    文字 - character, String, numeric, null
    类型转换 cast
    方法调用 methods call
    字段使用 field access
    数组使用 [] Arrary access
    三元运算符 ? :

  • 显示图片

    除了文字的设置,网络图片的显示也是我们常用的。来看看Data Binding是怎么实现图片的加载的。
    首先要提到BindingAdapter注解,这里创建了一个类,里面有显示图片的方法。

    public class ImageUtil {
    /**
    * 使用ImageLoader显示图片
    * @param imageView
    * @param url
    */
    @BindingAdapter({"bind:image"})
    public static void imageLoader(ImageView imageView, String url) {
    ImageLoader.getInstance().displayImage(url, imageView);
    }
    }

    (这方法必须是public static的,否则会报错)
    这里只用了bind声明了一个image自定义属性,等下在布局中会用到。
    这个类中只有一个静态方法imageLoader,里面有两参数,一个是需要设置图片的view,另一个是对应的Url,这里使用了ImageLoader库加载图片。
    看看吧它的布局是什么样的吧

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"> <data >
    <variable
    name="imageUrl"
    type="String"/>
    </data> <LinearLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    >
    <ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:image = "@{imageUrl}"/>
    </LinearLayout>
    </layout>

    最后在MainActivity中绑定下数据就可以了

    binding.setImageUrl(
    "http://115.159.198.162:3000/posts/57355a92d9ca741017a28375/1467250338739.jpg");

    哇靠!!!就这样?我都没看出来它是怎么设置这些图片的。
    不管了,先看看效果。(其中的原理以后慢慢唠,这里就负责说明怎么使用,这篇已经够长了,不想再写了)

    看个美女压压惊

    使用BindingAdapter的时候,我这还出现了这样的提示,不过不影响运行。不知道你们会不会...

     

    【已解决】
    感谢颜路同学指出@BindingAdapter({"bind:image"}) 改成
@BindingAdapter({"image"}) 就不会有警告了

  • 点击事件

    在MainActivity中声明方法:

    //参数View必须有,必须是public,参数View不能改成对应的控件,只能是View,否则编译不通过
    public void onClick(View view) {
    Toast.makeText(this,"点击事件", Toast.LENGTH_LONG).show();
    }

    布局中:

      <data>
    ...
    <variable
    name="mainActivity"
    type="com.example.gavin.databindingtest.MainActivity"/>
    </data>
    ....
    <Button
    ...
    android:onClick="@{mainActivity.onClick}"
    />

    最后记得在MainActivity中调用

    binding.setMainActivity(this);

    (发现:布局文件中,variable中的name,在binding中都会生成一个对应的set方法,如:setMainActivity。有set方法,那就应该有get方法,试试getMainActivity,还真有)
    运行下看看效果

    点击事件

    当然如果你不想吧点击事件写在MainActivity中,你把它单独写在一个类里面:

    public class MyHandler {
    public void onClick(View view) {
    Toast.makeText(view.getContext(), "点击事件", Toast.LENGTH_LONG).show();
    }
    }
      <data>
    ...
    <variable
    name="handle"
    type="com.example.gavin.databindingtest.MyHandler"/>
    </data>
    ....
    <Button
    ...
    android:onClick="@{handle.onClick}"
    />
    </data>

    在MainActivity调用

    binding.setHandle(new MyHandler());
  • 调用Activity中的变量

    上面看到它调用MainActivity中的onClick方法,那么可以调用MainActivity中的属性吗?
    在MainActivity中定义mName,

    public static String mName = "MM";

    布局中

      <data>
    ...
    <variable
    name="mainActivity"
    type="com.example.gavin.databindingtest.MainActivity"/>
    </data>
    <Button
    ...
    android:text="@{mainActivity.mName}"
    />

    注意这个变量必须是public static

  • 数据改变时更新UI

    当数据发生变化时,我们可以这样更新UI

      private ActivityMainBinding binding;
    private User user;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    user = new User("Micheal", "Jack");
    binding.setUser(user);
    binding.setHandle(new MyHandler());
    delay();
    }
    /**
    * 两秒后改变firstName
    */
    private void delay() {
    new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
    user.setFirstName("Com");
    binding.setUser(user);
    }
    }, 2000);
    }

    看看调用的这个setUser是什么:

    setUser

    从反编译的代码中可以看出,setUser方法中重新绑定了数据。
    看下效果

效果
  • BaseObservable

    使用上面的代码实现了UI的更新你就满足了?其实官方为我们提供了更加简便的方式,使User继承BaseObservable,代码如下

    public class User extends BaseObservable {
    private String firstName;
    private String lastName; public User(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    }
    @Bindable
    public String getFirstName() {
    return this.firstName;
    }
    @Bindable
    public String getLastName() {
    return this.lastName;
    } public void setLastName(String lastName) {
    this.lastName = lastName;
    notifyPropertyChanged(BR.lastName);
    } public void setFirstName(String firstName) {
    this.firstName = firstName;
    notifyPropertyChanged(BR.firstName);
    }
    }

    只要user发生变化,就能达到改变UI的效果。在MainActivity中只要调用以下代码

    user.setFirstName("Com");

    有了BaseObservable就够了?不不不,我比较懒,不想写那么多@Bindable和notifyPropertyChanged。万一里面有几十个属性,那不写哭起来?而且还有可能写丢了。
    Data Binding的开发者贴心得为我们准备了一系列的ObservableField,包括: ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat,ObservableDouble, 以及 ObservableParcelable看看它们的用法
    ObservableField的使用
    1、创建User2

    public class User2 {
    public final ObservableField<String> firstName = new ObservableField<>();
    public final ObservableField<String> lastName = new ObservableField<>();
    public final ObservableInt age = new ObservableInt();
    public final ObservableBoolean isStudent = new ObservableBoolean();
    }

    这类里面没有Get/Set。
    2、布局文件

          <TextView
    ...
    android:text="@{user2.firstName}" />
    <TextView
    ...
    android:text="@{user2.lastName}" />
    <TextView
    ...
    android:text="@{String.valueOf(user2.age)}"
    />

    3、MainActivity中

          mUser2 = new User2();
    binding.setUser2(mUser2);
    mUser2.firstName.set("Mr");
    mUser2.lastName.set("Bean");
    mUser2.age.set(20);
    mUser2.isStudent.set(false);

    这里new了一个User2对象后,直接就绑定了。之后只要mUser2中的数据发生变化,UI也会随之更新。
    除了这几个Map跟List也是必不可少的,Data Binding为我们提供了 ObservableArrayMapObservableArrayList
    ObservableArrayMap的使用

    ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
    user.put("firstName", "Google");
    user.put("lastName", "Inc.");
    user.put("age", 17);
    <data>
    <import type="android.databinding.ObservableMap"/>
    <variable name="user" type="ObservableMap<String, Object>"/>
    </data>

    <TextView
    android:text='@{user["lastName"]}'
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
    <TextView
    android:text='@{String.valueOf(1 + (Integer)user["age"])}'
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

    ObservableArrayList的使用

    ObservableArrayList<Object> user = new ObservableArrayList<>();
    user.add("Google");
    user.add("Inc.");
    user.add(17);
    <data>
    <import type="android.databinding.ObservableList"/>
    <import type="com.example.my.app.Fields"/>
    <variable name="user" type="ObservableList<Object>"/>
    </data>

    <TextView
    android:text='@{user[Fields.LAST_NAME]}'
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
    <TextView
    android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

    在布局中使用中文时,编译无法通过。

    android:text='@{user2.isStudent?"学生":"非学生"}'

    感谢吕檀溪同学的解决方案:
    这是java环境的问题,在系统环境变量中增加一个变量,变量名为: JAVA_TOOL_OPTIONS, 变量值为:-Dfile.encoding=UTF-8,保存。要重启一次电脑,中文就解决了,但是在某些地方,编译的时候控制台会出现部分乱

  • 在RecyclerView或ListView中使用

    前面说了那么多基础的用法,可还是不能达到我们的需求。几乎在每个app中都有列表的存在,RecyclerView或ListView,从上面所说的似乎还看不出Data Binding在RecyclerView或ListView中是否也能起作用。(用屁股想也知道,Google的开发团对怎么可能会犯这么低级的错误)。下面以RecyclerView为例子:
    1、直接看Item的布局(user_item.xml):

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
    <variable
    name="user2"
    type="com.example.gavin.databindingtest.User2" />
    </data>
    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:orientation="horizontal">
    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user2.firstName}"/>
    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="·"/>
    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user2.lastName}"/>
    <View
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_weight="1"/>
    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text='@{user2.age+""}'/>
    </LinearLayout>
    </layout>

    2、RecyclerView的数据绑定是在Adapter中完成的,下面看看Adapter(这里使用了一个Adapter,如果你在使用的时候发现RecyclerView的动画没了,去这里寻找答案)

    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
    
      private List<User2> mData = new ArrayList<>();
    
      public MyAdapter(List<User2> data) {
    this.mData = data;
    } @Override
    public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return MyHolder.create(LayoutInflater.from(parent.getContext()), parent);
    } @Override
    public void onBindViewHolder(MyHolder holder, int position) {
    holder.bindTo(mData.get(position));
    } @Override
    public int getItemCount() {
    if (mData == null)
    return 0;
    return mData.size();
    } static class MyHolder extends RecyclerView.ViewHolder {
    private UserItemBinding mBinding; static MyHolder create(LayoutInflater inflater, ViewGroup parent) {
    UserItemBinding binding = UserItemBinding.inflate(inflater, parent, false);
    return new MyHolder(binding);
    } private MyHolder(UserItemBinding binding) {
    super(binding.getRoot());
    this.mBinding = binding;
    } public void bindTo(User2 user) {
    mBinding.setUser2(user);
    mBinding.executePendingBindings();
    } }
    }

    3、最后在布局和MainActivity中的使用跟平时的用法一样
    布局中加入RecyclerView:

          <android.support.v7.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

    MainActivity中:

          List<User2> data = new ArrayList<>();
    for (int i = 0; i < 20; i++) {
    User2 user2 = new User2();
    user2.age.set(30);
    user2.firstName.set("Micheal " + i);
    user2.lastName.set("Jack " + i);
    data.add(user2);
    }
    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    LinearLayoutManager layoutManager = new LinearLayoutManager(
    this, LinearLayoutManager.VERTICAL, false);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(new MyAdapter(data));

    这样就可以了。
    不过,在自动生成的ActivityMainBinding中,我们可以看到根据RecyclerView的id,会自动生成一个recyclerView。

     

    所以在MainActivity中,我们可以不用findViewById,直接使用binding.recyclerView。

          LinearLayoutManager layoutManager = new LinearLayoutManager(
    this, LinearLayoutManager.VERTICAL, false);
    binding.recyclerView.setLayoutManager(layoutManager);
    binding.recyclerView.setAdapter(new MyAdapter(data));

    来看看效果吧:

    RecyclerView

Tips:

  • tip1:若需要显示int类型,需要加上"":如

    user.age为int类型,需要这样用

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text='@{""+user.age}'/>

    或者

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{String.valueOf(user.age)}"/>
  • tip2:不建议新手使用,出现错误的时候根据提示,不容易找到出错位置。(是根本找不到...)

参考

Google官方(权威,不过全英文。点击事件写的好像不对,后来去其他地方查的):
Realm(十分全面):
CSDN-亓斌(有点像google文档的翻译版,整体结果相似):
阳春面的博客(好奇怪的名字)

源码地址https://github.com/Gavin-ZYX/DataBindingTest

文/带心情去旅行(简书作者)
原文链接:http://www.jianshu.com/p/5dcdc5798d85
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

设计模式笔记之三:Android DataBinding库(MVVM设计模式)的更多相关文章

  1. Android DataBinding库(MVVM设计模式)

    什么是MVVM 说到DataBinding,就有必要先提起MVVM设计模式.Model–View–ViewModel(MVVM) 是一个软件架构设计模式,相比MVVM,大家对MVC或MVP可能会更加熟 ...

  2. Asp.net设计模式笔记之三:业务逻辑层的组织

    本章内容要点: 1.Transaction Script模式组织业务逻辑 2.Active Record模式和Castle Windsor来组织业务逻辑 3.Domain Model模式来组织业务逻辑 ...

  3. PHP设计模式笔记三:三种基本设计模式(工厂模式、单例模式、注册树模式) -- Rango韩老师 http://www.imooc.com/learn/236

    一.工厂设计模式 index.php $db = IMooc\Factory::createDatabase(); 使用工厂类的静态方法直接创建一个dababase对象,当类名发生修改时,在工厂里修改 ...

  4. 浅析设计模式之mvc、mvp、mvvm

    mvc.mvvm.mvp是常见的设计模式,也是常见的设计思想,现对它们进行简要的归纳总结 三种模式的介绍 1.MVC:经典设计模式 View 传送指令到 Controller(控制器) Control ...

  5. java I/O库的设计模式

    在java语言 I/O库的设计中,使用了两个结构模式,即装饰模式和适配器模式.      在任何一种计算机语言中,输入/输出都是一个很重要的部分.与一般的计算机语言相比,java将输入/输出的功能和使 ...

  6. MVVM设计模式和WPF中的实现(四)事件绑定

    MVVM设计模式和在WPF中的实现(四) 事件绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...

  7. 理解MVC,MVP和MVVM设计模式

    有3个非常受欢迎的MV-*系列设计模式:MVC,MVP,MVVM.他们被广泛应用于不多种结束.这篇文章我回阐述我自己对这3个设计模式的看法. MVC模式: MVC即Model-VIew-Control ...

  8. 浅谈 MVVM 设计模式在 Unity3D 中的设计与实施

    初识 MVVM 谈起 MVVM 设计模式,可能第一映像你会想到 WPF/Sliverlight,他们提供了的数据绑定(Data Binding),命令(Command)等功能,这让 MVVM 模式得到 ...

  9. [设计模式] .NET设计模式笔记 - 了解设计模式

    今天在TerryLee的cnblog(http://terrylee.cnblogs.com)里看到了与设计模式相关的整套文章,初学设计模式看完每篇文章后做些笔记和摘抄. ●什么是设计模式,什么是架构 ...

随机推荐

  1. RESTful架构2--架构详解

    转自:RESTful架构详解 1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在200 ...

  2. html/css技巧总结

    .e-select .on{display:none} on为e-select的子元素,(之间有空格).e-select.on{display:block} 只有两种属性同时存在时才会起作用(之间无空 ...

  3. hdu_5695_Gym Class(拓扑排序)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5695 题意:中文题,不解释 题解:逆向拓扑字典序就行 #include<cstdio> # ...

  4. 命令 shell 学习

    for i in a b c do echo $i done !ser  历史补全 > 正确信息输出文件 >>正确信息输出文件  ,追加 2>错误信息输出文件 2>> ...

  5. Bank Interest

    Bank Interest Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Tota ...

  6. sublime Text 常用操作

    原文出处:http://www.php100.com/html/it/focus/2014/1030/7666.html 1. 多光标操作:只要按下Cmd(Windows系统下Ctrl)键,再用鼠标选 ...

  7. Linux查看CPU和内存使用情况 【转】

    Linux查看CPU和内存使用情况 在系统维护的过程中,随时可能有需要查看 CPU 使用率,并根据相应信息分析系统状况的需要.在 CentOS 中,可以通过 top 命令来查看 CPU 使用状况.运行 ...

  8. phonegap的照相机API

    1. Camera Api简单介绍 2. 拍照 3. 预览照片 一. Camera Api简单介绍 Camera选择使用摄像头拍照,或从设备相册中获取一张照片.图片以base64编码的 字符串或图片U ...

  9. hibernate ——helloWorld程序(annotation配置)

    在  <hibernate  ——helloWorld程序(XML配置)>基础上,修改.添加部分文件: 1.Teacher类和Teacher表 package com.pt.hiberna ...

  10. Spring AOP面向切面编程的实现

    1.涉及到的几个概念 切面类.被切对象.切入点.切入时间.切入内容:(自己命的名,好理解点) 2.看配置文件 <?xml version="1.0" encoding=&qu ...