第十一章 避免代码碎片化
Hack 44 处理熄灯模式
在Android早期,系统在屏幕顶部显示一个状态栏(StatusBar),但在Android的Honeycomb版本上,状态栏移到了屏幕底部。
这里我们在不同的版本中实现全屏效果也就是熄灯模式。
熄灯模式:
在特定情况下,通过减少或隐藏导航栏、动作栏以及系统UI等控件,为用户提供全屏无干扰的视觉体验就是熄灯模式。熄灯模式可以保证用户更好的关注屏幕内容。如果用户需要操作内容,可以通过触摸屏幕等方式退出熄灯模式。
44.1 Android 2.x版本
代码实现如下:
public void onCreate(...){
...
//移除标题栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
mContentView = findViewById(R.id.content);
mContentView.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v){
Window w = getWindow();
if(mUseFullscreen){
w.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
w.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}else{
w.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
w.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
mUseFullscreen = !mUseFullscreen;
}
});
}
44.2 Android 3.x版本
在这个版本中,标题栏被动作栏(Action Bar)替代,仍然位于屏幕上方,但状态栏被移到屏幕底部。
还有一个重要改变是没有物理按键了,按键都被放置到状态栏中,因此一般只是将其暗化处理。
代码实现如下:
public void onCreate(...){
...
mContentView = findViewById(R.id.content);
//隐藏或显示动作栏
mContentView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisiblilityChange(int visibility){
ActionBar actionBar = getActionBar();
if(actionBar != null){
mContentView.setSystemUiVisibility(visibility);
//是否可视的参数
if(visibility == View.STATUS_BAR_VISIBLE){
actionBar.show();
}else{
actionBar.hide();
}
}
});
mContentView.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v){
if(mContentView.getSystemUiVisibility() == View.STATUS_BAR_VISIBLE){
mContentView.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
}else{
mContentView.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
}
}
});
}
44.3 在一个Activity中整合两种实现
代码实现如下:
Class<?> activity = null;
//坚持Android版本
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
activity = MainActivity2x.class;
}else{
activity = MainActivity3x.class;
}
//启动不同Activity
startActivity(new Intent(this,activity));
finish();
Hack 45 在旧版本上使用新API
这里我们进行在应用程序中使用Android新API并能运行在老设备上。
演示程序:
第一个API是Android v9中为SharedPreferences.Editor类新添加的apply()方法。
第二个API是在Android API Level 8中引入的,用于在manifest文件中声明是否允许讲应用程序安装在SD卡上。
45.1 使用apply()替代commit()
要操作SharedPreferences类,需要获取一个Editor类,然后调用该类提供的方法来修改SharedPreferences的值。所有相关修改都完成时,需要调用commit()方法。
从Android v9版本开始,SharedPreferences.Editor提供了apply()方法用于替代commit()方法。
官方文档上的解释:
“commit()方法会同步地将偏好值(Preference)直接写入持久化存储设备,与其不同的是,apply()方法会立即把修改内容提交到SharedPreferences内容缓存中,然后开始异步地将修改提交到存储设备上,在这个过程中,开发者不会察觉到任何错误问题。”
所以,如果不需要用到操作的返回值,开发者就应该用apply()方法代替commit()方法。
代码中“…”是那些基础的一般都有的代码。
Activity类中代码如下:
public class MainActivity extends Activity{
private static final String PREFS_NAME = "main_activity_prefs";
private static final String TIMES_OPENED_KEY = "times_opened_key";
private static final String TIMES_OPENED_FMT = "Times opened:%d";
private TextView mTextView;
private int mTimesOpened;
@Override
public void onCreate(...){
...
mTextView = (TextView) findViewById(R.id.times_opened);
}
@Override
protected void onResume(){
...
SharedPreferences prefs = getSharedPreferences(PREFS_NAME,0);
mTimesOpened = prefs.getInt(TIMES_OPENED_KEY,1);
mTextView.setText(String.format(TIMES_OPENED_FMT,mTimesOpened));
}
@Override
protected void onPause(){
...
Editor editor = getSharedPreferences(PREFS_NAME,0).edit();
editor.putInt(TIMES_OPENED_KEY,mTimesOpened+1);
SharedPreferencesCompat.apply(editor);
}
}
SharedPreferencesCompat类代码如下:
public class SharedPreferencesCompat{
private static final Method sApplyMethod = findApplyMethod();