Android 之 Jetpack

1.什么是Jetpack?

  • Jetpack是谷歌官方推出的一套Android开发组件集合,它就像是一个"开发工具百宝箱",帮助开发者更轻松地构建高质量的应用。想象一下,你要盖房子,Jetpack就是为你准备好的各种预制件和工具,让你不用从零开始造轮子。

2.为什么需要Jetpack?

  1. 减少样板代码:以前写Android应用要写很多重复的代码,Jetpack帮我们省去了这些麻烦
  2. 兼容性更好:自动处理不同Android版本的兼容问题
  3. 架构更清晰:提供标准化的开发模式,让代码更有条理
  4. 提高开发效率:很多常用功能已经封装好了,直接调用就行

3.Jetpack组件如何协同工作

复制代码
一个典型的Jetpack架构是这样的:

UI层 (Activity/Fragment)
  ↑ 观察 ↓ 通知
ViewModel (持有LiveData)
  ↑ 调用 ↓ 返回
Repository (数据仓库)
  ↑ 获取 ↓ 提供
本地数据源(Room) 或 远程数据源(Retrofit)

4.Jetpack核心组件详解

4.1. Lifecycle(生命周期管理)

通俗理解:就像给你的代码装了个"生命监测仪",能感知Activity/Fragment的生命周期变化。

常用场景

  • 当页面显示时开始播放视频,页面隐藏时暂停
  • 在合适的生命周期初始化或释放资源
java 复制代码
 java写法

1. ​​添加依赖(build.gradle)​

dependencies {
    implementation "androidx.lifecycle:lifecycle-common-java8:2.6.0" // Java 兼容库
}

2. ​​实现 LifecycleObserver(监听生命周期)

import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import android.util.Log;

public class LocationObserver implements DefaultLifecycleObserver {
    private static final String TAG = "LifecycleDemo";

    @Override
    public void onStart(LifecycleOwner owner) {
        startLocationTracking();
        Log.d(TAG, "onStart: 定位启动");
    }

    @Override
    public void onStop(LifecycleOwner owner) {
        stopLocationTracking();
        Log.d(TAG, "onStop: 定位停止");
    }

    private void startLocationTracking() {
        // 实际定位逻辑(如请求位置更新)
    }

    private void stopLocationTracking() {
        // 释放定位资源
    }
}

​​说明​​:
继承 DefaultLifecycleObserver,重写 onStart/onStop 等方法。
替代 @OnLifecycleEvent 注解(官方推荐方案)

3. ​​在 AppCompatActivity 中注册观察者

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 注册 LifecycleObserver
        getLifecycle().addObserver(new LocationObserver());
    }
}

​​关键点​​:
AppCompatActivity 已默认实现 LifecycleOwner 接口,直接通过 getLifecycle() 获取 Lifecycle 对象。
观察者自动绑定生命周期,无需手动调用生命周期方法。
​
4.2. ViewModel(数据管理)

通俗理解:相当于数据的"保险箱",屏幕旋转时数据不会丢失,而且不同Fragment可以共享同一个ViewModel。

特点

  • 独立于UI的生命周期
  • 配置更改(如旋转屏幕)时数据不会丢失
  • 便于UI组件间共享数据
4.3. LiveData(数据观察)

通俗理解:像是一个"数据广播站",当数据变化时会自动通知所有订阅者。

优点

  • 自动感知生命周期,避免内存泄漏
  • 数据变化时自动更新UI
  • 不需要手动处理订阅和取消订阅

以下是使用 Java 编写的 ​​ViewModel + LiveData​​ 完整范例,结合生命周期感知、数据持久化和屏幕旋转恢复等功能,适配最新 Jetpack 组件库

java 复制代码
1. ​​添加依赖(build.gradle)​

dependencies {
    implementation "androidx.lifecycle:lifecycle-viewmodel:2.6.0"
    implementation "androidx.lifecycle:lifecycle-livedata:2.6.0"
}

2. ​​创建 ViewModel 类(管理计数器逻辑)

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class CounterViewModel extends ViewModel {

    // MutableLiveData 存储可变数据,对外暴露不可变的 LiveData
    private final MutableLiveData<Integer> counter = new MutableLiveData<>(0);

    public LiveData<Integer> getCounter() {
        return counter;
    }

    // 增加计数
    public void increment() {
        counter.setValue(counter.getValue() + 1);
    }

    // 重置计数
    public void reset() {
        counter.setValue(0);
    }

    // ViewModel 销毁时释放资源
    @Override
    protected void onCleared() {
        super.onCleared();
        // 可在此取消网络请求或清理资源
    }
}

关键点​​:

MutableLiveData 封装数据,对外暴露 LiveData 防止外部篡改
onCleared() 在 ViewModel 永久销毁时自动调用,避免内存泄漏


3. ​​Activity 中初始化 ViewModel 并观察数据(MainActivity.java)​

import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProvider;

public class MainActivity extends AppCompatActivity {
    private CounterViewModel viewModel;
    private TextView tvCount;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化 ViewModel(系统自动管理生命周期)
        viewModel = new ViewModelProvider(this).get(CounterViewModel.class);

        tvCount = findViewById(R.id.tv_count);
        Button btnIncrement = findViewById(R.id.btn_increment);
        Button btnReset = findViewById(R.id.btn_reset);

        // 观察 LiveData 数据变化
        LiveData<Integer> counterLiveData = viewModel.getCounter();
        counterLiveData.observe(this, count -> {
            tvCount.setText(String.valueOf(count)); // 数据更新时刷新 UI
        });

        // 按钮点击事件
        btnIncrement.setOnClickListener(v -> viewModel.increment());
        btnReset.setOnClickListener(v -> viewModel.reset());
    }
}

关键点​​:

ViewModelProvider(this) 确保屏幕旋转时复用同一 ViewModel 实例
observe(this, ...) 自动绑定生命周期:仅在界面活跃时更新 UI,销毁时自动解绑

4. ​​布局文件(activity_main.xml)​

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/tv_count"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0"
        android:textSize="48sp"
        android:layout_gravity="center"/>

    <Button
        android:id="@+id/btn_increment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="+1"
        android:layout_marginTop="24dp"/>

    <Button
        android:id="@+id/btn_reset"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Reset"
        android:layout_marginTop="16dp"/>

</LinearLayout>
4.4 Room(数据库)

通俗理解:SQLite数据库的"升级版",用起来更简单,像操作对象一样操作数据库。

核心三部分

  • Entity:定义数据表结构
  • DAO (Data Access Object):数据库操作接口
  • Database:数据库持有者

以下是使用 Java 编写的 ​​Room 数据库完整示例​​,涵盖实体定义、DAO 接口、数据库构建及增删改查操作,适配最新 Jetpack 组件库(Room 2.6+)

java 复制代码
1. ​​添加依赖(app/build.gradle)

dependencies {
    implementation "androidx.room:room-runtime:2.6.1"
    annotationProcessor "androidx.room:room-compiler:2.6.1" // Java 注解处理器
    implementation "androidx.lifecycle:lifecycle-livedata:2.6.0" // LiveData 支持
}

 2. ​​定义实体类(Entity)​

import androidx.room.Entity;
import androidx.room.PrimaryKey;

@Entity(tableName = "users")
public class User {
    @PrimaryKey(autoGenerate = true)
    private int id;

    private String name;
    private int age;

    // 必须有无参构造(或所有字段为 public)
    public User() {}

    // Getter 和 Setter
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}

​​@Entity​​:标记为数据库表,tableName 指定表名。
​​@PrimaryKey​​:主键,autoGenerate = true 表示自增

 3. ​​定义 DAO 接口(数据访问对象)

import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import androidx.lifecycle.LiveData;
import java.util.List;

@Dao
public interface UserDao {
    @Insert
    void insert(User user); // 插入单条数据

    @Update
    void update(User user); // 更新数据

    @Delete
    void delete(User user); // 删除数据

    @Query("DELETE FROM users")
    void deleteAll(); // 清空表

    @Query("SELECT * FROM users")
    LiveData<List<User>> getAllUsers(); // 返回 LiveData 实现实时更新[1,5](@ref)

    @Query("SELECT * FROM users WHERE id = :userId")
    User getUserById(int userId); // 条件查询
}

​​@Query​​:支持自定义 SQL 语句,编译时验证语法。
​​LiveData​​:返回可观察数据,UI 自动响应变化

4. ​​创建数据库类(Database)​

import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import android.content.Context;

@Database(entities = {User.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();

    // 单例模式防止重复实例化
    private static volatile AppDatabase INSTANCE;

    public static AppDatabase getInstance(Context context) {
        if (INSTANCE == null) {
            synchronized (AppDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(
                            context.getApplicationContext(),
                            AppDatabase.class,
                            "app_database.db" // 数据库文件名
                    ).build();
                }
            }
        }
        return INSTANCE;
    }
}

​​@Database​​:声明数据库版本和实体类列表。
​​exportSchema = false​​:关闭 Schema 导出(生产环境建议开启备份

5. ​​在 Activity 中使用数据库​
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.lifecycle.Observer;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private AppDatabase db;
    private UserDao userDao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化数据库
        db = AppDatabase.getInstance(this);
        userDao = db.userDao();

        // 插入数据(需在子线程执行)
        new Thread(() -> {
            User user = new User();
            user.setName("Alice");
            user.setAge(25);
            userDao.insert(user);
        }).start();

        // 观察数据变化(自动在主线程回调)
        userDao.getAllUsers().observe(this, users -> {
            for (User u : users) {
                System.out.println("User: " + u.getName() + ", Age: " + u.getAge());
            }
        });
    }
}
​​线程管理​​:Room 禁止主线程操作数据库,需用 Thread/Executor 或异步框架(如 RxJava)。
​​LiveData 观察​​:数据变化时自动刷新 UI,避免手动查询