GVKun编程网logo

Android Architecture Components 系列(二) LifeCycle(android clean architecture)

1

这篇文章主要围绕AndroidArchitectureComponents系列和二LifeCycle展开,旨在为您提供一份详细的参考资料。我们将全面介绍AndroidArchitectureCompo

这篇文章主要围绕Android Architecture Components 系列二 LifeCycle展开,旨在为您提供一份详细的参考资料。我们将全面介绍Android Architecture Components 系列的优缺点,解答二 LifeCycle的相关问题,同时也会为您带来./src/components/CustomNavbar.jsx找不到模块:无法解析“ / Users / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”、./src/Components/Pages/About.js 未找到模块:无法解析“C:\Users\user\Desktop\yat2\yoaz\src\Components\Pages”中的“../logo.svg”、An Overview of the Android Architecture (Android Studio)、Android Architecture Components Part1:Room的实用方法。

本文目录一览:

Android Architecture Components 系列(二) LifeCycle(android clean architecture)

Android Architecture Components 系列(二) LifeCycle(android clean architecture)

Handling LifeCycle
android.arch.lifecycle 提供的类和接口,让使用者构建能够感知生命周期。
Lifecycle is a class that holds the information about the lifecycle state of a component (like an activity or a fragment) and allows other objects to observe this state.
    根据 Activity or fragment 的生命周期自行调整类的行为通过观察其状态
Lifecycle uses two main enumerations to track the lifecycle status for its associated component:
 
    AAC 中提供了 LifeCycle 使用枚举类来解决生命周期管理问题。
  •       持有 Activity/Fragment 生命周期类
  •       通过接口 LifecycleRegistryOwner /LifecycleObserver 注解事件 @OnLifecycleEvent (),以及外部调用观察者模式 addObserver (mTx),来完成将 (Activity/Fragment)” 生命周期” 共享给其他组件这么一件事
  •     事件
    生命周期事件由系统来分发,这些事件对应与 Activity 和 Fragment 的生命周期函数
    (ON_CREATE,ON_START,ON_RESUME,ON_PAUSE,ON_STOP,ON_DESTROY)
  •      状态
    LifeCycle 的状态,用于追踪 lifecycle 对象: (INITIALIZED,DESTROYED,CREATED,STARTED,RESUMED)
 
ps:在 STARTED 和 RESUMED 状态是处于活跃状态,只有在这两个状态下 LivaData 是会通知数据变化的。
 
 
 
ps 考虑一个问题: 
LifeCycle 是如何感知到 Activity 或是 Fragment 的生命周期的呢?
 
因为 AAC 是基于 MVVM 架构的所以首先开一下 MVP 和 MVVM 的感知生命周期操作。
 
(1)MVP 感知生命周期的方法
    最开始的 attach 和 detach ,通过 Activity 或是 Fragment 中生命周期函数去关联 Presenter,之后判断 View 是否是 Active 的来决定是否更新 Ui。因为 Retrofit 和 RxJava 的兴起,可以将 Presenter 中的动作变成一个流事件。通过 RxJava 特效通过解除订阅的方式来控制 Presenter 中的更新 Ui 的动作。后面有出了 RxLifecycle,通过细微控制到每一个生命周期函数,更进一步的感知处理每个生命周期函数。
 
(2)MVVM 感知生命周期的方法
创造一个 MVVM ViewModel 接口 ,里面包含所有的生命周期回掉的方法,然后在 Aor f 中的各个生命周期函数中调用。
 
(3)官方的 MVVM 感知生命周期的方法
在《使用 ContentProvider 初始化你的 Library》 一文中,作者提到使用了 ContentProvider 进行 library 的初始化,并通过其控制生命周期函数
http://zjutkz.net/2017/09/11/%E4%B8%80%E4%B8%AA%E5%B0%8F%E6%8A%80%E5%B7%A7%E2%80%94%E2%80%94%E4%BD%BF%E7%94%A8ContentProvider%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BD%A0%E7%9A%84Library/
 
LifeCycle 源码分析:
<provider 
android:name = “android.arch.lifecycle.LifecycleRuntimeTrojanProvider"
android:exported = “fasle”
android:multiporcess = “true”
android:authoritites = "com.example.hbl.mbbm.lifecycle-trojan"
/>
 
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class LifecycleRuntimeTrojanProviderextends ContentProvider {
    @Override
    public boolean onCreate() {
       LifecycleDispatcher .init (getContext () ); // 初始化生命周期控制的方法
        ProcessLifecycleOwner.init( getContext() );
        return true;
        }
  }
在 LifecycleDispatcher () 方法中 又是如何操作的呢?
     Class LifecycleDispatcher{
            private static final String REPORT_FRAGMENT_TAG = “android.arch.lifecycle"
                            + “.LifecycleDispatcher.report_fragment_tag” ;
            private static AtomicBooleansInitialized= new AtomicBoolean ( false);
            
            static void init (Context context) {
                if(sInitialized .getAndSet (true) ){
                        return ;
               }else {
                 ( (Application)context .getApplicationContext() ). registerActivityLifecycleCallbacks
                                                                                             (new DispatcherActivityCallback());
            }
        }
解析:通过 AtomicBoolean 来控制初始化一次,之后获取 ApplicationContext 并设置 ActivityLifecycleCallback 回调。
    ps:AtomicBoolean 函数在退出 app 的时候可以用到
 
在 DispatcherActivityCallback 中:
在 DispatcherActivityCallback () 构造函数中
1、创建了一个 FragmentCallback 对象,用于设置 Fragment 的生命周期。
2、在 onActivityCreated () 函数中 instanceof 一个 FragmentActivity,注入一股 ReportFragment 到当前 Activity
3、在 ReportFragment 中,将这个 Fragment 添加到当前 Activity 中,让当前的 fragment 绑定到 Activity 的生命周期中
 
4、之后通过 onActivityCreate () 函数中的 dispatch () 方法把当前生命周期分发到对应的 LifecycleOwner 中
5、通过这种方法,给 Activity or Fragment 添加其他额外的 fragment,来获取当前的 Activity 或是 Fragment 的生命周期。然后判断当前的 Activity 或是 Fragment 是否是 LifeCycleRegistryOwner 的。如果是,那么就分发当前的生命周期事件到当前的 Owner 中,以达到生命周期的传递操作
 
  • 官方 LifeCycle 的使用案例:
(一)创建监听器
classMyLocationListener{
    publicMyLocationListener(Contextcontext,Callbackcallback){
        // ...
    }
    voidstart(){
        // connect to system location service
    }
    voidstop(){
       // disconnect from system location service
    }
}
在需要的 Activity 中绑定监听器
privateMyLocationListenermyLocationListener;
@Override
    publicvoidonCreate(...){
        myLocationListener =newMyLocationListener(this,(location)->{
            // update UI
        });
    }
 @Override
    publicvoidonStart(){
        super.onStart();
        myLocationListener.start();
        // manage other components that need to respond
        // to the activity lifecycle
    }
    @Override
    publicvoidonStop(){
        super.onStop();
        myLocationListener.stop();
        // manage other components that need to respond
        // to the activity lifecycle
    }
 
 
(二)创建观察者对象 
publicclassMyObserverimplementsLifecycleObserver{
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    publicvoidconnectListener(){
        ...
    }
   @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    publicvoiddisconnectListener(){
        ...
    }
}
myLifecycleOwner.getLifecycle().addObserver(newMyObserver());
(三)实现 LifeCycleOwner 绑定 Activity 或是 Fragment 生命周期
publicclassMyActivityextendsActivityimplementsLifecycleOwner{
    privateLifecycleRegistrymLifecycleRegistry;
    @Override
    protectedvoidonCreate(BundlesavedInstanceState){
        super.onCreate(savedInstanceState);
        mLifecycleRegistry =newLifecycleRegistry(this);
        mLifecycleRegistry.markState(Lifecycle.State.CREATED);
    }
    @Override
    publicvoidonStart(){
        super.onStart();
        mLifecycleRegistry.markState(Lifecycle.State.STARTED);
    }
    @NonNull
    @Override
    publicLifecyclegetLifecycle(){
        returnmLifecycleRegistry;
    }
}
 
  • 一个有关 LifeCycle 的小 Ex:
    1、定义一个类实现 LifeCycleObserver 方法 
    2、定义 2 个状态变量 
    3、自定义类实现 LifecycleObserver 接口,并添加 Lifecycle 的生命周期绑定注解
class MyView extends TextView implements LifecycleObserver{
 
private boolean lifeCycleEnable;
private Lifecycle lifecycle;
// 添加构造方法
public boolean isLifeCycleEnable() {
    return lifeCycleEnable;
}
 
public void setLifeCycleEnable(boolean lifeCycleEnable) {
    this.lifeCycleEnable = lifeCycleEnable;
}
public Lifecycle getLifecycle() {
    return lifecycle;
}
// ****************** lifeCycle 生命周期函数事件 ******************
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void create() {
    if (lifeCycleEnable) {
        String text = System.currentTimeMillis() + "-create/n";
        Log.i(TAG, text);
        this.setText(text);
        }
    }
// 同理 Lifecycle.Event.ON_其他事件 ON_START 、ON_PAUSE、ON_STOP、ON_RESUME、ON_DESTROY、ON_ANY
}    
 
在 Activity 中的使用:
publicclass XActivity extends AppCompatActivity implements LifecycleRegistryOwner {
    privateLifecycleRegistry lifecycleRegistry =newLifecycleRegistry(this);
            // 在 onCreate()函数中初始化控件 mtx
            mtx .setLifecycle(getLifecycle()); 
//lifecycle 观察者  LifecycleObserver:自定义的类 MyView
//lifecycle 注册拥有者 LifecycleRegistryOwner:XActivity
            getLifecycle ().addObserver (mtx); // 添加观察者角色
            mtx .setLifeCycleEnable(true);    
        @Override 
     public LifecycleRegistry getLifecycle() {
             return lifecycleRegistry; 
        }
}
 
按 home 键进行观察日志:
creat -> start -> resume -> pause -> stop -> start -> resume
02-24 16:18:31.188 4694-4694/proxy.lifecycledemo E/MyView: Hello World!-creat
02-24 16:18:31.198 4694-4694/proxy.lifecycledemo E/MyView:-start
02-24 16:18:31.198 4694-4694/proxy.lifecycledemo E/MyView:-resume
02-24 16:32:46.058 4694-4694/proxy.lifecycledemo E/MyView:-pause
02-24 16:32:46.798 4694-4694/proxy.lifecycledemo E/MyView:-stop
02-24 16:32:47.988 4694-4694/proxy.lifecycledemo E/MyView:-start
02-24 16:32:47.988 4694-4694/proxy.lifecycledemo E/MyView:-resume
 
解析:LifecycleOwner 是一个只有一个方法的接口 getLifecycle (),需要由子类来实现。
        在 Lib 中已经有实现好的子类,我们可以直接拿来使用。比如 LifecycleActivity 和 LifecycleFragment,我们只需要继承此类就行了。
        当然实际开发的时候我们会自己定义 BaseActivity,Java 是单继承模式,那么需要自己实现 LifecycleRegistryOwner 接口。
如下所示即可,代码很近简单
public class BaseFragment extends Fragment implements LifecycleRegistryOwner {
    LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
    @Override
    public LifecycleRegistry getLifecycle() {
        return lifecycleRegistry;
    }
}
 

Lifecycle 的最佳建议

  • 保持 UI Controllers(Activity/Fragment)中代码足够简洁。一定不能包含如何获取数据的代码,要通过 ViewModel 获取 LiveData 形式的数据。
  • 用数据驱动 UI,UI 的职责就是根据数据改变显示的内容,并且把用户操作 UI 的行为传递给 ViewModel。
  • 把业务逻辑相关的代码放到 ViewModel 中,把 ViewModel 看成是链接 UI 和 App 其他部分的胶水。但 ViewModel 不能直接获取数据,要通过调用其他类来获取数据。
  • 使用 DataBinding 来简化 View(布局文件)和 UI Controllers(Activity/Fragment)之间的代码
  • 如果布局本身太过复杂,可以考虑创建一个 Presenter 类来处理 UI 相关的改变。虽然这么做会多写很多代码,但是对于保持 UI 的简介和可测试性是有帮助的。
  • 不要在 ViewModel 中持有任何 View/Activity 的 context。否则会造成内存泄露。

 

系列文章列表:
   Android Architecture Components 系列(一)初识
   Android Architecture Components 系列(三) LiveData
   Android Architecture Components 系列(四)ViewModel
   Android Architecture Components 系列(五)Room
   Android Architecture Components 系列(六)Paging Library
   Android Architecture Components 系列(七)WorkManager
        Android Architecture Components 系列(八)小结

 

./src/components/CustomNavbar.jsx找不到模块:无法解析“ / Users / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”

./src/components/CustomNavbar.jsx找不到模块:无法解析“ / Users / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”

如何解决./src/components/CustomNavbar.jsx找不到模块:无法解析“ / Users / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”

继续收到此错误,不确定我在做什么错

编译失败 ./src/components/CustomNavbar.jsx 找不到模块:无法解析“ / Users / mikemutabazi / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”

代码

id    date      product  early_product
1   2010-02-01     c         c
1   2010-02-02     v         c
1   2010-02-03     d         c
1   2010-02-04     g         c
2   2010-02-03     h         h
2   2010-02-04     w         h
2   2010-02-05     t         h
2   2010-02-06     d         h
3   2010-02-04     x         x
3   2010-02-05     f         x
3   2010-02-06     x         x

./src/Components/Pages/About.js 未找到模块:无法解析“C:\Users\user\Desktop\yat2\yoaz\src\Components\Pages”中的“../logo.svg”

./src/Components/Pages/About.js 未找到模块:无法解析“C:\Users\user\Desktop\yat2\yoaz\src\Components\Pages”中的“../logo.svg”

如何解决./src/Components/Pages/About.js 未找到模块:无法解析“C:\\Users\\user\\Desktop\\yat2\\yoaz\\src\\Components\\Pages”中的“../logo.svg”

请帮忙,我正在尝试将 logo.svg 导入 about.js 页面。 About.js 被放置在组件下的 Pages 文件夹中,但我似乎不知道显示它的最佳方式,我尝试以所有可能的方式引用它我知道我enter image description here 不断收到错误{{ 3}}

An Overview of the Android Architecture (Android Studio)

An Overview of the Android Architecture (Android Studio)


http://www.techotopia.com/index.php/An_Overview_of_the_Android_Architecture_(Android_Studio)


So far in this book, steps have been taken to set up an environment suitable for the development of Android applications using Android Studio. An initial step has also been taken into the process of application development through the creation of a simple Android Studio application project.

Before delving further into the practical matters of Android application development, however, it is important to gain an understanding of some of the more abstract concepts of both the Android SDK and Android development in general. Gaining a clear understanding of these concepts now will provide a sound foundation on which to build further knowledge.Starting with an overview of the Android architecture in this chapter, and continuing in the next few chapters of this book, the goal is to provide a detailed overview of the fundamentals of Android development.

The Android Software Stack

Android is structured in the form of a software stack comprising applications, an operating system, run-time environment, middleware, services and libraries. This architecture can, perhaps, best be represented visually as outlined in Figure 8-1. Each layer of the stack, and the corresponding elements within each layer, are tightly integrated and carefully tuned to provide the optimal application development and execution environment for mobile devices.


Figure 8-1


The remainder of this chapter will work through the different layers of the Android stack, starting at the bottom with the Linux Kernel.

The Linux Kernel

Positioned at the bottom of the Android software stack, the Linux Kernel provides a level of abstraction between the device hardware and the upper layers of the Android software stack. Based on Linux version 2.6, the kernel provides preemptive multitasking, low-level core system services such as memory, process and power management in addition to providing a network stack and device drivers for hardware such as the device display, Wi-Fi and audio.

The original Linux kernel was developed in 1991 by Linus Torvalds and was combined with a set of tools, utilities and compilers developed by Richard Stallman at the Free Software Foundation to create a full operating system referred to as GNU/Linux. Various Linux distributions have been derived from these basic underpinnings such as Ubuntu and Red Hat Enterprise Linux.

It is important to note, however, that Android only uses the Linux kernel. That said, it is worth noting that the Linux kernel was originally developed for use in traditional computers in the form of desktops and servers. In fact, Linux is now most widely deployed in mission critical enterprise server environments. It is a testament to both the power of today’s mobile devices and the efficiency and performance of the Linux kernel that we find this software at the heart of the Android software stack.

Android Runtime - ART

When an Android app is built within Android Studio it is compiled into an intermediate bytecode format (referred to as DEX format). When the application is subsequently loaded onto the device, the Android Runtime (ART) uses a process referred to as Ahead-of-Time (AOT) compilation to translate the bytecode down to the native instructions required by the device processor. This format is known as Executable and Linkable Format (ELF).

Each time the application is subsequently launched, the ELF executable version is run, resulting in faster application performance and improved battery life.

This contrasts with the Just-in-Time (JIT) compilation approach used in older Android implementations whereby the bytecode was translated within a virtual machine (VM) each time the application was launched.

Android Libraries

In addition to a set of standard Java development libraries (providing support for such general purpose tasks as string handling, networking and file manipulation), the Android development environment also includes the Android Libraries. These are a set of Java-based libraries that are specific to Android development. Examples of libraries in this category include the application framework libraries in addition to those that facilitate user interface building, graphics drawing and database access.

A summary of some key core Android libraries available to the Android developer is as follows:
  • android.app – Provides access to the application model and is the cornerstone of all Android applications.
  • android.content – Facilitates content access, publishing and messaging between applications and application components.
  • android.database – Used to access data published by content providers and includes SQLite database management classes.
  • android.graphics – A low-level 2D graphics drawing API including colors, points, filters, rectangles and canvases.
  • android.hardware – Presents an API providing access to hardware such as the accelerometer and light sensor.
  • android.opengl – A Java interface to the OpenGL ES 3D graphics rendering API.
  • android.os – Provides applications with access to standard operating system services including messages, system services and inter-process communication.
  • android.media – Provides classes to enable playback of audio and video.
  • android.net – A set of APIs providing access to the network stack. Includes android.net.wifi, which provides access to the device’s wireless stack.
  • android.print – Includes a set of classes that enables content to be sent to configured printers from within Android applications.
  • android.provider – A set of convenience classes that provide access to standard Android content provider databases such as those maintained by the calendar and contact applications.
  • android.text – Used to render and manipulate text on a device display.
  • android.util – A set of utility classes for performing tasks such as string and number conversion, XML handling and date and time manipulation.
  • android.view – The fundamental building blocks of application user interfaces.
  • android.widget - A rich collection of pre-built user interface components such as buttons, labels, list views, layout managers, radio buttons etc.
  • android.webkit – A set of classes intended to allow web-browsing capabilities to be built into applications.

Having covered the Java-based libraries in the Android runtime, it is now time to turn our attention to the C/C++ based libraries contained in this layer of the Android software stack.

C/C++ Libraries

The Android runtime core libraries outlined in the preceding section are Java-based and provide the primary APIs for developers writing Android applications. It is important to note, however, that the core libraries do not actually perform much of the actual work and are, in fact, essentially Java “wrappers” around a set of C/C++ based libraries. When making calls, for example, to the android.opengl library to draw 3D graphics on the device display, the library actually ultimately makes calls to the OpenGL ES C++ library which, in turn, works with the underlying Linux kernel to perform the drawing tasks.C/C++ libraries are included to fulfill a wide and diverse range of functions including 2D and 3D graphics drawing, Secure Sockets Layer (SSL) communication, SQLite database management, audio and video playback, bitmap and vector font rendering, display subsystem and graphic layer management and an implementation of the standard C system library (libc).

In practice, the typical Android application developer will access these libraries solely through the Java based Android core library APIs. In the event that direct access to these libraries is needed, this can be achieved using the Android Native Development Kit (NDK), the purpose of which is to call the native methods of non-Java programming languages (such as C and C++) from within Java code using the Java Native Interface (JNI).

Application Framework

The Application Framework is a set of services that collectively form the environment in which Android applications run and are managed. This framework implements the concept that Android applications are constructed from reusable, interchangeable and replaceable components. This concept is taken a step further in that an application is also able to publish its capabilities along with any corresponding data so that they can be found and reused by other applications.

The Android framework includes the following key services:

  • Activity Manager – Controls all aspects of the application lifecycle and activity stack.
  • Content Providers – Allows applications to publish and share data with other applications.
  • Resource Manager – Provides access to non-code embedded resources such as strings, color settings and user interface layouts.
  • Notifications Manager – Allows applications to display alerts and notifications to the user.
  • View System – An extensible set of views used to create application user interfaces.
  • Package Manager – The system by which applications are able to find out information about other applications currently installed on the device.
  • Telephony Manager – Provides information to the application about the telelphony services available on the device such as status and subscriber information.
  • Location Manager – Provides access to the location services allowing an application to receive updates about location changes.

Applications

Located at the top of the Android software stack are the applications. These comprise both the native applications provided with the particular Android implementation (for example web browser and email applications) and the third party applications installed by the user after purchasing the device.

Summary

A good Android development knowledge foundation requires an understanding of the overall architecture of Android. Android is implemented in the form of a software stack architecture consisting of a Linux kernel, a runtime environment and corresponding libraries, an application framework and a set of applications. Applications are predominantly written in Java and compiled down to bytecode format within the Android Studio build environment. When the application is subsequently installed on a device, this bytecode is compiled down by the Android Runtime (ART) to the native format used by the CPU. The key goals of the Android architecture are performance and efficiency, both in application execution and in the implementation of reuse in application design.



Android Architecture Components Part1:Room

Android Architecture Components Part1:Room

前言

Android Architecture Components(AAC)首次发布与 2017 GoogleI/O 大会,经过近一年的维护,现在 Google 团队已经发布了稳定版(v1.1.1)。能够更好的帮助我们来构建自己的 App 应用,如果你还没有了解 ACC 现在时间刚刚好,来不及解释,赶紧上车吧。

ACC 是一个架构组件,它能帮忙我们更好的来管理我们的 App,方便我们的开发。它能帮助我们的 App 更好的存储数据、管理生命周期、进行模块化、避免常见的错误、减少样板文件的编写。

ACC 主要由 4 个单一组件组成,分别为:Room、LiveData、Lifecycle 与 ViewModel。它们每一个都是独立存在的组件,我们可以单独使用其中几个,又或者可以将它们全部整合到一起。所以对于 ACC 它提供了更好的使用灵活性,方便我们集成到我们的 App 中。

今天主要是对 ACC 其中的 Room 组件进行分析。Room 是一个稳健的 SQL 对象映射库,用来帮助我们快速的实现数据本地存储。至于为何要使用本地数据库,自然是当用户无网络或者网络差的时候,能够更好的提高用户对我们 App 的体验。

添加依赖

在使用 Room 之前,我们还是要在项目中对其进行依赖添加。 首先在你的项目的根目录下的 build.gradle 中添加 google () 库,代码如下:

allprojects {
    repositories {
        jcenter()
        google()
    }
}

之后打开你的 App 或者 module 中的 build.gradle 文件,在 dependencies 中添加如下代码:

dependencies {
    def room_version = "1.1.0" // or, for latest rc, use "1.1.1-rc1"
 
    implementation "android.arch.persistence.room:runtime:$room_version"
    annotationProcessor "android.arch.persistence.room:compiler:$room_version"
 
    // optional - RxJava support for Room
    implementation "android.arch.persistence.room:rxjava2:$room_version"
 
    // optional - Guava support for Room, including Optional and ListenableFuture
    implementation "android.arch.persistence.room:guava:$room_version"
 
    // Test helpers
    testImplementation "android.arch.persistence.room:testing:$room_version"
}

Room

上面的依赖添加完成后,接下来我们可以正式使用 Room。在 Android App 中进行本地数据的存储都是使用 SQLite,当我们使用原生的 SQLite 进行本地数据库的编写时,我们不仅要定义数据库结构,还要创建 SQLiteHelper,编写一连串的 SQL 语句。这样代码量与复杂度不断上升,这不是我们想要的。而 Room 正好可以帮助我们减少代码、简化复杂度。

对于 Room 的使用主要由三部分构成:

  1. Entity:标识数据库中的表结构
  2. DAO: 标识提供获取数据库表中的数据方法
  3. Database:标识所需要创建的数据库

以上三部分在代码中都是通过注释来实现,从而达到代码的精简。

Entity

Entity 作用在 model 上,即我们与数据表中的字段所匹配的 model 类。现在我们来建立一个联系人相关的 model,对于正常的 model 建立如下:

data class ContactsModel(val id: Int, val name: String, val phone: String)

现在我们要把 ContactsModel 映射到数据库中的一种表,只需进行如下操作:

@Entity(tableName = "contacts")
data class ContactsModel(
        @PrimaryKey
        @ColumnInfo(name = "contacts_id")
        val id: Int,
        @ColumnInfo(name = "name")
        val name: String,
        @ColumnInfo(name = "phone")
        val phone: String
)

首先我们在 ContactsModel 中添加 @Entity 注释,表明它将映射成一种表。在 Entity 中可以通过使用 tableName 来为该表命名,这里将其命名未 contacts。

除此之外,使用 @ColumnInfo 来标明表中的字段,@PrimaryKey 来标明表的主键。其中 @ColumnInfo 也可以通过 (name = "name") 来命名字段名。当然还有别的注释例如外键的标明:@ForeignKey

DAO

数据库表建好了,现在是提供操作数据表中的数据的方法。

@Dao
interface ContactsDao {
 
    @Query("SELECT * FROM contacts")
    fun getAllContacts(): List<ContactsModel>
 
    @Query("SELECT * FROM contacts WHERE contacts_id = :id")
    fun getContactsById(id: Int): LiveData<ContactsModel>
 
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertContacts(contactsModel: ContactsModel)
 
    @Query("UPDATE contacts SET name = :name AND phone = :phone WHERE contacts_id = :id")
    fun updateContacts(id: Int, name: String, phone: String)
 
    @Query("DELETE FROM contacts WHERE contacts_id = :id")
    fun deleteContacts(id: Int)

这里我们只需创建一个接口,通过 @Dao 来标明它是提供操作数据表的方法集。要注意它必须为 interface,在接口中我们只需定义接口方法即可。与平常的接口方法定义不同的是,我们必须在每一个接口方法上通过注释来标明该方法的作用。

例如 getAllContacts () 方法,我们为了让它实现获取 contacts 表中的所有数据,我们需要在其方法中添加 @Query 注释,由于是查询方法,自然是使用 Query,如果是插入方法就是 Insert (第三个方法)。其次 () 中的内容就是正常的查询语句。这里是获取所有的 Contacts,所以我们使用

@Query("SELECT * FROM contacts")

对于有参数的 sql 语句编写,可以查看第二个方法,参数值只需在对应的方法参数名前加入:前缀,这就是传参的格式。

@Query("SELECT * FROM contacts WHERE contacts_id = :id")
fun getContactsById(id: Int): LiveData<ContactsModel>

Room 就是这么简单,通过定义接口与接口方法的形式,再结合注释来简化代码量与复杂度。当然最终 Room 会根据注释,编译器会帮我们实现这些接口方法。我们可以 build 项目,然后我们就可以搜索到 ContactsDao_Impl 类,这个读者可以自行尝试。本质是 ContactsDao_Impl 实现了 ContactsDao 接口。

Room 的强大之一是:它可以在编译时检测你的 SQL 语句是否编写正确,如果编写错误将导致编译失败。这样就可以避免 App 在运行时导致崩溃。这个读者可以自行测试一下。

Database

现在数据表有了,对表的操作方法也有了,最后就差数据库来保存各个数据表了。Talk is cheap. Show me the code。

@Database(entities = arrayOf(ContactsModel::class), version = 1)
abstract class ContactsDataBase : RoomDatabase() {
 
    abstract fun contactsDao(): ContactsDao
 
    companion object {
        private var instance: ContactsDataBase? = null
        fun getInstance(context: Context): ContactsDataBase {
            if (instance == null) {
                instance = Room.databaseBuilder(context.applicationContext,
                        ContactsDataBase::class.java,
                        "contacts.db").build()
            }
            return instance as ContactsDataBase
        }
    }
}

没错,还是使用注释,这里我们定义 ContactsDataBase 抽象类,让它继承 RoomDatabase 抽象类。当然也是同 @Database 来标明它是一个数据库。它接收两个参数,分别为 entities 与 version,前者接收的类型是 Class [] 数组,内容为对于表的 Class;后者是 int 的数据库版本号。

在 ContactsDataBase 中还需定义一个抽象方法,让它返回由 @Dao 注释的 ContactsDao,即提供获取数据表的方法。本质的为数据库暴露操作数据表的入口。至于它的具体方法实现也可以通过 build 来查看对应的自动生成文件 ContactsDataBase_Impl 类。

因为 contactsDao 是数据库的唯一入口,避免每次对数据库进行操作时都创建 ContactsDataBase 实例,如上代码我们可以使用单例模式来减少实例频繁创建的开销。

使用

经过上面的 Entity、DAO 与 Database 的创建,现在我们已经有了完整的本地数据库结构。接下来我们来看史上最简数据库使用的调用代码:

private val mContactsDao by lazy { ContactsDataBase.getInstance(application).contactsDao() }
 
fun getContactsById(id: Int): LiveData<ContactsModel> = mContactsDao.getContactsById(id)

你没看错只需两行代码,我们就能获取数据库中 Contacts 表中的所用数据。

第一行代码我们获取了 ContactsDao 实例,该实例包含操作数据表的所以方法。而第二行代码就是调用 ContactsDao 中的操作方法。返回我们所需的数据。

在第二行代码,细心的你们可能会发现它返回了 LiveData<ContactsModel> 类型数据。它是 ACC 的另一强大组件,这也是 Room 的另一强大之处,它可以直接返回 LiveData 数据类型,完美与 LiveData 结合。至于 LiveData 的作用,敬请关注下一篇文章 Android Architecture Components Part2:LiveData。

总结

如果你的 App 使用了 Room,那么你的 App 本地数据获取架构将会是这样的

最后文章中的代码都可以在 Github 中获取到。使用时请将分支切换到 feat_architecture_components

相关文章

Android Architecture Components Part2:LiveData

Android Architecture Components Part3:Lifecycle

Android Architecture Components Part4:ViewModel

关注

怪谈时间到了

今天关于Android Architecture Components 系列二 LifeCycle的分享就到这里,希望大家有所收获,若想了解更多关于./src/components/CustomNavbar.jsx找不到模块:无法解析“ / Users / Documents / GitHub / myweb_app / src / components”中的“ react-router-dom”、./src/Components/Pages/About.js 未找到模块:无法解析“C:\Users\user\Desktop\yat2\yoaz\src\Components\Pages”中的“../logo.svg”、An Overview of the Android Architecture (Android Studio)、Android Architecture Components Part1:Room等相关知识,可以在本站进行查询。

本文标签: