一,Android应用栏右上角的设置按钮(菜单项),点击后进入一个新的设置界面
首先在Earthquake应用中的res/menu/main.xml
中添加
菜单栏样式
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.android.quakereport.EarthquakeActivity">
<item
android:id="@+id/action_settings"
android:title="@string/settting_menu_item"
android:icon="@mipmap/ic_launcher"
android:orderInCategory="1"
app:showAsAction="ifRoom"/>
</menu>
更新strings.xml在res/values/strings.xml
文件中添加一些字符串,更新后的strings.xml
<resources>
<string name="app_name">Earthquake Report</string>
<string name="near_the">Near the</string>
<string name="settting_menu_item">Setting</string>
<string name="settings_title">Earthquake Setting</string>
<string name="setting_min_magnitude_label">Choose Minimum Magnitude</string>
<string name="setting_min_magnitude_key" translatable="false">min_magnitude</string>
<string name="setting_min_magnitude_default" translatable="false">6</string>
<string name="setting_location">Location</string>
<string name="setting_location_default">world</string>
<string name="setting_date">Date Setting</string>
<string name="setting_date_default">1</string>
</resources>
覆盖 EarthquakeActivity.java 中的onCreateOptionMenu方法和onOptionItemSelected方法以使用 菜单,然后在用户单击菜单项时作出响应,进入一个新的设置界面
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
Intent settingsIntent = new Intent(this, SettingsActivity.class);
startActivity(settingsIntent);
return true;
}
return super.onOptionsItemSelected(item);
}
添加设置界面:创建SettingsActivity类,创建EarthuquakePreferenceFragment内部类继承自PreferenceFragment来设置偏好
public class SettingsActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
}
//创建内部类EarthquakePreference继承自PreferenceFragment,用于设置偏好
public static class EarthquakePreferenceFragment extends PreferenceFragment {
}
}
在res/layout/activity_settings.xm
中定义设置活动的布局:
在activity_settings.xml中添加:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:name="com.example.android.quakereport.SettingsActivity$EarthquakePreferenceFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.android.quakereport.SettingsActivity">
</fragment>
其中android:name属性用于fragment布局关联到Fragment
在AndroidManifest.xml中声明新活动
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.quakereport">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
...
<activity
android:name=".SettingsActivity"
android:label="@string/settings_title">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.android.quakereport.EarthquakeActivity" />
</activity>
</application>
</manifest>
SharedPreferences是一种轻量级的存储工具,采用的是Key-Value的键值对的存储结构,SharedPreferences的存储介质是符合XML规范的配置文件。
偏好设置数据在res/xml/settings_main.xml
中存储。
在settings_main.xml中添加
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/settings_title">
<EditTextPreference
android:defaultValue="@string/setting_min_magnitude_default"
android:inputType="numberDecimal"
android:key="@string/setting_min_magnitude_key"
android:selectAllOnFocus="true"
android:title="@string/setting_min_magnitude_label" />
<ListPreference
android:title="@string/setting_location"
android:dialogTitle="@string/setting_location"
android:entries="@array/location"
android:entryValues="@array/location_value"
android:key="@string/setting_location"
android:defaultValue="@string/setting_location_default">
</ListPreference>
<ListPreference
android:title="@string/setting_date"
android:dialogTitle="@string/setting_date"
android:key="@string/setting_date"
android:entries="@array/date"
android:entryValues="@array/date_value"
android:defaultValue="@string/setting_date_default">
</ListPreference>
</PreferenceScreen>
在SettingActivity中,覆盖 EarthquakePreferenceFragment 内部类中的 onCreate() 方法,以使用新定义的 settings_main XML 资源。
public class SettingsActivity extends AppCompatActivity {
...
public static class EarthquakePreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings_main);
}
}
}
偏好设置中的ListPreference的使用:列表数据存在res/values/arrays.xml
中
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="location">
<item>China</item>
<item>US</item>
<item>Europe</item>
<item>Allover the World</item>
</string-array>
<string-array name="location_value">
<item>30.67,104.06</item>
<item>39.04,-97.95</item>
<item>50.40,23.14</item>
<item>world</item>
</string-array>
<string-array name="date">
<item>1 day before</item>
<item>2 day before</item>
<item>3 day before</item>
<item>4 day before</item>
<item>5 day before</item>
</string-array>
<string-array name="date_value">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
</string-array>
</resources>
二,根据用户偏好构建构造所需URL(该方法可以之后用到别的应用中)。
在这之前,我们已经使用硬编码固定 URL 请求地震。 但是,我们需要将最小震级偏好作为查询参数插入到 URL 中。虽然可以通过 一些复杂的字符串串联来实现该功能,但是使用 Uri.Builder 类是一种更好的方法。
再问一次什么是 URI?URI 即统一资源标识符,是 更常用的 URL。URL 常常指向计算机网络 上的资源,而 URI 可以识别 范围更大的事物(从文件和邮箱到物理 对象,如书)。
由于 URL 是 URI 的子集,因此 Android 提供 方法来操纵 URI 是非常有意义的,因为这些 URI 将 同样适用于 URL。
在EarthquakeActivity中添加以下方法updateUrl方法,该方法可以之后用到别的应用中
private void updateUrl(){
USGS_REQUEST_URL = "https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=";
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
//获取最小震级和之前天数对应偏好设置的值
String minMagnitude = sharedPreferences.getString(getString(R.string.setting_min_magnitude_key), getString(R.string.setting_min_magnitude_default));
String before_day = sharedPreferences.getString(getString(R.string.setting_date), getString(R.string.setting_date_default));
//add the date,获取之前某段时间的方法
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.DATE, - Integer.parseInt(before_day));
Date day = calendar.getTime();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String starttime = format.format(day);
USGS_REQUEST_URL += starttime;
//先将USGS_REQUEST_URL 常量的值修改为 基准 URI
Uri baseUri = Uri.parse(USGS_REQUEST_URL);
//在此baseUri之上进行添加,
Uri.Builder uriBuilder = baseUri.buildUpon();
//添加最小震级参数
uriBuilder.appendQueryParameter("minmag", minMagnitude);
//获取位置偏好的参数
String location = sharedPreferences.getString(getString(R.string.setting_location),"world");
//如果是位置偏好是世界范围的则不添加位置偏好到url中
if (!location.equals("world")){
String[] part = location.split(",");
String latitude = part[0];
String longitude = part[1];
String maxradiuskm = "800";
uriBuilder.appendQueryParameter("latitude", latitude);
uriBuilder.appendQueryParameter("longitude", longitude);
uriBuilder.appendQueryParameter("maxradiuskm", maxradiuskm);
}
USGS_REQUEST_URL = uriBuilder.toString();
}
三,使用下拉刷新SwipeRefreshLayout.OnRefreshListener接口
在EarthquakeActivity.java中添加接口,并且重写OnRefresh()方法,
public class EarthquakeActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
...
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
//设置刷新监听器
swipeRefreshLayout.setOnRefreshListener(this);
//设置进度圆圈的背景颜色
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
@Override
public void onRefresh() {
//update USGS_REQUEST_URL
updateUrl();
EarthquakeActivity.EarthquakeAsyncTask earthquakeAsyncTask = new EarthquakeActivity.EarthquakeAsyncTask();
//AsyncTask.execute方法会将参数传到doInBackground中执行
earthquakeAsyncTask.execute(USGS_REQUEST_URL);
}
...
}
在activity_earthquake.xml中添加SwipeRefreshLayout节点,该节点下面只能有一个直接子视图,且这个视图必须是可以滚动的,例如ListView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/swipe_refresh_layout">
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</ListView>
</android.support.v4.widget.SwipeRefreshLayout>
<TextView
android:id="@+id/empty_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No earthquake found"
android:layout_centerInParent="true" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progress_bar"
android:layout_centerInParent="true"/>
</RelativeLayout>
在EarthquakeActivty.java内部类EarthquakeAsyncTask中的onPostExecute()添加收到数据后结束刷新。
...
@Override
protected void onPostExecute(final ArrayList<Earthquake> earthquakes) {
//收到数据后结束下拉刷新动作
swipeRefreshLayout.setRefreshing(false);
...
if (earthquakes != null && !earthquakes.isEmpty()) {
...
//if the earthquake array list is not null then set the progressBar divisible
progressBar.setVisibility(View.GONE);
emptyView.setVisibility(View.INVISIBLE);
} else {
//收到数据后结束下拉刷新动作
swipeRefreshLayout.setRefreshing(false);
// Set the adapter on the {@link ListView}
// so the list can be populated in the user interface
earthquakeListView.setAdapter(adapter);
//if the earthquake array list null then set the emptyView visible and progressBar divisible
emptyView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
}
}