一 : 详解Android首选项框架ListPreference
探索首选项框架
在深入探讨Android的首选项框架之前,首先构想一个需要使用首选项的场景,然后分析如何实现这一场景。假设你正在编写一个应用程序,它提供了一个搜索飞机航班的工具。而且,假设该应用程序的默认设置是根据机票价格由低到高的顺序显示航班,但用户可以将首选项设置为始终根据最少停站数或特定航线来航班。如何实现这一场景?
ListPreference
显然,必须为用户提供UI 来查看排序选项列表。该列表将包含每个选项的单选按钮,而且默认(或当前)选项应该被预先选中。要使用Android首选项框架解决此问题,所做的工作非常之少。首先,创建首选项XML文件来描述首选项,然后使用预先构建的活动类,该类知道如何显示和持久化首选项,下面是我们的首选项XML文件flightoptions.xml 。
Xml代码
- <?xmlversion="1.0"encoding="utf-8"?>
- <PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:key="flight_option_preference"
- android:title="@string/prefTitle"
- android:summary="@string/prefSummary">
- <ListPreference
- android:key="@string/selected_flight_sort_option"
- android:title="@string/listTitle"
- android:summary="@string/listSummary"
- android:entries="@array/flight_sort_options"
- android:entryValues="@array/flight_sort_options_values"
- android:dialogTitle="@string/dialogTitle"
- android:defaultValue="@string/flight_sort_option_default_value"/>
- </PreferenceScreen>
上边说了我们还需要一个Activity类FlightPreferenceActivity,下面使我们的Activity类。这个Activity类继承了PreferenceActivity 代码如下:
Java代码
- packagexiaohang.zhimeng;
- importandroid.os.Bundle;
- importandroid.preference.PreferenceActivity;
- publicclassFlightPreferenceActivityextendsPreferenceActivity{
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.flightoptions);
- }
- }
上面的代码清单,包含了一个表示航班选项示例的首选项设置的XML片段。该包含了一个活动类,也就是我们的FlightPreferenceActivity 这个类主要用于加载我们的XML 文件。首先看一下XML。Android提供了一种端到端得首选项框架。这意味着,该框架支持定义首选项,想用户显示设置,以及将用户选择持久化到数据库存储中。 在/res/xml/目录下的XML文件中定义首选项。要向用户显示首选项,编写一个活动类来扩展预定义的 Android类 android.preference.PreferenceActivity,然后使用 addPreferencesFromResource()方法将资源添加到活动的资源集合中。该框架会负责剩余操作(现实和持久化)。
在本航班场景中,在/res/xml/目录下创建文件 flightoptions.xml。然后创建活动类FlightPreferenceActivity, 它扩展了 android.preference.PreferenceActivity类。接下来调用addPreferencesFromResource() 传入R.xml.flightoptions。请注意,首选项资源XML指向多个字符串资源。为了确保正确编译,需要向项目中添加多个字符串资源 (我们稍后介绍)。现在先看一下 上面得代码清单会生成什么样子的UI.
上边有两个视图。左边的视图称为首选项屏幕,右边的UI是一个列表首选项。当用户选择 Flight Options时, Choose Flight Options视图将以模态对话框的形式出现,其中包含每个选项的单选按钮。用户选择一个选项之后,将立即该选项并关闭视图。当用户返回选项屏幕时,视图将反映前面保存的选择。
前面已提到,首选项XML 文件和相关的活动类,从上边我们可以看到 我们在XML文件中定义了一个PreferenceScreen ,然后创建ListPreference作为子屏幕。对于 PreferenceScreen,设置了3个属性: key、title和 summary。 key 是一个字符串,可用于以编程的方式表示项 (类似于使用 android:id的方式);title 是屏幕的标题 (My Preferences) ; summary是对屏幕用途的描述。对于列表首选项,设置 key、title和 summary,以及 entries、entryValues、dialogTitle和defaultValue特性。下表总结了这些特性。
特性 | 说明 |
android:key | 选项的名称或键(比如selected_flight_sort_option) |
android:title | 选项的标题 |
android:summary | 选项的简短摘要 |
android:entries | 可将选项设置成列表项的文本 |
android:entryValues | 定义每个列表项的值。注意:每个列表项有一些文本和 一 个 值。 文本由entries定义,值由entryValues定义。 |
android:dialogTitle | 对话框的标题,在视图显示为模态对话框时使用 |
android:defaultValue | 项列表中选项的默认值 |
为了使我们的例子能够正常运行,我们还需要添加如下文件。
Xml代码
- <?xmlversion="1.0"encoding="utf-8"?>
- <resources>
- <string-arrayname="flight_sort_options">
- <item>TotalCost</item>
- <item>#ofStops</item>
- <item>Airline</item>
- </string-array>
- <string-arrayname="flight_sort_options_values">
- <item>0</item>
- <item>1</item>
- <item>2</item>
- </string-array>
- </resources>
此文件大家一看就知道是 定义我们选项的显示的文本,和对应的值。这个XML 文件的名字是 arrays.xml 此文件应该放在 /res/values/arrays.xml
当然不能少了我们的strings.xml
Xml代码
- <?xmlversion="1.0"encoding="utf-8"?>
- <resources>
- <stringname="hello">HelloWorld,FlightPreferenceActivity!</string>
- <stringname="app_name">Preference_Demo</string>
- <stringname="prefTitle">MyPreferences</string>
- <stringname="prefSummary">SetFlightOptionPreferences</string>
- <stringname="flight_sort_option_default_value">1</string>
- <stringname="dialogTitle">ChooseFlightOptions</string>
- <stringname="listSummary">SetSearchOptions</string>
- <stringname="listTitle">FlightOptions</string>
- <stringname="selected_flight_sort_option">selected_flight_sort_option</string>
- <stringname="menu_prefs_title">Settings</string>
- <stringname="menu_quit_title">Quit</string>
- </resources>
刚才上边说到我们有一个首选项视图,就是那个FlightPreferenceActivity ,在这
这个例子中我们是通过一个菜单跳转到我们的首选项视图的。就是我们有一个MainActivity 这个MainActivity有一个菜单叫Settings当我们点击这个菜单的时候就会跳转到我们的首选项视图了,然后我们修改首选项的内容 当我们再一次回到 MainActivity 的时候就会看到我们修改后的 文本和值,我们通过一个TextView来显示
我们还是来看一下效果吧。
下面这个XML文件就是用来定义我们 这个菜单的,此文件的目录在 /res/menu/mainmenu.xml
Xml代码
- <?xmlversion="1.0"encoding="utf-8"?>
- <menuxmlns:android="http://schemas.android.com/apk/res/android">
- <itemandroid:id="@+id/menu_prefs"android:title="@string/menu_prefs_title"/>
- <itemandroid:id="@+id/menu_quit"android:title="@string/menu_quit_title"/>
- </menu>
也比较简单了。
在接下来就是我们的布局文件main.xml了
Xml代码
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextViewandroid:id="@+id/text1"android:layout_width="fill_parent"
- android:layout_height="wrap_content"/>
- </LinearLayout>
只有一个TextView 主要用来显示我们修改首选项之后的文本和值。
有了main.xml自然少不了MainActivity了,下面使我们的MainActivity类
Java代码
- packagexiaohang.zhimeng;
- importandroid.app.Activity;
- importandroid.content.Intent;
- importandroid.content.SharedPreferences;
- importandroid.os.Bundle;
- importandroid.view.Menu;
- importandroid.view.MenuInflater;
- importandroid.view.MenuItem;
- importandroid.widget.TextView;
- publicclassMainActivityextendsActivity{
- privateTextViewtv=null;
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- tv=(TextView)findViewById(R.id.text1);
- setOptionText();
- }
- //创建菜单,这个菜单我们在XML文件中定义这里加载进来就OK
- @Override
- publicbooleanonCreateOptionsMenu(Menumenu){
- MenuInflaterinflater=getMenuInflater();
- //加载我们的菜单文件
- inflater.inflate(R.menu.mainmenu,menu);
- returntrue;
- }
- //菜单选项事件
- @Override
- publicbooleanonOptionsItemSelected(MenuItemitem){
- if(item.getItemId()==R.id.menu_prefs){
- //当我们点击Settings菜单的时候就会跳转到我们的首选项视图,也就是我们的FlightPreferenceActivity
- Intentintent=newIntent().setClass(this,xiaohang.zhimeng.FlightPreferenceActivity.class);
- //因为我们要接收上一个Activity就是我们的首选项视图返回的数据,所以这里用startActivityForResult()方法启动我们的首选项视图
- //参数一:我们要跳转到哪里
- //参数二:回传码
- this.startActivityForResult(intent,0);
- }elseif(item.getItemId()==R.id.menu_quit){
- //当我们点击Quit菜单退出应用程序
- finish();
- }
- returntrue;
- }
- //此方法用来接收我们上一个Activity也就是我们的首选项视图返回的数据,因为我们可能会修改数据
- @Override
- protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
- super.onActivityResult(requestCode,resultCode,data);
- setOptionText();
- }
- //这个方法就是用来设置我们MainActivity上的TextView的值(就是我们首选项的值)
- privatevoidsetOptionText(){
- /*这个方法比较有意思了
- *第一个参数:用来指定我们存储我们首选项值的文件的名称
- *格式就是包名_preferences,大家可以看到我的包名就是xiaohang.zhimeng
- *这里如果你不按照这个格式写比如你不写你当前包名写成别的,也会生成当前包名_preferences这个文件写或不写它就在那里
- *第二个参数:打开模式
- **/
- SharedPreferencesprefs=getSharedPreferences("xiaohang.zhimeng_preferences",0);
- //这个方法大家去看文档,否则我会越写越乱
- Stringoption=prefs.getString(this.getResources().getString(R.string.selected_flight_sort_option),this.getResources().getString(R.string.flight_sort_option_default_value));
- //得到我们首选项所有选项的文本
- String[]optionText=this.getResources().getStringArray(R.array.flight_sort_options);
- //设置我们TextView要显示的值
- tv.setText("optionvalueis"+option+"("+optionText[Integer.parseInt(option)]+")");
- }
- }
如果大家对这里比较陌生,比如 SharedPreferences 是什么东西,可以参考这两篇文章。
http://byandby.iteye.com/blog/837601
http://byandby.iteye.com/blog/833292
在下边就是我们的AndroidManifest.xml文件了,倒也没啥特别的。
Xml代码
- <?xmlversion="1.0"encoding="utf-8"?>
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="xiaohang.zhimeng"android:versionCode="1"android:versionName="1.0">
- <uses-sdkandroid:minSdkVersion="10"/>
- <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
- <activityandroid:name=".MainActivity"android:label="@string/app_name">
- <intent-filter>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <activityandroid:name=".FlightPreferenceActivity"
- android:label="@string/prefTitle">
- <intent-filter>
- <actionandroid:name="xiaohang.zhimeng.intent.action.FlightPreferences"/>
- <categoryandroid:name="android.intent.category.PREFERENCE"/>
- </intent-filter>
- </activity>
- </application>
- </manifest>
OK,当我们完成了上边的所有运行应用程序,首先会看到一个简单的文本消息,显示“option value is 1(# of Stops)”。单击Menu按钮,然后在点击Settings,就会打开我们的首选项视图FlightPreferenceActivity,然后我们更改首选项的值,然后再点击back按钮就会看到我们修改后的值了。
大家可能会问,那Android把我们修改后的数据存储在哪里了呢?前面已经提到Android framework还会负责持久化首选项。例如,当用户选择一个排序选项时,Android会选择存储在应用程序 /data 目录下的一个XML 文件中,见下图。
实际的文件路径为 /data/data/[PACKAGE_NAME]/shared_prefs/[PACKAGE_NAME]_preferences.xml。我们需要 看看这个文件里边到底存了些什么? 导出这个文件就可以看到了。哦 不对,不用这样 太麻烦了, 我们 去 shell 里边 用 cat 读一下就行了,见下图。
一看便知,是以键值对的方式存取。
二 : Android Otto框架浅析
今天要介绍的是一个Android中使用得比较多的android 事件总线 EventBus模式的一个框架Otto。(www.61k.com]
Otto 官网:http://square.github.io/otto/
一、Android Studio中配置Otto (Eclipse中直接下载jar包导入)
跟之前介绍的其他的框架一样,它只需要简单地在build.gradle中配置下面一行红色字体即可
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:19.+'
/ /otto 所需要依赖的包
}
二、Otto事件总线框架浅析
1、为什么要用Otto框架?
Otto框架的主要功能是帮助我们来降低多个类之间的耦合度的(解耦)。
譬如:一个类A和另一个类B之间,如果A要操作B中的某个方法。
传统的方法:A直接调用B对象的该方法(耦合在一起)
事件总线机制:A不需要调用B类的方法,而仅仅需要产生并发出 一个“事件通知”, 如果B订阅了该“事件”
那么它将会接受到这个事件,做出相应的操作。这样就被解耦了。
2. Otto框架使用(结合代码介绍)
Otto框架其实相对之前的几个Android开源框架来说,更容易理解。
它主要运用到一个类: Bus类(用于注册类,注销类,发布事件)
两个注解: @Subscribe (订阅) @Produce (生产) 【都是针对“事件”的注解】
为了方便,我这边没有使用两个类来做这个Demo, 不过如果大家要试的话也可以,不过记住一点,无论是
发布者类 还是 订阅者类, 都需要用Bus进行类的注册,还有注销。否则将没法被Bus识别,这样就无法生效了。
下面的Demo, 仅为了让大家知道“事件”被产生了之后,post出来,所有订阅了该事件的类都会接到该事件,接受的先后顺序,不由我们控制!
public class MyActivity extends ActionBarActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_my);findViewById(R.id.button_change).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {BusProvider.getBusInstance().post(new DataChangedEvent("this is changed String"));//发布事件}});}@Overrideprotected void onResume() {super.onResume();BusProvider.getBusInstance().register(this);//注册}@Overrideprotected void onPause() {super.onPause();BusProvider.getBusInstance().unregister(this);//注销}@Subscribe //订阅事件DataChangedEventpublic void sayGoodOnEvent(DataChangedEvent event){Log.e("event", "good");}@Subscribe //订阅事件public void sayBadOnEvent(DataChangedEvent event){Log.e("event", "bad");}@Produce//产生事件public DataChangedEvent produceDataChangedEvent(){return new DataChangedEvent("this is changed String");}}
扩展:otto框架 / otto框架与eventbus / android otto
三 : 来自官方的Android数据绑定(Data Binding)框架①
今年的Google IO 大会上,Android 团队发布了一个数据绑定框架(Data Binding Library)。[www.61k.com]以后可以直接在 layout 布局 xml 文件中绑定数据了,无需再 findViewById 然后手工设置数据了。其语法和使用方式和 JSP 中的 EL 表达式非常类似。
Data Binding Library 是一个 support 库,支持 Android 2.1+ 版本 (API level 7+)。 由于该框架需要使用编译器来生成很多代码,所以需要配合最新版本的 Android Studio (1.3.0-beta1 + 版本)才能使用。
另外需要注意的是,Data Binding Library 还处于 beta 测试阶段,所以 API 还不稳定,随时可能会修改 API 接口,同时还有很多 BUG, 如果您使用过程中遇到了 bug ,可以到这里反馈:https://code.google.com/p/android-developer-preview/。
下面来介绍下如何使用 Data Binding Library
dependencies { classpath "com.android.tools.build:gradle:1.2.3" classpath "com.android.databinding:dataBinder:1.0-rc0" }
allprojects { repositories { jcenter() }}
apply plugin: ‘com.android.application'apply plugin: 'com.android.databinding'
Data Binding 在编译的时候依赖很多其他库。 1.0-rc0 依赖的第三方库如下:
\--- com.android.databinding:compiler:1.0-rc0 +--- com.google.guava:guava:17.0 +--- org.apache.commons:commons-lang3:3.3.2 +--- commons-codec:commons-codec:1.10 +--- com.android.databinding:baseLibrary:1.0-rc0 +--- org.jetbrains.kotlin:kotlin-stdlib:0.11.91 | \--- org.jetbrains.kotlin:kotlin-runtime:0.11.91 +--- com.tunnelvisionlabs:antlr4:4.4 | +--- com.tunnelvisionlabs:antlr4-runtime:4.4 | | +--- org.abego.treelayout:org.abego.treelayout.core:1.0.1 | | \--- com.tunnelvisionlabs:antlr4-annotations:4.4 | +--- com.tunnelvisionlabs:antlr4-annotations:4.4 | +--- org.antlr:antlr-runtime:3.5.2 | \--- org.antlr:ST4:4.0.8 | \--- org.antlr:antlr-runtime:3.5.2 \--- commons-io:commons-io:2.4
在 Layout 布局文件中使用数据绑定(Data Binding)
数据绑定表达式
Data-binding 布局文件和常规的 布局文件是不一样的, 其根元素为 layout 然后里面有个 data 和一个 View 元素。 这个 View 元素的内容就是常规的布局文件内容。
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="com.example.User"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.lastName}"/> </LinearLayout></layout>
在 data 元素中使用 variable 来声明在布局文件中使用的变量。
<variable name=”user” type=”com.example.User”/>
布局文件中引用变量值的属性通过 @{} 格式来调用。下面的示例设置 TextView 的文字为 user 对象的 firstName 的值。
<TextView android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@{user.firstName}”/>
数据对象(Data Object)
假设上面引用的 user 对象为一个 POJO( plain-old Java object)
public class User {public final String firstName;public final String lastName;public User(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName;}}
这种类型对象的数据从来不变。 在应用中经常有这种数据。 也可以使用 JavaBeans 对象:
public class User { private final String firstName; private final 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; }}
在数据绑定中,这两种对象是一样的。 表达式 @{user.firstName} 在第一种情况中会使用 firstName 变量的值;在后一种情况中会使用 getFirstName() 函数的返回值。
绑定数据(Binding Data)
默认情况下, 自动生成的 Binding 类名字为 布局文件的名字加上 Binding 后缀,使用驼峰命名法。 例如上面的 activity_main.xml 生成的 Binding 类为 ActivityMainBinding。 该类包含了所有把布局文件的变量值应用到 View 上的代码,并且知道如何处理绑定表达式。 最简单的获取绑定类对象的方式如下:
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity); User user = new User("Test", "User"); binding.setUser(user);}
上面三行代码即可完成数据绑定的工作。 现在运行程序,就可以看到 Test User 字符串已经设置到 TextView 上了。
也可以通过如下方式获取 Binding 对象:
MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
如果您在 ListView 或者 RecyclerView 的 adapter 中使用数据绑定,则推荐使用如下的方式:
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
//or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
布局文件解析
导入(Imports)
在 data 元素中可以使用多个 import 元素来导入需要引用的对象,和 Java 的import 语句一样。
<data>
<import type=”android.view.View”/>
</data>
然后,你就可以在表达式中使用 View 对象了。
<TextView
android:text=”@{user.lastName}”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:visibility=”@{user.isAdult ? View.VISIBLE : View.GONE}”/>
如果遇到类名一样的情况下,可以使用 alias 来重命名:
<import type=”android.view.View”/>
<import type=”com.example.real.estate.View”
alias=”Vista”/>
这样就可以通过 Vista 来引用 com.example.real.estate.View 对象了。导入的对象也可以当做类型使用。
<data>
<import type=”com.example.User”/>
<import type=”java.util.List”/>
<variable name=”user” type=”User”/>
<variable name=”userList” type=”List<User>”/>
</data>
注意,当前的 Android Studio 还没有支持导入解析,所以代码自动完成还没法使用。
使用类似 Java 类型强制转换的表达式:
<TextView
android:text=”@{((User)(user.connection)).lastName}”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”/>
导入类型还可以使用静态函数和变量:
<data>
<import type=”com.example.MyStringUtils”/>
<variable name=”user” type=”com.example.User”/>
</data>
…
<TextView
android:text=”@{MyStringUtils.capitalize(user.lastName)}”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”/>
和 Java 一样, java.lang.* 中的对象自动导入了。
变量(Variables)
data 元素中还可以使用 variable 来定义在布局文件表达式中使用的对象。
<data>
<import type=”android.graphics.drawable.Drawable”/>
<variable name=”user” type=”com.example.User”/>
<variable name=”image” type=”Drawable”/>
<variable name=”note” type=”String”/>
</data>
变量的类型在编译的时候就确定了,如果一个变量类型实现了 Observable #observable_objects 或者 是一个 observable 集合,则在编译的时候回监听该变量的值变化事件。 如果没有实现 Observable 接口,则不会监听。
如果有多个布局文件(配置不一样的情况下,例如 横屏和竖屏),多个布局文件中的变量会叠加一起。所以要保证变量的名字不能冲突。
生成的 binding 类中包含每个变量的 setter 和 getter 函数。 如果您没有调用 setter 函数,则表达式将使用每个对象的默认值,也就是 Java 对象的默认值 (对象为 null, int 为 0 等)
自定义 Binding 类的名字
默认生成的 Binding 类位于模块包的 databinding 子包中。例如 contact_item.xml 生成一个 ContactItemBinding 类,如果模块包名字为 com.example.my.app, 则该类的包名字为 com.example.my.app.databinding。
使用 data 元素的 class 属性可以自定义 Binding 类名字和包名字。例如,下面的示例自定义 类名为 ContactItem。
<data class=”ContactItem”>
…
</data>
如果像把包名字修改为模块的包,则可以这样(前面多了一个 . ):
<data class=”.ContactItem”>
…
</data>
如果要单独设置一个包名字, 则可以这样:
<data class=”com.example.ContactItem”>
…
</data>
布局文件引用(Includes)
变量可以传递到布局文件引用的布局文件中:
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:bind="http://schemas.android.com/apk/res-auto"> <data> <variable name="user" type="com.example.User"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/name" bind:user="@{user}"/> <include layout="@layout/contact" bind:user="@{user}"/> </LinearLayout></layout>
上面的示例中,在 name.xml 和 contact.xml 布局文件中必须有一个 user 变量的定义。
表达式语言(Expression Language)
和 Java 表达式一样支持常见的表达式:
示例:
不支持的语法
空指针检查操作符(Null Coalescing Operator)如果 ?? 左边的对象不是 Null 则使用 左边的对象,否则使用右边的对象。
android:text=”@{user.displayName ?? user.lastName}”
上面的表达式等价于:android:text=”@{user.displayName != null ? user.displayName : user.lastName}”
属性引用(Property Reference)
属性应用很简单,例如
android:text=”@{user.lastName}”
分别在 user 对象中查找 值域、getter 函数或者 ObservableFields。
避免 NullPointerException
生成的数据绑定代码自动检查 Null 并且避免 NullPointerException。 例如,对于表达式 @{user.name} ,如果 user 是 null, 则表达式的值为默认值 null, 如果引用的为 user.age, age 为 int 类型,则默认值为 0.
集合
常见的集合可以使用 [] 操作符来引用里面的元素,例如 arrays, lists, sparse lists, 和 maps。
<data>
<import type=”android.util.SparseArray”/>
<import type=”java.util.Map”/>
<import type=”java.util.List”/>
<variable name=”list” type=”List<String>”/>
<variable name=”sparse” type=”SparseArray<String>”/>
<variable name=”map” type=”Map<String, String>”/>
<variable name=”index” type=”int”/>
<variable name=”key” type=”String”/>
</data>
…
android:text=”@{list[index]}”
…
android:text=”@{sparse[index]}”
…
android:text=”@{map[key]}”
字符串字面量(String Literals)
如果属性的值使用单引号(’),则可以在表达式中使用双引号(”)来引用字符串字面量:
android:text=’@{map["firstName"]}’
如果属性值使用双引号定义,则需要使用 " 或者反引号 (`)。
android:text=”@{map[`firstName`}"
android:text="@{map["firstName"]}”
资源
在常规表达式中也可以使用资源:android:padding=”@{large? @dimen/largePadding : @dimen/smallPadding}”
带参数的字符串或者复数字符串也可以通过提供参数来使用:
android:text=”@{@string/nameFormat(firstName, lastName)}”
android:text=”@{@plurals/banana(bananaCount)}”
如果 复数字符串使用了多个变量,则需要提供所有的变量:
Have an orangeHave %d oranges
android:text=”@{@plurals/orange(orangeCount, orangeCount)}”
有些资源的引用方式有变化:
资源类型 | 布局 View 中引用方式 | 表达式引用方式 |
---|---|---|
String[] | @array | @stringArray |
int[] | @array | @intArray |
TypedArray | @array | @typedArray |
Animator | @animator | @animator |
StateListAnimator | @animator | @stateListAnimator |
colorint | @color | @color |
ColorStateList | @color | @colorStateList |
未完待续
本文标题:android框架-详解Android首选项框架ListPreference61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1