《极简笔记》源码分析(一)

本文详细分析了《极简笔记》App的源码,涵盖MVP架构、Dagger2依赖注入、搜索功能、ButterKnife库、Material Design主题等关键点。通过对AndroidManifest的权限分析,Application层的Dagger2使用,以及MainActivity的生命周期、布局文件和搜索功能的实现,展示了应用的核心设计和实现技巧。同时,还介绍了如何处理Activity的生命周期、使用自定义注解以及数据库操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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,如图:
主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的使用。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值