C# 很早就有了MVVM的开发模式,Android手机中的MVVM一直到去年Google的I\O大会上才推出,姗姗来迟。MVVM这中开发模式的优点自不必多说,可以实现视图和逻辑代码的解耦,而且,按照Google的说法,使用了MVVM的开发模式,还可以提高布局文件的解析速度,个人觉得这一点非常重要。我们在安卓开发中经常需要写很多个findViewById,让人心烦,很多人不想写这个于是用了一些注解框架,可是注解框架无论性能多好,效率总是要低于findViewById的,因此,Android中的MVVM也即databinding可以帮助我们彻底解决这个问题。OK,废话不多说,我们来看看具体要怎么在Android开发中使用MVVM。

在低版本的AndroidStudio中使用DataBinding稍微有点麻烦,这里不做介绍。我这里以AndroidStuido2.1为例来介绍DataBinding。本文主要包含以下几方面内容:

1.基本使用

2.绑定ImageView

3.绑定ListView

4.点击事件处理

5.数据更新处理

好了,那就开始吧!

1.基本使用

创建好一个Android Project之后,在gradle文件中添加如下几行代码,表示开启databinding:

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

就是这么简单,一个简单的databinding配置之后,就可以开始使用数据绑定了。

要使用数据绑定,我们得首先创建一个实体类,比如User实体类,如下:

/**
* Created by 王松 on 2016/7/31.
*/
public class UserEntity {
private String username;
private String nickname;
private int age; public UserEntity() {
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getNickname() {
return nickname;
} public void setNickname(String nickname) {
this.nickname = nickname;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public UserEntity(int age, String nickname, String username) {
this.age = age;
this.nickname = nickname;
this.username = username;
}
}

然后我们来看看布局文件该怎么写,首先布局文件不再是以传统的某一个容器作为根节点,而是使用<layout></layout>作为根节点,在<layout>节点中我们可以通过<data>节点来引入我们要使用的数据源,如下:

<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
> <data> <variable
name="user"
type="org.lenve.databinding1.UserEntity"/>
</data> <LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="org.lenve.databinding1.MainActivity"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.username}"/> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.nickname}"/> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(user.age)}"/>
</LinearLayout>
</layout>

在data中定义的variable节点,name属性表示变量的名称,type表示这个变量的类型,实例就是我们实体类的位置,当然,这里你也可以换一种写法,如下:

    <data>

        <import type="org.lenve.databinding1.UserEntity"/>
<variable
name="user"
type="UserEntity"/>
</data>

先使用import节点将UserEntity导入,然后直接使用即可。但是如果这样的话又会有另外一个问题,假如我有两个类都是UserEntity,这两个UserEntity分属于不同的包中,又该如何?看下面:

    <data>

        <import type="org.lenve.databinding1.UserEntity" alias="Lenve"/>
<variable
name="user"
type="Lenve"/>
</data>

在import节点中还有一个属性叫做alias,这个属性表示我可以给该类取一个别名,我给UserEntity这个实体类取一个别名叫做Lenve,这样我就可以在variable节点中直接写Lenve了。

看完data节点我们再来看看布局文件,TextView的text属性被我直接设置为了@{user.username},这样,该TextView一会直接将UserEntity实体类的username属性的值显示出来,对于显示age的TextView,我用了String.valueOf来显示,因为大家知道TextView并不能直接显示int型数据,所以需要一个简单的转换,事实上,我们还可以在{}里边进行一些简单的运算,这些我一会再说。

最后,我们来看看Activity中该怎么写,setContentView方法不能够再像以前那样来写了,换成下面的方式:

DataBindingUtil.setContentView(this, R.layout.activity_main)

该方法有一个返回值,这个返回值就是系统根据我们的activity_main.xml布局生成的一个ViewModel类,所以完整写法如下:

ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

有了ViewModel,再把数据绑定上去就可以了,如下:

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
UserEntity user = new UserEntity();
user.setAge(34);
user.setUsername("zhangsan");
user.setNickname("张三");
activityMainBinding.setUser(user);
}

运行,显示效果如下:

OK,那我们刚才还说到可以在@{}进行简单的计算,都有哪些计算呢?我们来看看:

1.基本的三目运算

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

两个??表示如果username属性为null则显示nickname属性,否则显示username属性。

2.字符拼接

        <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`username is :`+user.username}"/>

大家注意,这里的字符拼接不是用单引号哦,用的是ESC按键下面那个按键按出来的。目前DataBinding中的字符拼接还不支持中文。

3.根据数据来决定显示样式

        <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@{user.age &lt; 30 ? 0xFF0000FF:0xFFFF0000}"
android:text="@{String.valueOf(user.age)}"/>

我在这里给TextView设置背景的时候,做了一个简单的判断,如果用户的年龄小于30,背景就显示为蓝色,否则背景就显示为红色,DataBinding里支持小于号但是不支持大于号,索性,大于小于号我都用转义字符来表示。

另外,DataBinding对于基本的四则运算、逻辑与、逻辑或、取反位移等都是支持的,我这里不再举例。

2.绑定ImageView

OK,上文只是一个简单的绑定文本,下面我们来看看怎么样绑定图片,这里我们还得介绍DataBinding的另一项新功能,就是关于DataBinding自定义属性的问题,事实上,在我们使用DataBinding的时候,可以给一个控件自定义一个属性,比如我们下面即将说的这个绑定ImageView的案例。假设我现在想要通过Picasso显示一张网络图片,正常情况下这个显示很简单,可是如果我要通过DataBinding来实现,该怎么做呢?我们可以使用

@BindingAdapter

注解来创建一个自定义属性,同时还要有一个配套的注解的方法。当我们在布局文件中使用这个自定义属性的时候,会触发这个被我们注解的方法,这样说大家可能还有一点模糊,我们来看看新的实体类:

/**
* Created by 王松 on 2016/7/31.
*/
public class User {
private String username;
private String userface; public User() {
} public User(String userface, String username) {
this.userface = userface;
this.username = username;
} @BindingAdapter("bind:userface")
public static void getInternetImage(ImageView iv, String userface) {
Picasso.with(iv.getContext()).load(userface).into(iv);
} public String getUserface() {
return userface;
} public void setUserface(String userface) {
this.userface = userface;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
}
}

新类里边只有两个属性,分别是用户名和用户图像,用户图像中存储的实际上是一个网络图片地址,这里除了基本的get/set方法之外还多了一个叫做getInternetImage的网络方法,这个方法有一个注解@BindAdapter("bind:userface"),该注解表示当用户在ImageView中使用自定义属性userface的时候,会触发这个方法,我在这个方法中来为这个ImageView加载一张图片,这里有一点需要注意,就是该方法必须为静态方法。OK,我们再来看看这次的布局文件:

<?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="user"
type="org.lenve.databinding2.User"/>
</data> <LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="org.lenve.databinding2.MainActivity"> <ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:userface="@{user.userface}"></ImageView> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.username}"/>
</LinearLayout>
</layout>

大家注意我在ImageView控件中使用userface属性的时候,使用的前缀不是android而是app哦。再来看看Activity中的代码:

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
dataBinding.setUser(new User("http://img2.cache.netease.com/auto/2016/7/28/201607282215432cd8a.jpg", "张三"));
}

就是这么简单,加上网络权限就可以运行了,运行效果如下:

3.绑定ListView

好了,看完了简单使用之后,不知道你有没有喜欢上DataBinding,如果还没有,那就再来看看使用DataBinding来给ListView绑定数据吧,这个你一定会喜欢上的。因为使用这中方式来绑定太简单了。

先来看看我们要做的效果吧:

就是一个ListView,左边显示图片,右边显示文本,这样一个效果。OK,那就一步一步来吧,先是主布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="org.lenve.databinding3.MainActivity"> <ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</RelativeLayout>

主布局很简单,就是一个ListView,再来看看ListView的item布局:

<?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="food"
type="org.lenve.databinding3.Food"/>
</data> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="96dp"
android:orientation="vertical"> <ImageView
android:id="@+id/iv"
android:layout_width="96dp"
android:layout_height="96dp"
android:padding="6dp"
app:img="@{food.img}"/> <TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_toRightOf="@id/iv"
android:ellipsize="end"
android:maxLines="3"
android:text="@{food.description}"/> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_toRightOf="@id/iv"
android:layout_alignParentBottom="true"
android:layout_marginBottom="2dp"
android:text="@{food.keywords}"
android:textStyle="bold"/>
</RelativeLayout>
</layout>

图片加载、文本加载前两节都已经说过了,这里的东西就没有什么难度了,我们再来看看实体类Food:

/**
* Created by 王松 on 2016/7/31.
*/
public class Food {
private String description;
private String img;
private String keywords;
private String summary; public Food() {
} public Food(String description, String img, String keywords, String summary) {
this.description = description;
this.img = img;
this.keywords = keywords;
this.summary = summary;
} @BindingAdapter("bind:img")
public static void loadInternetImage(ImageView iv, String img) {
Picasso.with(iv.getContext()).load(img).into(iv);
} public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description;
} public String getImg() {
return img;
} public void setImg(String img) {
this.img = img;
} public String getKeywords() {
return keywords;
} public void setKeywords(String keywords) {
this.keywords = keywords;
} public String getSummary() {
return summary;
} public void setSummary(String summary) {
this.summary = summary;
}
}

这个实体类中有一个加载图片的方法,加载方式我们上文都已经介绍过了,不多说。好了,再来看看我们的终极Adapter类:

/**
* Created by 王松 on 2016/7/31.
*/
public class MyBaseAdapter<T> extends BaseAdapter {
private Context context;
private LayoutInflater inflater;
private int layoutId;
private int variableId;
private List<T> list; public MyBaseAdapter(Context context, int layoutId, List<T> list, int resId) {
this.context = context;
this.layoutId = layoutId;
this.list = list;
this.variableId = resId;
inflater = LayoutInflater.from(context);
} @Override public int getCount() {
return list.size();
} @Override
public Object getItem(int position) {
return list.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewDataBinding dataBinding;
if (convertView == null) {
dataBinding = DataBindingUtil.inflate(inflater, layoutId, parent, false);
}else{
dataBinding = DataBindingUtil.getBinding(convertView);
}
dataBinding.setVariable(variableId, list.get(position));
return dataBinding.getRoot();
}
}

这个大概算是Adapter的终极写法了,如果你按这种方式来写Adapter,那么如果没有非常奇葩的需求,你这个App中可能就只有这一个给ListView使用的Adapter了,为什么这么说呢?因为这个Adapter中没有一个变量和我们的ListView沾边,解释一下几个变量吧:layoutId这个表示item布局的资源id,variableId是系统自动生成的,根据我们的实体类,直接从外部传入即可。另外注意布局加载方式为DataBindingUtil类中的inflate方法。OK,最后再来看看Activity:

public class MainActivity extends AppCompatActivity {

    private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
MyBaseAdapter<Food> adapter = new MyBaseAdapter<>(MainActivity.this, R.layout.listview_item, foods, org.lenve.databinding3.BR.food);
lv.setAdapter(adapter);
}
};
private List<Food> foods;
private ListView lv; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = ((ListView) findViewById(R.id.lv));
initData();
} private void initData() {
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder().url("http://www.tngou.net/api/food/list?id=1").build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) { } @Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
parseJson(response.body().string());
}
}
});
} private void parseJson(String jsonStr) {
foods = new ArrayList<>();
try {
JSONObject jo = new JSONObject(jsonStr);
JSONArray tngou = jo.getJSONArray("tngou");
for (int i = 0; i < tngou.length(); i++) {
JSONObject item = tngou.getJSONObject(i);
String description = item.getString("description");
String img = "http://tnfs.tngou.net/image"+item.getString("img");
String keywords = "【关键词】 "+item.getString("keywords");
String summary = item.getString("summary");
foods.add(new Food(description, img, keywords, summary));
}
mHandler.sendEmptyMessage(0);
} catch (JSONException e) {
e.printStackTrace();
}
}
}

OkHttp下载数据和Json解析自不用多说,在构造MyAdapter的时候传入的最后一个参数,是BR中的,这个BR和我们项目中的R文件类似,都是系统自动生成的。

至此,我们使用DataBinding的方式来给ListView加载数据就算完成了。so easy~~~

4.点击事件处理

如果你使用DataBinding,我们的点击事件也会有新的处理方式,首先以ListView为例来说说如何绑定点击事件,在listview_item布局文件中每一个item的根节点添加如下代码:

<?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"
>
....
....
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="96dp"
android:onClick="@{food.onItemClick}"
android:orientation="vertical"> <ImageView
android:id="@+id/iv"
android:layout_width="96dp"
android:layout_height="96dp"
android:padding="6dp"
app:img="@{food.img}"/>
....
....
....
</RelativeLayout>
</layout>

OK,我给RelativeLayout容器添了onClick属性,属性的值为food.onItemClick,那么这个onItemClick到底是什么呢?其实就是在实体类Food中定义的一个方法,如下:

    public void onItemClick(View view) {
Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();
}

点击item获取当前position的数据,获取方式也是非常简单,直接get方法获取即可,比传统的ListView的点击事件通过position来获取数据方便多了。如果我想为关键字这个TextView添加点击事件也很简单,和上面一样,这里我就不再贴代码了,文末可以下载源码。

5. 数据更新处理

单纯的更新Food对象并不能改变ListView的UI显示效果,那该怎么做呢?Google给我们提供了三种解决方案,分别如下:

1.让实体类继承自BaseObservable

让实体类继承自BaseObservable,然后给需要改变的字段的get方法添加上@Bindable注解,然后给需要改变的字段的set方法加上notifyPropertyChanged(org.lenve.databinding3.BR.description);一句即可,比如我想点击item的时候把description字段的数据全部改为111,我可以修改Food类变为下面的样子:

public class Food extends BaseObservable {
private String description;
private String img;
private String keywords;
private String summary; public Food() {
} public Food(String description, String img, String keywords, String summary) {
this.description = description;
this.img = img;
this.keywords = keywords;
this.summary = summary;
} @BindingAdapter("bind:img")
public static void loadInternetImage(ImageView iv, String img) {
Picasso.with(iv.getContext()).load(img).into(iv);
} public void onItemClick(View view) {
// Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();
setDescription("111");
} public void clickKeywords(View view) {
Toast.makeText(view.getContext(), getKeywords(), Toast.LENGTH_SHORT).show();
} @Bindable
public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description;
notifyPropertyChanged(org.lenve.databinding3.BR.description);
} public String getImg() {
return img;
} public void setImg(String img) {
this.img = img;
} public String getKeywords() {
return keywords;
} public void setKeywords(String keywords) {
this.keywords = keywords;
} public String getSummary() {
return summary;
} public void setSummary(String summary) {
this.summary = summary;
}
}

OK,这是第一种解决方案,也是比较简单常用的一种。

2.使用DataBinding提供的ObservableFields来创建实体类

这种方式使用起来略微麻烦,除了继承BaseObservable之外,创建属性的方式也变成下面这种:

private final ObservableField<String> description = new ObservableField<>();

属性的读写方式也变了,读取方式如下:

description.get()

写入方式如下:

this.description.set(description);

OK,依据上面几个规则,我新定义的实体类如下:

/**
* Created by 王松 on 2016/7/31.
*/
public class Food extends BaseObservable {
private final ObservableField<String> description = new ObservableField<>();
private final ObservableField<String> img = new ObservableField<>();
private final ObservableField<String> keywords = new ObservableField<>();
private final ObservableField<String> summary = new ObservableField<>();
public Food() {
} public Food(String description, String img, String keywords, String summary) {
this.description.set(description);
this.keywords.set(keywords);
this.img.set(img);
this.summary.set(summary);
} @BindingAdapter("bind:img")
public static void loadInternetImage(ImageView iv, String img) {
Picasso.with(iv.getContext()).load(img).into(iv);
} public void onItemClick(View view) {
// Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();
setDescription("111");
} public void clickKeywords(View view) {
Toast.makeText(view.getContext(), getKeywords(), Toast.LENGTH_SHORT).show();
} @Bindable
public String getDescription() {
return description.get();
} public void setDescription(String description) {
this.description.set(description);
notifyPropertyChanged(org.lenve.databinding3.BR.description);
} public String getImg() {
return img.get();
} public void setImg(String img) {
this.img.set(img);
} public String getKeywords() {
return keywords.get();
} public void setKeywords(String keywords) {
this.keywords.set(keywords);
} public String getSummary() {
return summary.get();
} public void setSummary(String summary) {
this.summary.set(summary);
}
}

这种方式实现的功能和第一个实体类实现的功能一模一样。

3.使用DataBinding中提供的集合来存储数据即可

DataBinding中给我们提供了一些现成的集合,用来存储数据,比如ObservableArrayList,ObservableArrayMap,因为这些用的少,我这里就不做介绍了。

本文共涉及到三个Demo,由于CSDN对上传文件大小的限制,我分三次上传,下载地址如下:

1.http://download.csdn.net/detail/u012702547/9591142

2.http://download.csdn.net/detail/u012702547/9591150

3.http://download.csdn.net/detail/u012702547/9591160

以上。

玩转Android之MVVM开发模式实战,炫酷的DataBinding!的更多相关文章

  1. Android之MVVM开发模式

    MVVM 模式简介 MVVM模式是指Model-View-ViewModel.相信看过笔者关于MVP的文章的读者也会发现,无论如何抽象化,在我们的View层中是无法避免的要处理一部分逻辑的.而MVVM ...

  2. js架构设计模式——理解javascript中的MVVM开发模式

    理解javascript中的MVVM开发模式 http://blog.csdn.net/slalx/article/details/7856769 MVVM的全称是Model View ViewMod ...

  3. 【Android珍藏】推荐10个炫酷的开源库【转】

    感谢大佬:https://www.jianshu.com/p/d608f0228fd4 前言 技术群里面经常有人问到一些炫酷的UI效果实现方法,有时候我都是给一个相同或者相似效果的Github链接,有 ...

  4. MVVM开发模式简单实例MVVM Demo

    本文主要是翻译Rachel Lim的一篇有关MVVM模式介绍的博文 A Simple MVVM Example 并具体给出了一个简单的Demo(原文是以WPF开发的,对于我自己添加或修改的一部分会用红 ...

  5. MVVM开发模式简单实例MVVM Demo【续】

    本文将接着上篇文章,介绍一下三点:(Universal App) 1.将添加Product集合,绑定到列表 2.给点击ListBox的添加选项改变时的事件(要附加依赖属性,和Button点击事件不同) ...

  6. 精通MVC网站、MVVM开发模式、Razor语法

    http://www.cnblogs.com/powertoolsteam/p/MVC_one.html ASP.NET MVC (一)——深入理解ASP.NET MVC 以下是ASP.NET MVC ...

  7. 从MVC -> MVVM ? 开发模式

    MVVM 到底是什么? view :由 MVC 中的 view 和 controller 组成,负责 UI 的展示,绑定 viewModel 中的属性,触发 viewModel 中的命令: viewM ...

  8. 【Android开发】安卓炫酷效果集合

    1. android-ripple-background 能产生波浪效果的背景图片控件,可以自定义颜色,波浪扩展的速度,波浪的圈数. github地址 2. android-shapeLoadingV ...

  9. Android自定义View(RollWeekView-炫酷的星期日期选择控件)

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/53420889 本文出自:[openXu的博客] 目录: 1分析 2定义控件布局 3定义Cus ...

随机推荐

  1. Android开发UI之Toast的使用

    Toast,A toast provides simple feedback about an operation in a small popup. 对于操作提供一个简单反馈信息. 官网链接:htt ...

  2. oracle rac scan ip 用途 原理

    Oracle 11G R2 RAC增加了scan ip功能,在11.2之前,client链接数据库的时候要用vip,假如你的cluster有4个节点,那么客户端的tnsnames.ora中就对应有四个 ...

  3. Go语言程序的状态监控 via 达达

    Go语言程序的状态监控 Go是很实在的编程语言,从一开始就提供了很详细的运行状态信息.产品上线后的调优和排查疑难杂症都得靠这些状态信息.这边总结一些我们项目里用到的状态监控手段. pprof Go自带 ...

  4. STL find() ,还是挺重要的

    template<class InputIterator, class T> InputIterator find (InputIterator first, InputIterator ...

  5. 一步步写STM32 OS【三】PendSV与堆栈操作

    一.什么是PendSV PendSV是可悬起异常,如果我们把它配置最低优先级,那么如果同时有多个异常被触发,它会在其他异常执行完毕后再执行,而且任何异常都可以中断它.更详细的内容在<Cortex ...

  6. 【原】泛型-Java

    泛型是Java SE5.0中新增的新特性,通过泛型使得在代码编译的时候就能检查类型安全,并且所有的强制类型转换都是自动和隐式的,从而提高代码的重用率. Note:在JavaSE7+以后的版本中,构造函 ...

  7. Html笔记(七)表单

    表单标签: <form> 表单标签是最常用的标签,用于与服务器端的交互. <input>:输入标签:接受用户输入信息 其中type属性指定输入标签的类型 文本框 text:输入 ...

  8. 增加eclipse启动的Tomcat内存的方法 tomcat内存增加

    增加eclipse启动的Tomcat内存的方法 Tomcat一般默认情况下最大最优内存设置为2G 这种情况下,修改Tomcat\bin\catalina.bat,添加如下内容 set JAVA_OPT ...

  9. ARP局域网欺骗工具编写

    每台主机都设有一个ARP高速缓存(ARP cache),里面有本局域网上各主机和路由器的IP地址和硬件地址的映射表,这些都是该主机目前知道的一些地址. 当主机A要向本局域网上的某个主机B发送IP数据报 ...

  10. Galgame引擎编写,实现对话文本显示

    class cTalk { public: cTalk(); ~cTalk(); void Init(); void Shutdown(); void SetSpeed(int speed); voi ...