如何玩转Android fowstudio 种子,玩转Android fowstudio 种子是怎样的一种体验

玩转Android之MVVM开发模式实战,炫酷的DataBinding!
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.绑定ImageView3.绑定ListView4.点击事件处理5.数据更新处理好了,那就开始吧!1.基本使用创建好一个Android Project之后,在gradle文件中添加如下几行代码,表示开启databinding:android {
dataBinding{
enabled true
}就是这么简单,一个简单的databinding配置之后,就可以开始使用数据绑定了。要使用数据绑定,我们得首先创建一个实体类,比如User实体类,如下:/**
* Created by 王松 on .
public class UserEntity {
public UserEntity() {
public int getAge() {
public void setAge(int age) {
this.age =
public String getNickname() {
public void setNickname(String nickname) {
this.nickname =
public String getUsername() {
public void setUsername(String username) {
this.username =
public UserEntity(int age, String nickname, String username) {
this.age =
this.nickname =
this.username =
}然后我们来看看布局文件该怎么写,首先布局文件不再是以传统的某一个容器作为根节点,而是使用&layout&&/layout&作为根节点,在&layout&节点中我们可以通过&data&节点来引入我们要使用的数据源,如下:&?xml version=&1.0& encoding=&utf-8&?&
xmlns:android=&/apk/res/android&
name=&user&
type=&org.lenve.databinding1.UserEntity&/&
&LinearLayout
xmlns:tools=&/tools&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:orientation=&vertical&
tools:context=&org.lenve.databinding1.MainActivity&&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:text=&@{user.username}&/&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:text=&@{user.nickname}&/&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:text=&@{String.valueOf(user.age)}&/&
&/LinearLayout&
&/layout&在data中定义的variable节点,name属性表示变量的名称,type表示这个变量的类型,实例就是我们实体类的位置,当然,这里你也可以换一种写法,如下:
&import type=&org.lenve.databinding1.UserEntity&/&
name=&user&
type=&UserEntity&/&
&/data&先使用import节点将UserEntity导入,然后直接使用即可。但是如果这样的话又会有另外一个问题,假如我有两个类都是UserEntity,这两个UserEntity分属于不同的包中,又该如何?看下面:
&import type=&org.lenve.databinding1.UserEntity& alias=&Lenve&/&
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,再把数据绑定上去就可以了,如下:
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.基本的三目运算
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:text=&@{user.username??user.nickname}&/&两个??表示如果username属性为null则显示nickname属性,否则显示username属性。2.字符拼接
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:text=&@{`username is :`+user.username}&/&大家注意,这里的字符拼接不是用单引号哦,用的是ESC按键下面那个按键按出来的。目前DataBinding中的字符拼接还不支持中文。3.根据数据来决定显示样式
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:background=&@{user.age & 30 ? 0xFF0000FF:0xFFFF0000}&
android:text=&@{String.valueOf(user.age)}&/&我在这里给TextView设置背景的时候,做了一个简单的判断,如果用户的年龄小于30,背景就显示为蓝色,否则背景就显示为红色,DataBinding里支持小于号但是不支持大于号,索性,大于小于号我都用转义字符来表示。另外,DataBinding对于基本的四则运算、逻辑与、逻辑或、取反位移等都是支持的,我这里不再举例。2.绑定ImageViewOK,上文只是一个简单的绑定文本,下面我们来看看怎么样绑定图片,这里我们还得介绍DataBinding的另一项新功能,就是关于DataBinding自定义属性的问题,事实上,在我们使用DataBinding的时候,可以给一个控件自定义一个属性,比如我们下面即将说的这个绑定ImageView的案例。假设我现在想要通过Picasso显示一张网络图片,正常情况下这个显示很简单,可是如果我要通过DataBinding来实现,该怎么做呢?我们可以使用@BindingAdapter注解来创建一个自定义属性,同时还要有一个配套的注解的方法。当我们在布局文件中使用这个自定义属性的时候,会触发这个被我们注解的方法,这样说大家可能还有一点模糊,我们来看看新的实体类:/**
* Created by 王松 on .
public class User {
public User() {
public User(String userface, String username) {
this.userface =
this.username =
@BindingAdapter(&bind:userface&)
public static void getInternetImage(ImageView iv, String userface) {
Picasso.with(iv.getContext()).load(userface).into(iv);
public String getUserface() {
public void setUserface(String userface) {
this.userface =
public String getUsername() {
public void setUsername(String username) {
this.username =
}新类里边只有两个属性,分别是用户名和用户图像,用户图像中存储的实际上是一个网络图片地址,这里除了基本的get/set方法之外还多了一个叫做getInternetImage的网络方法,这个方法有一个注解@BindAdapter(&bind:userface&),该注解表示当用户在ImageView中使用自定义属性userface的时候,会触发这个方法,我在这个方法中来为这个ImageView加载一张图片,这里有一点需要注意,就是该方法必须为静态方法。OK,我们再来看看这次的布局文件:&?xml version=&1.0& encoding=&utf-8&?&
xmlns:android=&/apk/res/android&
xmlns:app=&/apk/res-auto&
name=&user&
type=&org.lenve.databinding2.User&/&
&LinearLayout
xmlns:tools=&/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&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:text=&@{user.username}&/&
&/LinearLayout&
&/layout&大家注意我在ImageView控件中使用userface属性的时候,使用的前缀不是android而是app哦。再来看看Activity中的代码:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
dataBinding.setUser(new User(&http://img2./auto//432cd8a.jpg&, &张三&));
}就是这么简单,加上网络权限就可以运行了,运行效果如下:3.绑定ListView好了,看完了简单使用之后,不知道你有没有喜欢上DataBinding,如果还没有,那就再来看看使用DataBinding来给ListView绑定数据吧,这个你一定会喜欢上的。因为使用这中方式来绑定太简单了。先来看看我们要做的效果吧:就是一个ListView,左边显示图片,右边显示文本,这样一个效果。OK,那就一步一步来吧,先是主布局:&?xml version=&1.0& encoding=&utf-8&?&
&RelativeLayout
xmlns:android=&/apk/res/android&
xmlns:tools=&/tools&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
tools:context=&org.lenve.databinding3.MainActivity&&
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&?&
xmlns:android=&/apk/res/android&
xmlns:app=&/apk/res-auto&
name=&food&
type=&org.lenve.databinding3.Food&/&
&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}&/&
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}&/&
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 .
public class Food {
public Food() {
public Food(String description, String img, String keywords, String summary) {
this.description =
this.img =
this.keywords =
this.summary =
@BindingAdapter(&bind:img&)
public static void loadInternetImage(ImageView iv, String img) {
Picasso.with(iv.getContext()).load(img).into(iv);
public String getDescription() {
public void setDescription(String description) {
this.description =
public String getImg() {
public void setImg(String img) {
this.img =
public String getKeywords() {
public void setKeywords(String keywords) {
this.keywords =
public String getSummary() {
public void setSummary(String summary) {
this.summary =
}这个实体类中有一个加载图片的方法,加载方式我们上文都已经介绍过了,不多说。好了,再来看看我们的终极Adapter类:/**
* Created by 王松 on .
public class MyBaseAdapter&T& extends BaseAdapter {
private LayoutI
private int layoutId;
private int variableId;
private List&T&
public MyBaseAdapter(Context context, int layoutId, List&T& list, int resId) {
this.context =
this.layoutId = layoutId;
this.list =
this.variableId = resId;
inflater = LayoutInflater.from(context);
public int getCount() {
return list.size();
public Object getItem(int position) {
return list.get(position);
public long getItemId(int position) {
public View getView(int position, View convertView, ViewGroup parent) {
ViewDataBinding dataB
if (convertView == null) {
dataBinding = DataBindingUtil.inflate(inflater, layoutId, parent, false);
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(){
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&
private ListV
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() {
public void onFailure(Call call, IOException e) {
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
parseJson(response.body().string());
private void parseJson(String jsonStr) {
foods = new ArrayList&&();
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&?&
xmlns:android=&/apk/res/android&
xmlns:app=&/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 {
public Food() {
public Food(String description, String img, String keywords, String summary) {
this.description =
this.img =
this.keywords =
this.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();
public String getDescription() {
public void setDescription(String description) {
this.description =
notifyPropertyChanged(org.lenve.databinding3.BR.description);
public String getImg() {
public void setImg(String img) {
this.img =
public String getKeywords() {
public void setKeywords(String keywords) {
this.keywords =
public String getSummary() {
public void setSummary(String summary) {
this.summary =
OK,这是第一种解决方案,也是比较简单常用的一种。2.使用DataBinding提供的ObservableFields来创建实体类这种方式使用起来略微麻烦,除了继承BaseObservable之外,创建属性的方式也变成下面这种:private final ObservableField&String& description = new ObservableField&&();属性的读写方式也变了,读取方式如下:description.get()写入方式如下:this.description.set(description);OK,依据上面几个规则,我新定义的实体类如下:/**
* Created by 王松 on .
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();
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.2.3.以上。
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?如何玩转Android studio,玩转Android Studio是怎样的一种体验? - 知乎671被浏览23129分享邀请回答/**
* TODO: document your custom view class.
public class MyView extends View {
public MyView(Context context) {
super(context);
init(null, 0);
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs, defStyle);
private void init(AttributeSet attrs, int defStyle) {
// Load attributes
final TypedArray a = getContext().obtainStyledAttributes(
attrs, R.styleable.MyView, defStyle, 0);
mExampleDimension = a.getDimension(
R.styleable.MyView_exampleDimension,
mExampleDimension);
if (a.hasValue(R.styleable.MyView_exampleDrawable)) {
mExampleDrawable = a.getDrawable(
R.styleable.MyView_exampleDrawable);
mExampleDrawable.setCallback(this);
a.recycle();
// Set up a default TextPaint object
mTextPaint = new TextPaint();
mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextAlign(Paint.Align.LEFT);
// Update TextPaint and text measurements from attributes
invalidateTextPaintAndMeasurements();
private void invalidateTextPaintAndMeasurements() {
mTextPaint.setTextSize(mExampleDimension);
mTextPaint.setColor(mExampleColor);
mTextWidth = mTextPaint.measureText(mExampleString);
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
mTextHeight = fontMetrics.bottom;
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// TODO: consider storing these as member variables to reduce
// allocations per draw cycle.
int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop();
int paddingRight = getPaddingRight();
int paddingBottom = getPaddingBottom();
int contentWidth = getWidth() - paddingLeft - paddingRight;
int contentHeight = getHeight() - paddingTop - paddingBottom;
// Draw the text.
canvas.drawText(mExampleString,
paddingLeft + (contentWidth - mTextWidth) / 2,
paddingTop + (contentHeight + mTextHeight) / 2,
mTextPaint);
// Draw the example drawable on top of the text.
if (mExampleDrawable != null) {
mExampleDrawable.setBounds(paddingLeft, paddingTop,
paddingLeft + contentWidth, paddingTop + contentHeight);
mExampleDrawable.draw(canvas);
强大的快捷键记住几个常用的快捷键就可以轻松自如地玩转AS,比如(在Mac下):alt + Enter
-- import classcmd + N
-- generate codecmd + shift + F6(有点蛋疼)-- renamecmd + F
-- searchDesign Preview
一边写布局一看实际效果屌炸天的反汇编能力,得益于IDEA使用Gradle构建项目一句话导入第三方库各项配置也超级方便最近发现AS可以方便地导入常用的第三方库了,只需要在列表中选择你想要的库就行了,再也不用去各处复制了!!!Android Studio 1.3 Preview 支持直接把ADT项目(包括其依赖的其他ADT项目)导入成AS项目。当然不仅仅是这一点,如图:2921 条评论分享收藏感谢收起1添加评论分享收藏感谢收起查看更多回答

我要回帖

更多关于 fowstudio艾达王种子 的文章

 

随机推荐