0. 介绍
此文将对Github上lguipeng大神所开发的 极简笔记 v2.0
(点我下载源码)代码进行分析学习。
通过此文你将学到:
- 应用源码的研读方法
- MVP架构模式
- Application的应用
- Degger2依赖注入框架
- 搜索控件的使用
- ButterKnife库的使用
- Material主题
- RecyclerView等新控件的用法
- Lambda表达式
- Java自定义注解
- aFinal框架
1. Manifest入手
1.1 权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
声明了网络与储存读写相关权限,至于网络权限笔者猜测应该是用于印象笔记的同步吧。
1.2 Application层
android:name=".App"
在Application层发现了一个奇怪的属性,然后又发现项目结构目录中有个继承自Application的类,顿时疑惑。经查阅后又联想到包建强的《App研发录》中提到彻底结束安卓程序进程需要用到继承Application的类来记录已经打开的Activity,然后统一结束它们,如代码所示:
public class App extends Application {
public List<Activity> activities=new ArrayList<Activity>();
}
Manifest进行注册:
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:name=".App" >
每个Activity中的做法如下:
//首先:onCreate()方法里边:
App app = (App) getApplicationContext();// 获取应用程序全局的实例引用
app.activities.add(this); // 把当前Activity放入集合中
//然后:onDestroy()方法里边做法:
@Override
protected void onDestroy() {
super.onDestroy();
App app = (App) getApplication();// 获取应用程序全局的实例引用
app.activities.remove(this); // 把当前Activity从集合中移除
}
//最后:在程序中需要结束时的做法:
List<Activity> activities = app.activities;
for (Activity act : activities) {
act.finish();// 显式结束
}
我想此处亦是同样原理。
补充Application相关知识点:
- 创建一个类继承Application并在manifest的application标签中进行注册
- 生命周期等于这个程序的生命周期
- 通常用于数据传递、数据共享、数据缓存等操作
- onTerminate() 当终止应用程序对象时调用 onLowMemory() 当后台程序已经终止资源还匮乏时会调用
1.2.1 探索继承自Application的App类
类中定义了以下方法:
private void initializeInjector() {
mAppComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}
通过DaggerAppComponent可以发现使用了Dagger2库,那么Dagger库又是什么呢?继续探索…
1.2.1.1 Dagger2介绍
在此之前,需要先了解依赖注入,在本人看来其实就是低级类对高级类的依赖关系,它有以下好处:
- 依赖的注入和配置独立于组件之外
- 因为对象是在一个独立、不耦合的地方初始化,所以当注入抽象方法的时候,我们只需要修改对象的实现方法,而不用大改代码库
- 依赖可以注入到一个组件中:我们可以注入这些依赖的模拟实现,这样使得测试更加简单
而Dagger2就是Google基于java的依赖注入标准维护的一个库。
1.2.1.1 Dagger2的使用
第一步: 添加编译和运行库
dependencies {
apt 'com.google.dagger:dagger-compiler:2.0'
compile 'com.google.dagger:dagger:2.0'
...
}
第二步: 构建依赖
@Module
public class ActivityModule {
@Provides UserModel provideUserModel() {
return new UserModel();
}
}
第三步: 构建Injector
@Component(modules = ActivityModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
}
第三步: 完成依赖注入
public class MainActivity extends ActionBarActivity {
private ActivityComponent mActivityComponent;
@Inject UserModel userModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mActivityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule()).build();
mActivityComponent.inject(this);
((TextView) findViewById(R.id.user_desc_line)).setText(userModel.id + "\n" + userModel.name + "\n" + userModel.gender);
}
...
}
1.3 Activity层
<activity
android:name=".ui.MainActivity"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize|stateHidden"
android:screenOrientation="portrait">
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
由标签里的内容可以看出该Activity是程序启动的主Activity,如图:
此外,还有一点值得注意:
1.3.1 搜索功能的使用方法
搜索有两种实现方式,默认搜索框(比如Toolbar上面的)和搜索控件(可以在Layout里面声明的SearchView),一般采用默认的搜索框方式即可,此处也只简单讲讲此方式,如要了解更多可以去阅读官方文档的创建搜索界面
1.3.1.1 创建搜索配置文件
主要是对搜索框样式的配置,文件保存在res/xml/searchable.xml
:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_label"
android:hint="@string/search_hint" >
</searchable>
1.3.1.2 创建Activity并注册
注册Activity有两个要点,一个是接收Intent.ACTION_SEARCH,另一个是搜索框的配置文件地址:
<application ... >
<activity android:name=".SearchableActivity" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable"/>
</activity>
...
</application>
1.3.1.3 执行搜索过程
搜索的执行过程又分为3步:
- 接收查询: 收到Intent数据获取到搜索内容执行搜索
- 搜索你的资料: 通过SQLite的FTS3方式搜索或进行在线搜索
- 呈现结果: 使用ListView等展示结果
此处展示接收查询的示例代码:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
// Get the intent, verify the action and get the query
Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
doMySearch(query);
}
}
1.3.1.4 进行实时搜索
如果要进行实时搜索,需要在Activity中重写onSearchRequested()方法,返回true代表成功消耗此请求,示例代码如下:
@Override
public boolean onSearchRequested() {
Bundle appData = new Bundle();
appData.putBoolean(SearchableActivity.JARGON, true);
startSearch(null, false, appData, false);
return true;
}
// startSearch()中
Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
if (appData != null) {
boolean jargon = appData.getBoolean(SearchableActivity.JARGON);
}
2. 攻入MainActivity
2.1 ButterKnife
public class MainActivity extends BaseActivity implements MainView{
@Bind(R.id.toolbar) Toolbar toolbar;
@Bind(R.id.refresher) SwipeRefreshLayout refreshLayout;
...
}
打开MainActivity。映入眼帘的是熟悉的ButterKnife,此处回顾一下ButterKnife的使用。