设计模式笔记之三:Android DataBinding库(MVVM设计模式)
本博客转自郭霖公众号: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、创建User2public 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为我们提供了 ObservableArrayMap和ObservableArrayList。
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设计模式)的更多相关文章
- Android DataBinding库(MVVM设计模式)
什么是MVVM 说到DataBinding,就有必要先提起MVVM设计模式.Model–View–ViewModel(MVVM) 是一个软件架构设计模式,相比MVVM,大家对MVC或MVP可能会更加熟 ...
- Asp.net设计模式笔记之三:业务逻辑层的组织
本章内容要点: 1.Transaction Script模式组织业务逻辑 2.Active Record模式和Castle Windsor来组织业务逻辑 3.Domain Model模式来组织业务逻辑 ...
- PHP设计模式笔记三:三种基本设计模式(工厂模式、单例模式、注册树模式) -- Rango韩老师 http://www.imooc.com/learn/236
一.工厂设计模式 index.php $db = IMooc\Factory::createDatabase(); 使用工厂类的静态方法直接创建一个dababase对象,当类名发生修改时,在工厂里修改 ...
- 浅析设计模式之mvc、mvp、mvvm
mvc.mvvm.mvp是常见的设计模式,也是常见的设计思想,现对它们进行简要的归纳总结 三种模式的介绍 1.MVC:经典设计模式 View 传送指令到 Controller(控制器) Control ...
- java I/O库的设计模式
在java语言 I/O库的设计中,使用了两个结构模式,即装饰模式和适配器模式. 在任何一种计算机语言中,输入/输出都是一个很重要的部分.与一般的计算机语言相比,java将输入/输出的功能和使 ...
- MVVM设计模式和WPF中的实现(四)事件绑定
MVVM设计模式和在WPF中的实现(四) 事件绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...
- 理解MVC,MVP和MVVM设计模式
有3个非常受欢迎的MV-*系列设计模式:MVC,MVP,MVVM.他们被广泛应用于不多种结束.这篇文章我回阐述我自己对这3个设计模式的看法. MVC模式: MVC即Model-VIew-Control ...
- 浅谈 MVVM 设计模式在 Unity3D 中的设计与实施
初识 MVVM 谈起 MVVM 设计模式,可能第一映像你会想到 WPF/Sliverlight,他们提供了的数据绑定(Data Binding),命令(Command)等功能,这让 MVVM 模式得到 ...
- [设计模式] .NET设计模式笔记 - 了解设计模式
今天在TerryLee的cnblog(http://terrylee.cnblogs.com)里看到了与设计模式相关的整套文章,初学设计模式看完每篇文章后做些笔记和摘抄. ●什么是设计模式,什么是架构 ...
随机推荐
- 用js 将long类型转换成日期格式
//扩展Date的format方法 Date.prototype.format = function (format) { var o = { "M+": this.getMont ...
- 认识cookie与session的区别与应用
通常我们所说的浏览器自动保存密码,下次不用登陆,网页换皮肤,用户引导,提示一次就不再出现的内容,大部分通过cookie或者session来实现的,在这次制作用户引导中,本人就用到了cookie的内容, ...
- Away 3d 基本属性
出处:http://blog.sina.com.cn/s/blog_59f0ac9d0101ci2j.html View3D在初始化时候就已经创建的Camera3D 所以有时候没有创建Camera3D ...
- 一个小知识点强引用__strong 弱引用__weak
__weak的类型的指针是不会影响对象的释放 当系统释放后 会自动的指向nil: __Strong 至少有一个__Strong类型的指针是 对象不会释放
- linux CTRL+Z
关于 linux 系统中使用ctrl+Z 的使用 (1) CTRL+Z停止进程并放入后台 (2) jobs 显示当前暂停的进程 (3) bg %N 使第N个任务在后台运行(%前有空格) ,N 为任务号 ...
- postgres 数据库备份恢复
postgre 数据库备份恢复命令 备份:pg_dump -U postgres -v -F c -Z 4 -f ***.backup dbname 9压缩率最狠恢复:pg_restore -U p ...
- pci 相关资料
1.http://www.cnblogs.com/image-eye/archive/2012/02/15/2352699.html
- 连接SQLServer OLEDB数据库(ACCESS) ODBC Oracle
web.Config文件中的连接字符串 <configuration> <system.web> <compilation debug="true" ...
- sql优化__rownum的使用【转】
ROWNUM的概念ROWNUM是一个虚假的列.它将被分配为 1,2,3,4,...N,N 是行的数量.一个ROWNUM值不是被永久的分配给一行 (这是最容易被误解的).表中的某一行并没有标号:你不可以 ...
- ant android打包--学习第一弹
1. 准备工作 用eclipse创建一个android项目 安装ant和SDK,并且添加到系统环境变量 2.ant 使用 2.1 ant简单的帮助命令 ant -p 2.2 创建ant配置文件%AND ...