解读(二):从简单的类开始
AppManager类
/**
* 应用程序入口
*/
public class AppManager extends Application {
public static Context context;
public static Resources resources;
public static SharedPreferences preferences;
public static User LOCAL_LOGINED_USER; //记录登录的用户
public static final String BUNDLE_TYPE = "BUNDLE_TYPE";
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
resources = getResources();
//以包名作为SharePreference的文件名
preferences = getSharedPreferences(context.getPackageName(), MODE_PRIVATE);
//使用LeakCanary做内存泄露检查
//LeakCanary.install(this);
}
/**
* 获得包信息
*/
public static PackageInfo getPackageInfo() {
try {
//包信息都记录在PackageManager中
return context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
}
/**
* 判断是否登录
*/
public static boolean isLogined() {
return LOCAL_LOGINED_USER != null;
}
}
- 说明:
- AppManager类中保存了一个静态变量LOCAL_LOGINED_USER保存已登录的用户.
StartActivity类
/**
* 启动页面
*/
public class StartActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//因为在主题Theme.AppStart中设置了android:windowBackground图片,这里没内容
setContentView(R.layout.activity_start);
//从SharePreference中登录用户
loadLocalUser();
//使用postDelayed延迟2s进入MainActivity
new Handler().postDelayed(() -> {
startActivity(new Intent(StartActivity.this, MainActivity.class));
finish();
}, 2000);
}
/**
* 从SharePreference登录用户
*/
private void loadLocalUser() {
SharedPreferences preferences = SharePreferenceManager.getLocalUser(this);
// 首先是否有登录记录
boolean isLogin = preferences.getBoolean(LocalUser.KEY_LOGIN_STATE, false);
if (!isLogin)
return;
// 其次,登录记录是否过期
long lastLoginTime = preferences.getLong(LocalUser.KEY_LAST_LOGIN_TIME, -1);
if (lastLoginTime == -1)
return;
//登录过期时间为30天
if (new Date().getTime() - lastLoginTime > 30L * 24 * 60 * 60 * 1000)
return;
// 验证信息是否完善
User user = new User();
user.setUid(preferences.getLong(LocalUser.KEY_UID, -1));//UID
if (user.getUid() == -1)
return;
user.setName(preferences.getString(LocalUser.KEY_NICK, null));//昵称
if (user.getName() == null)
return;
user.setPortrait(preferences.getString(LocalUser.KEY_PORTRAIT, null));//头像
if (user.getPortrait() == null)
return;
user.setAccount(preferences.getString(LocalUser.KEY_USERNAME, null));//账号
if (user.getAccount() == null)
return;
user.setPwd(preferences.getString(LocalUser.KEY_PASSWORD, null));//密码
if (user.getPwd() == null)
return;
user.setGender(preferences.getString(LocalUser.KEY_GENDER, null)); //性别
user.setScore(preferences.getInt(LocalUser.KEY_SKILL_SCORE, 0));//积分
AppManager.LOCAL_LOGINED_USER = user; //使用AppManager静态变量保存登录用户
}
}
- 说明:
- handler.postDelayed()方法使用了Lambda表达式.
new Handler().postDelayed(() -> {
startActivity(new Intent(StartActivity.this, MainActivity.class));
finish();
}, 2000);
项目中其他地方也大量使用了Lambda表达式, 这是java 8推出的新特性. 目前Android本身是不支持的. 好像在Android Studio 2.1之后支持了, 但是我没用过. 因此这里要在build.gradle中引入了retrolambda依赖.
- 在build.gradle中加入编译的依赖,这会使用retrolambda来编译Java代码
buildscript {
dependencies {
classpath 'me.tatarka:gradle-retrolambda:3.2.4'
}
}
- 同时要加入plugin声明
apply plugin: 'me.tatarka.retrolambda'
- 加入compileOptions,这会让IDE使用用JAVA8语法解析
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
- 指定将源码编译的级别,,使用下列代码,会将代码编译到兼容1.6的字节码格式
retrolambda {
javaVersion JavaVersion.VERSION_1_6
}
参考自:android上的JAVA8:使用retrolambda
简单的Lambda入门:使用Lambda在Android中的替代匿名类
SharePreferenceManager类
/**
* SharePreference管理类, oop管理众多的首选项文件
*/
public class SharePreferenceManager {
/**
* 获得应用的配置,目前主要是白天黑夜模式
*/
public static SharedPreferences getApplicationSetting(Context context) {
return context.getSharedPreferences(ApplicationSetting.FILE_NAME, Context.MODE_PRIVATE);
}
/**
* 获得登录用户信息
*/
public static SharedPreferences getLocalUser(Context context) {
return context.getSharedPreferences(LocalUser.FILE_NAME, Context.MODE_PRIVATE);
}
/**
* 应用配置首选项, 保存主题...一些系统级别的配置
*/
public static class ApplicationSetting {
public static final String FILE_NAME = "APPLICATION_SETTING";//应用配置
public static final String KEY_THEME = "KEY_THEME"; //主题
//应用主题的枚举
public enum ApplicationTheme {
LIGHT(1, R.style.LightTheme), //白天
DARK(2, R.style.DarkTheme); //黑夜
private int key;
private int resId;
ApplicationTheme(int key, int resId) {
this.key = key;
this.resId = resId;
}
public int getKey() {
return key;
}
public int getResId() {
return resId;
}
}
}
/**
* 专门保存用户信息
*/
public static class LocalUser {
public static final String FILE_NAME = "LOCAL_USER"; //文件名
public static final String KEY_USERNAME = "KEY_USERNAME"; //账号
public static final String KEY_PASSWORD = "KEY_PASSWORD"; //密码
public static final String KEY_GENDER = "KEY_GENDER"; //性别
public static final String KEY_NICK = "KEY_NICK"; //昵称
public static final String KEY_SKILL_SCORE = "KEY_SKILL_SCORE"; //积分
public static final String KEY_UID = "KEY_UID"; //UID唯一标识
public static final String KEY_LAST_LOGIN_TIME = "KEY_LAST_LOGIN_TIME"; //最后登录时间
public static final String KEY_LOGIN_STATE = "KEY_LOGIN_STATE"; //登录记录
public static final String KEY_PORTRAIT = "KEY_PORTRAIT"; //头像
public static final String KEY_COOKIES = "KEY_COOKIES"; //Cookies
}
}
- 说明:
- ApplicationTheme是一个枚举类. 枚举是java 5引入的新特性.
- 使用静态内部类LocalUser管理保存到首选项中的用户信息的key.
- 白天和黑夜的主题颜色设置在values/styles.xml中.
<!--==================light theme==================-->
<style name="LightTheme.Base" parent="AppTheme.Base"> //白天主题的Base
<item name="colorPrimary">@color/light_principle</item>
<item name="colorPrimaryDark">@color/light_state_bar</item>
<item name="android:listDivider">@color/light_divider</item>
<item name="hint">@color/light_hint</item>
<item name="horizontal_divider">@color/light_divider</item>
<item name="tab_item_selected">@color/light_tab_item_selected</item>
<item name="tab_item_unselected">@color/light_tab_item_unselected</item>
<item name="tab_item_underline">@color/light_tab_item_underline</item>
<item name="list_view_background">@color/light_list_item_background</item>
<item name="main_list_item_title">@color/light_main_list_item_title</item>
<item name="main_list_item_content">@color/light_main_list_item_title</item>
<item name="main_list_item_username">@color/light_main_list_item_username</item>
<item name="main_list_item_time">@color/light_main_list_item_title</item>
<item name="main_list_item_background">@drawable/selector_light_list_item</item>
<item name="main_list_item_comment_count">@color/light_main_list_item_title</item>
<item name="drawer_header_background">@color/light_drawer_header_background</item>
<item name="drawer_header_username">@color/light_drawer_header_username</item>
<item name="drawer_header_abilities">@color/light_drawer_header_abilities</item>
<item name="drawer_header_abilities_background">@color/light_drawer_header_abilities_background</item>
<item name="drawer_header_skill_score">@color/light_drawer_header_skill_score</item>
<item name="drawer_container_background">@color/light_drawer_container_background</item>
<item name="drawer_container_menu_text">@color/light_drawer_container_menu_text</item>
<item name="drawer_container_menu">@drawable/selector_light_drawer_menu</item>
<item name="func_loading_text">@color/light_func_loading_text</item>
<item name="refresh_progress_background">@color/light_refresh_progress_background</item>
<item name="detail_title_background">@color/light_detail_title_background</item>
<item name="detail_title_text">@color/light_detail_title_text</item>
<item name="detail_header_username">@color/light_detail_header_username</item>
<item name="detail_header_other">@color/light_detail_header_other</item>
<item name="detail_header_background">@color/light_detail_header_background</item>
<item name="detail_content_text">@color/light_detail_content_text</item>
<item name="detail_content_background">@color/light_detail_content_background</item>
<item name="detail_footer_text">@color/light_detail_footer_text</item>
<item name="detail_footer_background">@drawable/selector_light_detail_footer_item</item>
<item name="comment_list_item_username">@color/light_comment_list_item_username</item>
<item name="comment_list_item_time">@color/light_comment_list_item_time</item>
<item name="comment_list_item_content">@color/light_comment_list_item_content</item>
<item name="comment_list_item_background">@drawable/selector_light_list_item</item>
<item name="comment_list_item_refer_background">@drawable/shape_light_refer_item</item>
<item name="comment_list_item_refer_title">@color/light_comment_list_item_refer_title</item>
<item name="comment_list_item_refer_content">@color/light_comment_list_item_refer_content</item>
<item name="comment_list_item_refer_border">@color/light_comment_list_item_refer_border</item>
<item name="keyboard_panel_background">@color/light_keyboard_panel_background</item>
<item name="keyboard_emotion_tab_item_background">@drawable/selector_light_emotion_item</item>
<item name="keyboard_emotion_tab_item_text">@color/light_keyboard_emotion_tab_item_text</item>
<item name="keyboard_input_text">@color/light_keyboard_input_text</item>
<item name="tweet_list_item_username">@color/light_tweet_list_item_username</item>
<item name="tweet_list_item_content">@color/light_tweet_list_item_content</item>
<item name="tweet_list_item_highlight">@color/light_tweet_list_item_highlight</item>
<item name="tweet_list_item_other">@color/light_tweet_list_item_other</item>
<item name="tweet_list_item_background">@drawable/selector_light_list_item</item>
<item name="tweet_list_item_like_list_background">@color/light_tweet_list_item_like_list_background</item>
<item name="tweet_comment_list_item_username">@color/light_tweet_comment_list_item_username</item>
<item name="tweet_comment_list_item_content">@color/light_tweet_comment_list_item_content</item>
<item name="tweet_comment_list_item_time">@color/light_tweet_comment_list_item_time</item>
<item name="tweet_comment_list_item_background">@drawable/selector_light_list_item</item>
<item name="tweet_floating_action_button_background_unselected">@color/light_tweet_floating_action_button_background_unselected</item>
<item name="tweet_floating_action_button_background_selected">@color/light_tweet_floating_action_button_background_selected</item>
<item name="tweet_floating_action_button_plus">@color/light_tweet_floating_action_button_plus</item>
<item name="tweet_floating_action_button_item_background_unselected">@color/light_tweet_floating_action_button_item_background_unselected</item>
<item name="tweet_floating_action_button_item_background_selected">@color/light_tweet_floating_action_button_item_background_selected</item>
<item name="tweet_floating_cover">@color/light_tweet_floating_cover</item>
<item name="login_background">@color/light_login_background</item>
<item name="login_form_username">@color/light_login_form_username</item>
<item name="login_form_password">@color/light_login_form_password</item>
<item name="login_form_hint">@color/light_login_form_hint</item>
<item name="login_form_error">@color/light_login_form_error</item>
<item name="login_text">@color/light_login_text</item>
<item name="dialog_opinion_background">@drawable/selector_light_opinion_item</item>
<item name="dialog_text">@color/light_dialog_text</item>
<item name="tweet_publish_editor_background">@color/light_tweet_publish_editor_background</item>
<item name="tweet_publish_editor_text">@color/light_tweet_publish_editor_text</item>
<item name="tweet_publish_emotion_navigation">@color/light_tweet_publish_emotion_navigation</item>
<item name="user_home_username">@color/light_user_home_username</item>
<item name="user_home_join_time">@color/light_user_home_join_time</item>
<item name="user_home_coordinate">@color/light_user_home_coordinate</item>
<item name="user_home_statistic">@color/light_user_home_statistic</item>
<item name="user_home_statistic_border">@color/light_user_home_statistic_border</item>
<item name="user_home_blow_background">@color/light_user_home_blow_background</item>
<item name="user_home_blow_row">@color/light_user_home_blow_row</item>
<item name="user_home_blow_label">@color/light_user_home_blow_label</item>
<item name="user_home_blow_label_value">@color/light_user_home_blow_label_value</item>
<item name="user_home_blow_label_value_background">@drawable/shape_light_user_home_label_value</item>
</style>
<!--======================Dark Theme========================-->
<style name="DarkTheme.Base" parent="AppTheme.Base">
//配置的属性一样,省略
</style>
<style name="LightTheme" parent="LightTheme.Base" /> //白天主题
<style name="DarkTheme" parent="DarkTheme.Base" /> //黑夜主题
- 目前只看到了设置这些属性值, 具体在哪里应用到了, 目前还没读到, 待之后补充.
//TODO: 找到在哪里需要这些主题属性值的代码
DeviceManager类
/**
* 设备管理类
*/
public class DeviceManager {
private static ConnectivityManager mCnnManager; //网络连接管理
private static InputMethodManager mSoftInputManager; //输入法管理
/**
* 获得网络连接管理对象
*/
public static ConnectivityManager getCnnManager(Context context) {
if (mCnnManager == null)
mCnnManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
return mCnnManager;
}
/**
* 获得输入法管理对象
*/
public static InputMethodManager getSoftInputManager(Context context) {
if (mSoftInputManager == null)
mSoftInputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
return mSoftInputManager;
}
/**
* 获得剪切板管理对象
*/
public static ClipboardManager getClipboardManager(Context context) {
return (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
}
/**
* 检测是否有网络. getActiveNetworkInfo()获得NetworkInfo()对象,该类是对网络信息的描述
*/
public static boolean hasInternet(Context context) {
return getCnnManager(context).getActiveNetworkInfo() != null && getCnnManager(context).getActiveNetworkInfo().isAvailable();
}
/**
* 网络类型
*/
public static int getInternetType(Context context) {
return getCnnManager(context).getActiveNetworkInfo().getType();
}
/**
* 关闭软键盘. getWindowToken()返回的是附加到window上view的唯一标识token.
*/
public static void hideSoftInput(Context context, View view) {
if (view == null)
return;
getSoftInputManager(context).hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
BaseActivity类
/**
* Activity的基类
*/
public abstract class BaseActivity<P extends Presenter> extends NucleusActivity<P> {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 主题选择,从首选项中获得保存的主题
SharedPreferences preferences = SharePreferenceManager.getApplicationSetting(this);
int theme = preferences.getInt(ApplicationSetting.KEY_THEME, ApplicationTheme.LIGHT.getKey());
//使用setTheme()设置白天和黑夜主题
if (theme == ApplicationTheme.LIGHT.getKey()) {
setTheme(ApplicationTheme.LIGHT.getResId());
} else if (theme == ApplicationTheme.DARK.getKey()) {
setTheme(ApplicationTheme.DARK.getResId());
}
// 方向锁定, 设置为垂直方向
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Override
protected void onPause() {
super.onPause();
//isFinishing()常用在onPause()中判断activity仅仅是pause还是彻底的finish
if (isFinishing()) {
//隐藏输入法
DeviceManager.hideSoftInput(this, getCurrentFocus());
}
}
}
- 说明
- setRequestedOrientation 改变当前activity的屏幕朝向
// TODO: 目前对MVP模式不是太熟悉, 等以后完成架构分析
- setRequestedOrientation 改变当前activity的屏幕朝向