引言

Android作为全球最流行的移动操作系统,拥有超过25亿活跃设备。对于初学者来说,掌握Android开发不仅能打开移动应用开发的大门,还能创造巨大的职业机会。本指南将从零基础开始,通过详细的实例分析,带你一步步构建完整的实战项目。

第一部分:Android开发基础

1.1 Android开发环境搭建

Android Studio是Google官方推荐的集成开发环境(IDE)。安装步骤如下:

  1. 下载安装:访问Android开发者官网下载最新版本
  2. 配置SDK:首次启动时,Android Studio会引导你安装Android SDK和必要的工具
  3. 创建虚拟设备:通过AVD Manager创建模拟器,建议选择Pixel系列设备进行测试
# 验证安装是否成功
adb devices
# 应该显示连接的设备或模拟器列表

1.2 Android项目结构解析

创建一个新项目后,你会看到以下主要目录:

MyApp/
├── app/
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/          # Java/Kotlin源代码
│   │   │   ├── res/           # 资源文件
│   │   │   │   ├── layout/    # XML布局文件
│   │   │   │   ├── values/    # 字符串、颜色等
│   │   │   │   └── drawable/  # 图片资源
│   │   │   └── AndroidManifest.xml  # 应用配置文件
│   │   └── test/              # 单元测试
│   └── build.gradle           # 模块级构建配置
├── build.gradle               # 项目级构建配置
└── settings.gradle            # 项目设置

1.3 第一个Android应用:Hello World

让我们创建一个简单的”Hello World”应用来理解基本结构:

MainActivity.java

package com.example.helloworld;

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

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 获取TextView并设置文本
        TextView textView = findViewById(R.id.textView);
        textView.setText("Hello, Android Developer!");
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:textColor="#333333"
        android:text="Hello World!" />

</LinearLayout>

第二部分:核心组件与UI开发

2.1 Activity生命周期详解

Activity是Android应用的基本组件,理解其生命周期至关重要:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate: Activity被创建");
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart: Activity开始可见");
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume: Activity完全可见,可交互");
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause: Activity部分可见,可能被暂停");
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop: Activity完全不可见");
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: Activity被销毁");
    }
}

生命周期图解

onCreate() → onStart() → onResume() → [运行状态] → onPause() → onStop() → onDestroy()

2.2 常用UI组件与布局

2.2.1 布局管理器

LinearLayout(线性布局)

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="16dp">

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="按钮1" />

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="按钮2" />

</LinearLayout>

RelativeLayout(相对布局)

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="标题"
        android:layout_centerHorizontal="true" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="确定"
        android:layout_below="@id/title"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20dp" />

</RelativeLayout>

ConstraintLayout(约束布局)

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me"
        app:layout_constraintTop_toBottomOf="@id/textView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

2.2.2 常用控件

Button与点击事件

// 在Activity中
Button button = findViewById(R.id.myButton);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(MainActivity.this, "按钮被点击了!", Toast.LENGTH_SHORT).show();
    }
});

// 使用Lambda表达式(Java 8+)
button.setOnClickListener(v -> {
    Toast.makeText(MainActivity.this, "按钮被点击了!", Toast.LENGTH_SHORT).show();
});

EditText与输入验证

EditText editText = findViewById(R.id.editText);
Button submitButton = findViewById(R.id.submitButton);

submitButton.setOnClickListener(v -> {
    String input = editText.getText().toString().trim();
    
    if (input.isEmpty()) {
        editText.setError("请输入内容");
        return;
    }
    
    if (input.length() < 3) {
        editText.setError("至少需要3个字符");
        return;
    }
    
    // 处理有效输入
    Toast.makeText(this, "输入有效: " + input, Toast.LENGTH_SHORT).show();
});

Spinner(下拉选择)

Spinner spinner = findViewById(R.id.spinner);
String[] items = {"选项1", "选项2", "选项3", "选项4"};

ArrayAdapter<String> adapter = new ArrayAdapter<>(
    this, 
    android.R.layout.simple_spinner_item, 
    items
);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);

spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        String selected = items[position];
        Toast.makeText(MainActivity.this, "选择了: " + selected, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
        // 未选择任何项
    }
});

2.3 RecyclerView:高效列表展示

RecyclerView是现代Android开发中展示列表数据的首选组件。

1. 添加依赖

// app/build.gradle
dependencies {
    implementation 'androidx.recyclerview:recyclerview:1.3.2'
}

2. 创建列表项布局

<!-- item_user.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="16dp">

    <ImageView
        android:id="@+id/avatar"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@drawable/ic_user" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical"
        android:layout_marginStart="16dp">

        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/email"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            android:textColor="#666666" />

    </LinearLayout>

</LinearLayout>

3. 创建数据模型

public class User {
    private String name;
    private String email;
    private int avatarResId;

    public User(String name, String email, int avatarResId) {
        this.name = name;
        this.email = email;
        this.avatarResId = avatarResId;
    }

    // Getters and Setters
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public int getAvatarResId() { return avatarResId; }
    public void setAvatarResId(int avatarResId) { this.avatarResId = avatarResId; }
}

4. 创建Adapter

public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
    private List<User> userList;
    private OnItemClickListener listener;

    public interface OnItemClickListener {
        void onItemClick(User user);
    }

    public UserAdapter(List<User> userList, OnItemClickListener listener) {
        this.userList = userList;
        this.listener = listener;
    }

    @NonNull
    @Override
    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_user, parent, false);
        return new UserViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
        User user = userList.get(position);
        holder.name.setText(user.getName());
        holder.email.setText(user.getEmail());
        holder.avatar.setImageResource(user.getAvatarResId());

        // 设置点击事件
        holder.itemView.setOnClickListener(v -> {
            if (listener != null) {
                listener.onItemClick(user);
            }
        });
    }

    @Override
    public int getItemCount() {
        return userList.size();
    }

    // 更新数据的方法
    public void updateData(List<User> newUsers) {
        userList = newUsers;
        notifyDataSetChanged();
    }

    // ViewHolder内部类
    static class UserViewHolder extends RecyclerView.ViewHolder {
        TextView name, email;
        ImageView avatar;

        public UserViewHolder(@NonNull View itemView) {
            super(itemView);
            name = itemView.findViewById(R.id.name);
            email = itemView.findViewById(R.id.email);
            avatar = itemView.findViewById(R.id.avatar);
        }
    }
}

5. 在Activity中使用

public class UserListActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private UserAdapter adapter;
    private List<User> userList = new ArrayList<>();

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

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        // 初始化数据
        initData();

        // 创建并设置Adapter
        adapter = new UserAdapter(userList, user -> {
            // 处理点击事件
            Toast.makeText(this, "点击了: " + user.getName(), Toast.LENGTH_SHORT).show();
        });

        recyclerView.setAdapter(adapter);
    }

    private void initData() {
        userList.add(new User("张三", "zhangsan@example.com", R.drawable.ic_user));
        userList.add(new User("李四", "lisi@example.com", R.drawable.ic_user));
        userList.add(new User("王五", "wangwu@example.com", R.drawable.ic_user));
        userList.add(new User("赵六", "zhaoliu@example.com", R.drawable.ic_user));
    }
}

第三部分:数据存储与网络通信

3.1 SharedPreferences:轻量级数据存储

SharedPreferences适合存储简单的键值对数据,如用户设置、登录状态等。

1. 保存数据

public class SharedPreferencesHelper {
    private static final String PREF_NAME = "MyAppPrefs";
    private static final String KEY_USERNAME = "username";
    private static final String KEY_IS_LOGGED_IN = "is_logged_in";

    public static void saveUsername(Context context, String username) {
        SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(KEY_USERNAME, username);
        editor.apply(); // 异步提交
    }

    public static void saveLoginStatus(Context context, boolean isLoggedIn) {
        SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putBoolean(KEY_IS_LOGGED_IN, isLoggedIn);
        editor.apply();
    }
}

2. 读取数据

public static String getUsername(Context context) {
    SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
    return prefs.getString(KEY_USERNAME, "默认用户");
}

public static boolean isLoggedIn(Context context) {
    SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
    return prefs.getBoolean(KEY_IS_LOGGED_IN, false);
}

3. 删除数据

public static void clearUserData(Context context) {
    SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = prefs.edit();
    editor.remove(KEY_USERNAME);
    editor.remove(KEY_IS_LOGGED_IN);
    editor.apply();
}

3.2 SQLite数据库:结构化数据存储

SQLite是Android内置的轻量级关系型数据库,适合存储结构化数据。

1. 创建数据库帮助类

public class DatabaseHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "MyApp.db";
    private static final int DATABASE_VERSION = 1;

    // 表名和列名
    public static final String TABLE_USERS = "users";
    public static final String COLUMN_ID = "id";
    public static final String COLUMN_NAME = "name";
    public static final String COLUMN_EMAIL = "email";
    public static final String COLUMN_AGE = "age";

    // 创建表的SQL语句
    private static final String CREATE_TABLE_USERS = 
        "CREATE TABLE " + TABLE_USERS + " (" +
        COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
        COLUMN_NAME + " TEXT NOT NULL, " +
        COLUMN_EMAIL + " TEXT UNIQUE, " +
        COLUMN_AGE + " INTEGER)";

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_TABLE_USERS);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 数据库升级时的处理
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_USERS);
        onCreate(db);
    }
}

2. 数据操作类

public class UserRepository {
    private DatabaseHelper dbHelper;

    public UserRepository(Context context) {
        dbHelper = new DatabaseHelper(context);
    }

    // 插入用户
    public long insertUser(String name, String email, int age) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(DatabaseHelper.COLUMN_NAME, name);
        values.put(DatabaseHelper.COLUMN_EMAIL, email);
        values.put(DatabaseHelper.COLUMN_AGE, age);
        
        long id = db.insert(DatabaseHelper.TABLE_USERS, null, values);
        db.close();
        return id;
    }

    // 查询所有用户
    public List<User> getAllUsers() {
        List<User> users = new ArrayList<>();
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        
        Cursor cursor = db.query(
            DatabaseHelper.TABLE_USERS,
            null, // 所有列
            null, // WHERE条件
            null, // WHERE参数
            null, // GROUP BY
            null, // HAVING
            DatabaseHelper.COLUMN_NAME + " ASC" // ORDER BY
        );

        if (cursor != null && cursor.moveToFirst()) {
            do {
                int id = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.COLUMN_ID));
                String name = cursor.getString(cursor.getColumnIndex(DatabaseHelper.COLUMN_NAME));
                String email = cursor.getString(cursor.getColumnIndex(DatabaseHelper.COLUMN_EMAIL));
                int age = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.COLUMN_AGE));
                
                User user = new User(name, email, R.drawable.ic_user);
                user.setId(id);
                user.setAge(age);
                users.add(user);
            } while (cursor.moveToNext());
            
            cursor.close();
        }
        
        db.close();
        return users;
    }

    // 根据ID查询用户
    public User getUserById(int id) {
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        
        Cursor cursor = db.query(
            DatabaseHelper.TABLE_USERS,
            null,
            DatabaseHelper.COLUMN_ID + " = ?",
            new String[]{String.valueOf(id)},
            null, null, null
        );

        User user = null;
        if (cursor != null && cursor.moveToFirst()) {
            String name = cursor.getString(cursor.getColumnIndex(DatabaseHelper.COLUMN_NAME));
            String email = cursor.getString(cursor.getColumnIndex(DatabaseHelper.COLUMN_EMAIL));
            int age = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.COLUMN_AGE));
            
            user = new User(name, email, R.drawable.ic_user);
            user.setId(id);
            user.setAge(age);
            
            cursor.close();
        }
        
        db.close();
        return user;
    }

    // 更新用户
    public int updateUser(int id, String name, String email, int age) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(DatabaseHelper.COLUMN_NAME, name);
        values.put(DatabaseHelper.COLUMN_EMAIL, email);
        values.put(DatabaseHelper.COLUMN_AGE, age);
        
        int rowsAffected = db.update(
            DatabaseHelper.TABLE_USERS,
            values,
            DatabaseHelper.COLUMN_ID + " = ?",
            new String[]{String.valueOf(id)}
        );
        
        db.close();
        return rowsAffected;
    }

    // 删除用户
    public int deleteUser(int id) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        
        int rowsDeleted = db.delete(
            DatabaseHelper.TABLE_USERS,
            DatabaseHelper.COLUMN_ID + " = ?",
            new String[]{String.valueOf(id)}
        );
        
        db.close();
        return rowsDeleted;
    }
}

3.3 Retrofit:网络请求与API集成

Retrofit是Square公司开发的HTTP客户端,是Android网络请求的首选库。

1. 添加依赖

// app/build.gradle
dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.okhttp3:okhttp:4.10.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.10.0'
}

2. 创建数据模型

// 用户数据模型
public class UserResponse {
    private int id;
    private String name;
    private String email;
    private String phone;
    private Address address;
    private Company company;

    // Getters and Setters
    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 String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
    public Address getAddress() { return address; }
    public void setAddress(Address address) { this.address = address; }
    public Company getCompany() { return company; }
    public void setCompany(Company company) { this.company = company; }

    // 内部类
    public static class Address {
        private String street;
        private String suite;
        private String city;
        private String zipcode;
        private Geo geo;

        // Getters and Setters
        public String getStreet() { return street; }
        public void setStreet(String street) { this.street = street; }
        public String getSuite() { return suite; }
        public void setSuite(String suite) { this.suite = suite; }
        public String getCity() { return city; }
        public void setCity(String city) { this.city = city; }
        public String getZipcode() { return zipcode; }
        public void setZipcode(String zipcode) { this.zipcode = zipcode; }
        public Geo getGeo() { return geo; }
        public void setGeo(Geo geo) { this.geo = geo; }

        public static class Geo {
            private String lat;
            private String lng;

            // Getters and Setters
            public String getLat() { return lat; }
            public void setLat(String lat) { this.lat = lat; }
            public String getLng() { return lng; }
            public void setLng(String lng) { this.lng = lng; }
        }
    }

    public static class Company {
        private String name;
        private String catchPhrase;
        private String bs;

        // Getters and Setters
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getCatchPhrase() { return catchPhrase; }
        public void setCatchPhrase(String catchPhrase) { this.catchPhrase = catchPhrase; }
        public String getBs() { return bs; }
        public void setBs(String bs) { this.bs = bs; }
    }
}

3. 创建API接口

public interface ApiService {
    // 获取所有用户
    @GET("users")
    Call<List<UserResponse>> getUsers();

    // 根据ID获取用户
    @GET("users/{id}")
    Call<UserResponse> getUserById(@Path("id") int id);

    // 创建用户
    @POST("users")
    Call<UserResponse> createUser(@Body UserResponse user);

    // 更新用户
    @PUT("users/{id}")
    Call<UserResponse> updateUser(@Path("id") int id, @Body UserResponse user);

    // 删除用户
    @DELETE("users/{id}")
    Call<Void> deleteUser(@Path("id") int id);

    // 带查询参数的请求
    @GET("users")
    Call<List<UserResponse>> getUsersByCity(@Query("city") String city);

    // 带多个查询参数
    @GET("users")
    Call<List<UserResponse>> getUsersByCityAndName(
        @Query("city") String city,
        @Query("name") String name
    );
}

4. 创建Retrofit客户端

public class RetrofitClient {
    private static final String BASE_URL = "https://jsonplaceholder.typicode.com/";
    private static Retrofit retrofit = null;

    public static Retrofit getClient() {
        if (retrofit == null) {
            // 创建OkHttp拦截器用于日志
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(loggingInterceptor)
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .build();

            retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        }
        return retrofit;
    }

    public static ApiService getApiService() {
        return getClient().create(ApiService.class);
    }
}

5. 在Activity中使用

public class NetworkActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private UserAdapter adapter;
    private List<UserResponse> userList = new ArrayList<>();

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

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        fetchUsers();
    }

    private void fetchUsers() {
        ApiService apiService = RetrofitClient.getApiService();
        Call<List<UserResponse>> call = apiService.getUsers();

        call.enqueue(new Callback<List<UserResponse>>() {
            @Override
            public void onResponse(Call<List<UserResponse>> call, Response<List<UserResponse>> response) {
                if (response.isSuccessful() && response.body() != null) {
                    userList = response.body();
                    updateUI();
                } else {
                    Toast.makeText(NetworkActivity.this, 
                        "请求失败: " + response.code(), Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onFailure(Call<List<UserResponse>> call, Throwable t) {
                Toast.makeText(NetworkActivity.this, 
                    "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void updateUI() {
        // 转换为本地User对象
        List<User> localUsers = new ArrayList<>();
        for (UserResponse response : userList) {
            User user = new User(response.getName(), response.getEmail(), R.drawable.ic_user);
            user.setId(response.getId());
            localUsers.add(user);
        }

        adapter = new UserAdapter(localUsers, user -> {
            // 处理点击事件
            showUserDetails(user);
        });
        recyclerView.setAdapter(adapter);
    }

    private void showUserDetails(User user) {
        // 显示用户详情
        Intent intent = new Intent(this, UserDetailActivity.class);
        intent.putExtra("user_id", user.getId());
        startActivity(intent);
    }
}

第四部分:实战项目:用户管理应用

4.1 项目概述

我们将构建一个完整的用户管理应用,包含以下功能:

  1. 用户列表展示(RecyclerView)
  2. 用户详情查看
  3. 添加新用户
  4. 编辑现有用户
  5. 删除用户
  6. 数据持久化(SQLite)
  7. 网络同步(可选)

4.2 项目架构设计

MVC架构模式

Model: 数据层(User, UserRepository)
View: 视图层(Activity, Fragment, XML布局)
Controller: 控制层(Activity/Fragment中的业务逻辑)

项目结构

app/
├── src/main/java/com/example/usermanager/
│   ├── model/
│   │   └── User.java
│   ├── repository/
│   │   └── UserRepository.java
│   ├── database/
│   │   └── DatabaseHelper.java
│   ├── network/
│   │   ├── ApiService.java
│   │   └── RetrofitClient.java
│   ├── ui/
│   │   ├── activity/
│   │   │   ├── MainActivity.java
│   │   │   ├── UserListActivity.java
│   │   │   ├── UserDetailActivity.java
│   │   │   ├── AddUserActivity.java
│   │   │   └── EditUserActivity.java
│   │   ├── adapter/
│   │   │   └── UserAdapter.java
│   │   └── fragment/
│   │       └── UserListFragment.java
│   └── utils/
│       └── SharedPreferencesHelper.java
└── res/
    ├── layout/
    │   ├── activity_main.xml
    │   ├── activity_user_list.xml
    │   ├── activity_user_detail.xml
    │   ├── activity_add_user.xml
    │   ├── activity_edit_user.xml
    │   └── item_user.xml
    ├── values/
    │   ├── strings.xml
    │   ├── colors.xml
    │   └── styles.xml
    └── drawable/
        └── ic_user.xml

4.3 核心功能实现

4.3.1 用户列表界面

UserListActivity.java

public class UserListActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private UserAdapter adapter;
    private UserRepository userRepository;
    private List<User> userList = new ArrayList<>();
    private FloatingActionButton fabAddUser;

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

        // 初始化组件
        recyclerView = findViewById(R.id.recyclerView);
        fabAddUser = findViewById(R.id.fabAddUser);
        
        // 设置RecyclerView
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));

        // 初始化Repository
        userRepository = new UserRepository(this);

        // 加载数据
        loadUsers();

        // 设置添加按钮点击事件
        fabAddUser.setOnClickListener(v -> {
            Intent intent = new Intent(UserListActivity.this, AddUserActivity.class);
            startActivity(intent);
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 每次返回时刷新数据
        loadUsers();
    }

    private void loadUsers() {
        // 从数据库获取用户列表
        userList = userRepository.getAllUsers();
        
        if (adapter == null) {
            adapter = new UserAdapter(userList, user -> {
                // 点击用户查看详情
                Intent intent = new Intent(UserListActivity.this, UserDetailActivity.class);
                intent.putExtra("user_id", user.getId());
                startActivity(intent);
            });
            recyclerView.setAdapter(adapter);
        } else {
            adapter.updateData(userList);
        }

        // 显示空状态
        if (userList.isEmpty()) {
            showEmptyState();
        } else {
            hideEmptyState();
        }
    }

    private void showEmptyState() {
        // 显示空状态视图
        View emptyView = findViewById(R.id.emptyView);
        emptyView.setVisibility(View.VISIBLE);
        recyclerView.setVisibility(View.GONE);
    }

    private void hideEmptyState() {
        // 隐藏空状态视图
        View emptyView = findViewById(R.id.emptyView);
        emptyView.setVisibility(View.GONE);
        recyclerView.setVisibility(View.VISIBLE);
    }
}

4.3.2 添加用户界面

AddUserActivity.java

public class AddUserActivity extends AppCompatActivity {
    private EditText etName, etEmail, etAge;
    private Button btnSave;
    private UserRepository userRepository;

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

        // 初始化组件
        etName = findViewById(R.id.etName);
        etEmail = findViewById(R.id.etEmail);
        etAge = findViewById(R.id.etAge);
        btnSave = findViewById(R.id.btnSave);

        // 初始化Repository
        userRepository = new UserRepository(this);

        // 设置保存按钮点击事件
        btnSave.setOnClickListener(v -> saveUser());
    }

    private void saveUser() {
        String name = etName.getText().toString().trim();
        String email = etEmail.getText().toString().trim();
        String ageStr = etAge.getText().toString().trim();

        // 验证输入
        if (validateInput(name, email, ageStr)) {
            int age = Integer.parseInt(ageStr);
            
            // 保存到数据库
            long id = userRepository.insertUser(name, email, age);
            
            if (id > 0) {
                Toast.makeText(this, "用户添加成功", Toast.LENGTH_SHORT).show();
                finish(); // 返回上一页
            } else {
                Toast.makeText(this, "添加失败", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private boolean validateInput(String name, String email, String ageStr) {
        // 验证姓名
        if (name.isEmpty()) {
            etName.setError("请输入姓名");
            etName.requestFocus();
            return false;
        }

        // 验证邮箱
        if (email.isEmpty()) {
            etEmail.setError("请输入邮箱");
            etEmail.requestFocus();
            return false;
        }
        
        if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
            etEmail.setError("邮箱格式不正确");
            etEmail.requestFocus();
            return false;
        }

        // 验证年龄
        if (ageStr.isEmpty()) {
            etAge.setError("请输入年龄");
            etAge.requestFocus();
            return false;
        }

        try {
            int age = Integer.parseInt(ageStr);
            if (age < 0 || age > 150) {
                etAge.setError("年龄必须在0-150之间");
                etAge.requestFocus();
                return false;
            }
        } catch (NumberFormatException e) {
            etAge.setError("请输入有效的年龄");
            etAge.requestFocus();
            return false;
        }

        return true;
    }
}

4.3.3 用户详情界面

UserDetailActivity.java

public class UserDetailActivity extends AppCompatActivity {
    private TextView tvName, tvEmail, tvAge;
    private Button btnEdit, btnDelete;
    private UserRepository userRepository;
    private int userId;
    private User currentUser;

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

        // 获取传递的用户ID
        userId = getIntent().getIntExtra("user_id", -1);
        if (userId == -1) {
            Toast.makeText(this, "无效的用户ID", Toast.LENGTH_SHORT).show();
            finish();
            return;
        }

        // 初始化组件
        tvName = findViewById(R.id.tvName);
        tvEmail = findViewById(R.id.tvEmail);
        tvAge = findViewById(R.id.tvAge);
        btnEdit = findViewById(R.id.btnEdit);
        btnDelete = findViewById(R.id.btnDelete);

        // 初始化Repository
        userRepository = new UserRepository(this);

        // 加载用户数据
        loadUser();

        // 设置按钮点击事件
        btnEdit.setOnClickListener(v -> editUser());
        btnDelete.setOnClickListener(v -> deleteUser());
    }

    private void loadUser() {
        currentUser = userRepository.getUserById(userId);
        if (currentUser != null) {
            tvName.setText(currentUser.getName());
            tvEmail.setText(currentUser.getEmail());
            tvAge.setText(String.valueOf(currentUser.getAge()));
        } else {
            Toast.makeText(this, "用户不存在", Toast.LENGTH_SHORT).show();
            finish();
        }
    }

    private void editUser() {
        Intent intent = new Intent(this, EditUserActivity.class);
        intent.putExtra("user_id", userId);
        startActivity(intent);
    }

    private void deleteUser() {
        new AlertDialog.Builder(this)
            .setTitle("确认删除")
            .setMessage("确定要删除用户 " + currentUser.getName() + " 吗?")
            .setPositiveButton("确定", (dialog, which) -> {
                int rowsDeleted = userRepository.deleteUser(userId);
                if (rowsDeleted > 0) {
                    Toast.makeText(this, "用户已删除", Toast.LENGTH_SHORT).show();
                    finish();
                } else {
                    Toast.makeText(this, "删除失败", Toast.LENGTH_SHORT).show();
                }
            })
            .setNegativeButton("取消", null)
            .show();
    }
}

4.3.4 编辑用户界面

EditUserActivity.java

public class EditUserActivity extends AppCompatActivity {
    private EditText etName, etEmail, etAge;
    private Button btnSave;
    private UserRepository userRepository;
    private int userId;
    private User currentUser;

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

        // 获取传递的用户ID
        userId = getIntent().getIntExtra("user_id", -1);
        if (userId == -1) {
            Toast.makeText(this, "无效的用户ID", Toast.LENGTH_SHORT).show();
            finish();
            return;
        }

        // 初始化组件
        etName = findViewById(R.id.etName);
        etEmail = findViewById(R.id.etEmail);
        etAge = findViewById(R.id.etAge);
        btnSave = findViewById(R.id.btnSave);

        // 初始化Repository
        userRepository = new UserRepository(this);

        // 加载用户数据
        loadUser();

        // 设置保存按钮点击事件
        btnSave.setOnClickListener(v -> updateUser());
    }

    private void loadUser() {
        currentUser = userRepository.getUserById(userId);
        if (currentUser != null) {
            etName.setText(currentUser.getName());
            etEmail.setText(currentUser.getEmail());
            etAge.setText(String.valueOf(currentUser.getAge()));
        } else {
            Toast.makeText(this, "用户不存在", Toast.LENGTH_SHORT).show();
            finish();
        }
    }

    private void updateUser() {
        String name = etName.getText().toString().trim();
        String email = etEmail.getText().toString().trim();
        String ageStr = etAge.getText().toString().trim();

        // 验证输入
        if (validateInput(name, email, ageStr)) {
            int age = Integer.parseInt(ageStr);
            
            // 更新数据库
            int rowsAffected = userRepository.updateUser(userId, name, email, age);
            
            if (rowsAffected > 0) {
                Toast.makeText(this, "用户更新成功", Toast.LENGTH_SHORT).show();
                finish(); // 返回上一页
            } else {
                Toast.makeText(this, "更新失败", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private boolean validateInput(String name, String email, String ageStr) {
        // 验证姓名
        if (name.isEmpty()) {
            etName.setError("请输入姓名");
            etName.requestFocus();
            return false;
        }

        // 验证邮箱
        if (email.isEmpty()) {
            etEmail.setError("请输入邮箱");
            etEmail.requestFocus();
            return false;
        }
        
        if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
            etEmail.setError("邮箱格式不正确");
            etEmail.requestFocus();
            return false;
        }

        // 验证年龄
        if (ageStr.isEmpty()) {
            etAge.setError("请输入年龄");
            etAge.requestFocus();
            return false;
        }

        try {
            int age = Integer.parseInt(ageStr);
            if (age < 0 || age > 150) {
                etAge.setError("年龄必须在0-150之间");
                etAge.requestFocus();
                return false;
            }
        } catch (NumberFormatException e) {
            etAge.setError("请输入有效的年龄");
            etAge.requestFocus();
            return false;
        }

        return true;
    }
}

4.4 项目优化与扩展

4.4.1 添加搜索功能

在UserListActivity中添加搜索功能

public class UserListActivity extends AppCompatActivity {
    // ... 其他代码 ...

    private SearchView searchView;

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

        // ... 初始化代码 ...

        // 设置搜索功能
        setupSearch();
    }

    private void setupSearch() {
        searchView = findViewById(R.id.searchView);
        
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                filterUsers(newText);
                return true;
            }
        });
    }

    private void filterUsers(String query) {
        if (query.isEmpty()) {
            // 显示所有用户
            adapter.updateData(userList);
        } else {
            // 过滤用户
            List<User> filteredList = new ArrayList<>();
            for (User user : userList) {
                if (user.getName().toLowerCase().contains(query.toLowerCase()) ||
                    user.getEmail().toLowerCase().contains(query.toLowerCase())) {
                    filteredList.add(user);
                }
            }
            adapter.updateData(filteredList);
        }
    }
}

4.4.2 添加分页功能

修改UserRepository添加分页查询

public class UserRepository {
    // ... 其他代码 ...

    // 分页查询用户
    public List<User> getUsersByPage(int page, int pageSize) {
        List<User> users = new ArrayList<>();
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        
        int offset = (page - 1) * pageSize;
        
        Cursor cursor = db.query(
            DatabaseHelper.TABLE_USERS,
            null,
            null,
            null,
            null,
            null,
            DatabaseHelper.COLUMN_NAME + " ASC LIMIT " + pageSize + " OFFSET " + offset
        );

        if (cursor != null && cursor.moveToFirst()) {
            do {
                // ... 解析数据 ...
            } while (cursor.moveToNext());
            
            cursor.close();
        }
        
        db.close();
        return users;
    }

    // 获取总记录数
    public int getTotalCount() {
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor cursor = db.rawQuery("SELECT COUNT(*) FROM " + DatabaseHelper.TABLE_USERS, null);
        
        int count = 0;
        if (cursor != null && cursor.moveToFirst()) {
            count = cursor.getInt(0);
            cursor.close();
        }
        
        db.close();
        return count;
    }
}

4.4.3 添加数据验证与错误处理

创建统一的验证工具类

public class ValidationUtils {
    public static boolean isValidEmail(String email) {
        return Patterns.EMAIL_ADDRESS.matcher(email).matches();
    }

    public static boolean isValidAge(int age) {
        return age >= 0 && age <= 150;
    }

    public static boolean isValidName(String name) {
        return name != null && !name.trim().isEmpty() && name.trim().length() >= 2;
    }

    public static String validateUserInput(String name, String email, String ageStr) {
        if (!isValidName(name)) {
            return "姓名至少需要2个字符";
        }
        
        if (!isValidEmail(email)) {
            return "邮箱格式不正确";
        }
        
        try {
            int age = Integer.parseInt(ageStr);
            if (!isValidAge(age)) {
                return "年龄必须在0-150之间";
            }
        } catch (NumberFormatException e) {
            return "请输入有效的年龄";
        }
        
        return null; // 验证通过
    }
}

第五部分:高级主题与最佳实践

5.1 Fragment的使用

Fragment是构建灵活UI的重要组件,特别适合平板电脑和大屏幕设备。

1. 创建Fragment

public class UserListFragment extends Fragment {
    private RecyclerView recyclerView;
    private UserAdapter adapter;
    private UserRepository userRepository;
    private List<User> userList = new ArrayList<>();
    private OnUserClickListener listener;

    public interface OnUserClickListener {
        void onUserClick(User user);
    }

    public UserListFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_user_list, container, false);
        
        recyclerView = view.findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        
        userRepository = new UserRepository(getContext());
        loadUsers();
        
        return view;
    }

    private void loadUsers() {
        userList = userRepository.getAllUsers();
        
        if (adapter == null) {
            adapter = new UserAdapter(userList, user -> {
                if (listener != null) {
                    listener.onUserClick(user);
                }
            });
            recyclerView.setAdapter(adapter);
        } else {
            adapter.updateData(userList);
        }
    }

    public void setOnUserClickListener(OnUserClickListener listener) {
        this.listener = listener;
    }

    public void refreshData() {
        loadUsers();
    }
}

2. 在Activity中使用Fragment

public class MainActivity extends AppCompatActivity 
    implements UserListFragment.OnUserClickListener {
    
    private UserListFragment userListFragment;

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

        // 检查是否是平板模式
        if (isTabletMode()) {
            // 平板模式:同时显示列表和详情
            setupTabletLayout();
        } else {
            // 手机模式:只显示列表
            setupPhoneLayout();
        }
    }

    private boolean isTabletMode() {
        return findViewById(R.id.detail_container) != null;
    }

    private void setupPhoneLayout() {
        // 手机模式:只显示列表Fragment
        userListFragment = new UserListFragment();
        getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.fragment_container, userListFragment)
            .commit();
    }

    private void setupTabletLayout() {
        // 平板模式:同时显示列表和详情
        userListFragment = new UserListFragment();
        userListFragment.setOnUserClickListener(this);
        
        getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.list_container, userListFragment)
            .commit();
    }

    @Override
    public void onUserClick(User user) {
        if (isTabletMode()) {
            // 平板模式:在右侧显示详情
            UserDetailFragment detailFragment = UserDetailFragment.newInstance(user.getId());
            getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.detail_container, detailFragment)
                .commit();
        } else {
            // 手机模式:启动新的Activity
            Intent intent = new Intent(this, UserDetailActivity.class);
            intent.putExtra("user_id", user.getId());
            startActivity(intent);
        }
    }
}

5.2 ViewModel与LiveData(MVVM架构)

1. 添加依赖

// app/build.gradle
dependencies {
    implementation 'androidx.lifecycle:lifecycle-viewmodel:2.6.2'
    implementation 'androidx.lifecycle:lifecycle-livedata:2.6.2'
    implementation 'androidx.lifecycle:lifecycle-runtime:2.6.2'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}

2. 创建ViewModel

public class UserViewModel extends ViewModel {
    private UserRepository userRepository;
    private MutableLiveData<List<User>> userListLiveData = new MutableLiveData<>();
    private MutableLiveData<User> userLiveData = new MutableLiveData<>();
    private MutableLiveData<Boolean> isLoading = new MutableLiveData<>(false);
    private MutableLiveData<String> errorMessage = new MutableLiveData<>();

    public UserViewModel(Application application) {
        userRepository = new UserRepository(application);
    }

    public LiveData<List<User>> getUserList() {
        return userListLiveData;
    }

    public LiveData<User> getUser() {
        return userLiveData;
    }

    public LiveData<Boolean> getIsLoading() {
        return isLoading;
    }

    public LiveData<String> getErrorMessage() {
        return errorMessage;
    }

    public void loadUsers() {
        isLoading.setValue(true);
        
        // 在后台线程执行数据库查询
        new Thread(() -> {
            try {
                List<User> users = userRepository.getAllUsers();
                userListLiveData.postValue(users);
            } catch (Exception e) {
                errorMessage.postValue("加载失败: " + e.getMessage());
            } finally {
                isLoading.postValue(false);
            }
        }).start();
    }

    public void loadUser(int userId) {
        isLoading.setValue(true);
        
        new Thread(() -> {
            try {
                User user = userRepository.getUserById(userId);
                if (user != null) {
                    userLiveData.postValue(user);
                } else {
                    errorMessage.postValue("用户不存在");
                }
            } catch (Exception e) {
                errorMessage.postValue("加载失败: " + e.getMessage());
            } finally {
                isLoading.postValue(false);
            }
        }).start();
    }

    public void addUser(String name, String email, int age) {
        isLoading.setValue(true);
        
        new Thread(() -> {
            try {
                long id = userRepository.insertUser(name, email, age);
                if (id > 0) {
                    // 重新加载列表
                    loadUsers();
                } else {
                    errorMessage.postValue("添加失败");
                }
            } catch (Exception e) {
                errorMessage.postValue("添加失败: " + e.getMessage());
            } finally {
                isLoading.postValue(false);
            }
        }).start();
    }

    public void updateUser(int userId, String name, String email, int age) {
        isLoading.setValue(true);
        
        new Thread(() -> {
            try {
                int rowsAffected = userRepository.updateUser(userId, name, email, age);
                if (rowsAffected > 0) {
                    // 重新加载数据
                    loadUser(userId);
                    loadUsers();
                } else {
                    errorMessage.postValue("更新失败");
                }
            } catch (Exception e) {
                errorMessage.postValue("更新失败: " + e.getMessage());
            } finally {
                isLoading.postValue(false);
            }
        }).start();
    }

    public void deleteUser(int userId) {
        isLoading.setValue(true);
        
        new Thread(() -> {
            try {
                int rowsDeleted = userRepository.deleteUser(userId);
                if (rowsDeleted > 0) {
                    // 重新加载列表
                    loadUsers();
                } else {
                    errorMessage.postValue("删除失败");
                }
            } catch (Exception e) {
                errorMessage.postValue("删除失败: " + e.getMessage());
            } finally {
                isLoading.postValue(false);
            }
        }).start();
    }
}

3. 在Activity中使用ViewModel

public class UserListActivity extends AppCompatActivity {
    private UserViewModel viewModel;
    private RecyclerView recyclerView;
    private UserAdapter adapter;
    private List<User> userList = new ArrayList<>();
    private ProgressBar progressBar;
    private View emptyView;

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

        // 初始化组件
        recyclerView = findViewById(R.id.recyclerView);
        progressBar = findViewById(R.id.progressBar);
        emptyView = findViewById(R.id.emptyView);
        
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        // 创建ViewModel
        viewModel = new ViewModelProvider(this).get(UserViewModel.class);

        // 观察LiveData
        observeViewModel();

        // 加载数据
        viewModel.loadUsers();
    }

    private void observeViewModel() {
        // 观察用户列表
        viewModel.getUserList().observe(this, users -> {
            if (users != null) {
                userList = users;
                updateUI();
            }
        });

        // 观察加载状态
        viewModel.getIsLoading().observe(this, isLoading -> {
            if (isLoading != null) {
                progressBar.setVisibility(isLoading ? View.VISIBLE : View.GONE);
            }
        });

        // 观察错误消息
        viewModel.getErrorMessage().observe(this, errorMessage -> {
            if (errorMessage != null && !errorMessage.isEmpty()) {
                Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void updateUI() {
        if (userList.isEmpty()) {
            emptyView.setVisibility(View.VISIBLE);
            recyclerView.setVisibility(View.GONE);
        } else {
            emptyView.setVisibility(View.GONE);
            recyclerView.setVisibility(View.VISIBLE);
            
            if (adapter == null) {
                adapter = new UserAdapter(userList, user -> {
                    // 处理点击事件
                    Intent intent = new Intent(this, UserDetailActivity.class);
                    intent.putExtra("user_id", user.getId());
                    startActivity(intent);
                });
                recyclerView.setAdapter(adapter);
            } else {
                adapter.updateData(userList);
            }
        }
    }
}

5.3 依赖注入(Dagger Hilt)

1. 添加依赖

// app/build.gradle
dependencies {
    implementation 'com.google.dagger:hilt-android:2.48'
    kapt 'com.google.dagger:hilt-compiler:2.48'
    implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03'
    kapt 'androidx.hilt:hilt-compiler:1.0.0'
}

2. 创建Application类

@HiltAndroidApp
public class MyApp extends Application {
    // Hilt会自动处理
}

3. 创建Module

@Module
@InstallIn(SingletonComponent.class)
public class AppModule {
    
    @Provides
    @Singleton
    public DatabaseHelper provideDatabaseHelper(@ApplicationContext Context context) {
        return new DatabaseHelper(context);
    }

    @Provides
    @Singleton
    public UserRepository provideUserRepository(DatabaseHelper dbHelper) {
        return new UserRepository(dbHelper);
    }

    @Provides
    @Singleton
    public ApiService provideApiService() {
        return RetrofitClient.getApiService();
    }
}

4. 在Activity中使用

@AndroidEntryPoint
public class UserListActivity extends AppCompatActivity {
    @Inject
    UserRepository userRepository;
    
    @Inject
    ApiService apiService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_list);
        
        // userRepository和apiService已经自动注入
        // 可以直接使用
    }
}

5.4 测试

1. 单元测试

@RunWith(AndroidJUnit4.class)
public class UserRepositoryTest {
    private UserRepository userRepository;
    private Context context;

    @Before
    public void setUp() {
        context = ApplicationProvider.getApplicationContext();
        userRepository = new UserRepository(context);
    }

    @Test
    public void testInsertUser() {
        long id = userRepository.insertUser("Test User", "test@example.com", 25);
        assertTrue(id > 0);
    }

    @Test
    public void testGetUserById() {
        long id = userRepository.insertUser("Test User", "test@example.com", 25);
        User user = userRepository.getUserById((int) id);
        assertNotNull(user);
        assertEquals("Test User", user.getName());
    }

    @Test
    public void testUpdateUser() {
        long id = userRepository.insertUser("Test User", "test@example.com", 25);
        int rowsAffected = userRepository.updateUser((int) id, "Updated User", "updated@example.com", 30);
        assertEquals(1, rowsAffected);
    }

    @Test
    public void testDeleteUser() {
        long id = userRepository.insertUser("Test User", "test@example.com", 25);
        int rowsDeleted = userRepository.deleteUser((int) id);
        assertEquals(1, rowsDeleted);
    }
}

2. UI测试

@RunWith(AndroidJUnit4.class)
public class UserListActivityTest {
    @Rule
    public ActivityScenarioRule<UserListActivity> activityRule = 
        new ActivityScenarioRule<>(UserListActivity.class);

    @Test
    public void testRecyclerViewIsDisplayed() {
        onView(withId(R.id.recyclerView)).check(matches(isDisplayed()));
    }

    @Test
    public void testAddUserButtonIsDisplayed() {
        onView(withId(R.id.fabAddUser)).check(matches(isDisplayed()));
    }

    @Test
    public void testClickAddUserButton() {
        onView(withId(R.id.fabAddUser)).perform(click());
        onView(withId(R.id.etName)).check(matches(isDisplayed()));
    }
}

第六部分:发布与优化

6.1 性能优化

1. 内存优化

// 避免内存泄漏
public class UserListActivity extends AppCompatActivity {
    private Handler handler = new Handler(Looper.getMainLooper());
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // 执行耗时操作
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 移除所有回调
        handler.removeCallbacks(runnable);
        // 清理资源
        if (adapter != null) {
            adapter = null;
        }
    }
}

2. 网络优化

// 使用缓存
public class RetrofitClient {
    private static final String BASE_URL = "https://api.example.com/";
    private static Retrofit retrofit = null;

    public static Retrofit getClient() {
        if (retrofit == null) {
            // 创建缓存
            int cacheSize = 10 * 1024 * 1024; // 10 MB
            Cache cache = new Cache(new File("cache"), cacheSize);

            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .cache(cache)
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Request request = chain.request();
                        Response response = chain.proceed(request);
                        
                        // 添加缓存控制头
                        return response.newBuilder()
                            .header("Cache-Control", "public, max-age=60") // 缓存60秒
                            .build();
                    }
                })
                .build();

            retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        }
        return retrofit;
    }
}

3. UI优化

// 使用ViewHolder模式优化RecyclerView
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
    // ... 其他代码 ...

    static class UserViewHolder extends RecyclerView.ViewHolder {
        TextView name, email;
        ImageView avatar;

        public UserViewHolder(@NonNull View itemView) {
            super(itemView);
            name = itemView.findViewById(R.id.name);
            email = itemView.findViewById(R.id.email);
            avatar = itemView.findViewById(R.id.avatar);
        }
    }

    // 使用DiffUtil优化列表更新
    public void updateData(List<User> newUsers) {
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(
            new UserDiffCallback(userList, newUsers)
        );
        userList = newUsers;
        diffResult.dispatchUpdatesTo(this);
    }

    static class UserDiffCallback extends DiffUtil.Callback {
        private List<User> oldList;
        private List<User> newList;

        public UserDiffCallback(List<User> oldList, List<User> newList) {
            this.oldList = oldList;
            this.newList = newList;
        }

        @Override
        public int getOldListSize() {
            return oldList.size();
        }

        @Override
        public int getNewListSize() {
            return newList.size();
        }

        @Override
        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
            return oldList.get(oldItemPosition).getId() == newList.get(newItemPosition).getId();
        }

        @Override
        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
            User oldUser = oldList.get(oldItemPosition);
            User newUser = newList.get(newItemPosition);
            return oldUser.getName().equals(newUser.getName()) &&
                   oldUser.getEmail().equals(newUser.getEmail()) &&
                   oldUser.getAge() == newUser.getAge();
        }
    }
}

6.2 安全性考虑

1. 数据加密

public class EncryptionUtils {
    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/GCM/NoPadding";

    public static String encrypt(String data, String secretKey) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        
        byte[] encrypted = cipher.doFinal(data.getBytes());
        return Base64.encodeToString(encrypted, Base64.DEFAULT);
    }

    public static String decrypt(String encryptedData, String secretKey) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        
        byte[] decoded = Base64.decode(encryptedData, Base64.DEFAULT);
        byte[] decrypted = cipher.doFinal(decoded);
        return new String(decrypted);
    }
}

2. 安全存储

public class SecureStorage {
    private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
    private static final String KEY_ALIAS = "MyAppKey";

    public static void saveSecureData(Context context, String key, String value) throws Exception {
        KeyStore keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
        keyStore.load(null);

        if (!keyStore.containsAlias(KEY_ALIAS)) {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(
                KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_PROVIDER);
            KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
                KEY_ALIAS,
                KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build();
            keyGenerator.init(spec);
            keyGenerator.generateKey();
        }

        SecretKey secretKey = (SecretKey) keyStore.getKey(KEY_ALIAS, null);
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        byte[] encrypted = cipher.doFinal(value.getBytes());
        String encryptedString = Base64.encodeToString(encrypted, Base64.DEFAULT);

        SharedPreferences prefs = context.getSharedPreferences("secure_prefs", Context.MODE_PRIVATE);
        prefs.edit().putString(key, encryptedString).apply();
    }

    public static String getSecureData(Context context, String key) throws Exception {
        SharedPreferences prefs = context.getSharedPreferences("secure_prefs", Context.MODE_PRIVATE);
        String encryptedString = prefs.getString(key, null);
        
        if (encryptedString == null) return null;

        KeyStore keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
        keyStore.load(null);
        SecretKey secretKey = (SecretKey) keyStore.getKey(KEY_ALIAS, null);

        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        byte[] decoded = Base64.decode(encryptedString, Base64.DEFAULT);
        byte[] decrypted = cipher.doFinal(decoded);
        return new String(decrypted);
    }
}

6.3 发布准备

1. 配置签名

// app/build.gradle
android {
    signingConfigs {
        release {
            storeFile file("my-release-key.jks")
            storePassword "password"
            keyAlias "my-key-alias"
            keyPassword "password"
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

2. 配置ProGuard

# proguard-rules.pro
# 保持所有模型类
-keep class com.example.usermanager.model.** { *; }
-keep class com.example.usermanager.network.** { *; }

# Retrofit
-keepattributes Signature
-keepattributes *Annotation*
-keep class retrofit2.** { *; }
-keepclasseswithmembers class * {
    @retrofit2.http.* <methods>;
}

# Gson
-keep class com.google.gson.** { *; }
-keep class sun.misc.Unsafe { *; }
-keep class com.example.usermanager.model.** { *; }

# SQLite
-keep class android.database.** { *; }
-keep class android.database.sqlite.** { *; }

3. 生成APK

# 在Android Studio中
# Build → Generate Signed Bundle / APK

# 或使用命令行
./gradlew assembleRelease

第七部分:扩展学习与资源

7.1 推荐学习路径

  1. 基础阶段(1-2个月)

    • Java/Kotlin基础
    • Android基础组件
    • UI开发与布局
  2. 进阶阶段(2-3个月)

    • 数据存储与网络通信
    • 架构模式(MVC/MVP/MVVM)
    • 第三方库使用
  3. 高级阶段(3-6个月)

    • 性能优化
    • 安全性
    • 测试与调试
    • 发布与维护

7.2 推荐资源

官方文档

在线课程

  • Udacity Android开发课程
  • Coursera Android专项课程
  • Google Android开发者培训

开源项目

社区与论坛

  • Stack Overflow
  • Reddit r/androiddev
  • Android开发者社区

7.3 持续学习建议

  1. 关注官方博客:Google Android开发者博客
  2. 参与开源项目:GitHub上有很多优秀的Android项目
  3. 参加技术会议:Google I/O, Android Dev Summit
  4. 阅读源码:学习优秀开源项目的实现
  5. 实践项目:不断开发新项目,积累经验

结语

Android开发是一个不断发展的领域,从零基础到实战项目开发需要系统的学习和大量的实践。本指南提供了从环境搭建到项目开发的完整流程,涵盖了Android开发的各个方面。

记住,编程最重要的是实践。不要只是阅读代码,要动手编写,调试,优化。每个项目都是学习的机会,每个错误都是进步的阶梯。

祝你在Android开发的道路上取得成功!