引言
Android作为全球最流行的移动操作系统,拥有庞大的开发者社区和丰富的应用场景。对于初学者来说,Android开发可能显得复杂而难以入手;对于有经验的开发者,如何从基础走向进阶,构建高质量的应用程序同样是一个挑战。本文将通过一系列具体的编程实例,从基础概念到高级技术,系统地分析Android开发的实战技巧。我们将涵盖UI设计、数据存储、网络通信、性能优化等关键领域,并通过完整的代码示例帮助读者理解每个概念。
第一部分:Android开发基础
1.1 Android开发环境搭建
在开始编写代码之前,我们需要搭建一个完整的开发环境。Android Studio是Google官方推荐的集成开发环境(IDE),它提供了代码编辑、调试、性能分析等全方位工具。
安装步骤:
- 下载Android Studio(建议从官网下载最新版本)
- 安装过程中选择”Custom”安装,确保勾选Android SDK和Android Virtual Device
- 配置SDK路径和模拟器
验证安装:
# 打开终端,输入以下命令验证Android SDK是否正确安装
adb version
1.2 第一个Android应用:Hello World
让我们创建一个简单的”Hello World”应用来理解Android应用的基本结构。
项目结构:
MyApp/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/com/example/myapp/
│ │ │ │ └── MainActivity.java
│ │ │ ├── res/
│ │ │ │ ├── layout/
│ │ │ │ │ └── activity_main.xml
│ │ │ │ ├── values/
│ │ │ │ │ └── strings.xml
│ │ │ └── AndroidManifest.xml
MainActivity.java:
package com.example.myapp;
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!");
}
}
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" />
</LinearLayout>
1.3 Activity生命周期
Activity是Android应用的基本组件,理解其生命周期对于开发稳定的应用至关重要。
生命周期方法:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("Lifecycle", "onCreate called");
}
@Override
protected void onStart() {
super.onStart();
Log.d("Lifecycle", "onStart called");
}
@Override
protected void onResume() {
super.onResume();
Log.d("Lifecycle", "onResume called");
}
@Override
protected void onPause() {
super.onPause();
Log.d("Lifecycle", "onPause called");
}
@Override
protected void onStop() {
super.onStop();
Log.d("Lifecycle", "onStop called");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("Lifecycle", "onDestroy called");
}
}
生命周期图示:
onCreate() → onStart() → onResume() → [运行状态] → onPause() → onStop() → onDestroy()
第二部分:UI设计与交互
2.1 布局系统详解
Android提供了多种布局方式,其中ConstraintLayout是最推荐的现代布局方式。
ConstraintLayout示例:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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:textSize="24sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="50dp" />
<EditText
android:id="@+id/username"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="请输入用户名"
android:inputType="text"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="30dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp" />
<EditText
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="请输入密码"
android:inputType="textPassword"
app:layout_constraintTop_toBottomOf="@id/username"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="15dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp" />
<Button
android:id="@+id/loginButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="登录"
app:layout_constraintTop_toBottomOf="@id/password"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="30dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
2.2 RecyclerView列表展示
RecyclerView是展示列表数据的高效组件,支持动态添加、删除和更新。
数据模型:
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; }
}
适配器:
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
private List<User> userList;
private Context context;
public UserAdapter(Context context, List<User> userList) {
this.context = context;
this.userList = userList;
}
@NonNull
@Override
public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).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.nameTextView.setText(user.getName());
holder.emailTextView.setText(user.getEmail());
holder.avatarImageView.setImageResource(user.getAvatarResId());
// 点击事件
holder.itemView.setOnClickListener(v -> {
Toast.makeText(context, "点击了: " + user.getName(), Toast.LENGTH_SHORT).show();
});
}
@Override
public int getItemCount() {
return userList.size();
}
// ViewHolder内部类
public static class UserViewHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
TextView emailTextView;
ImageView avatarImageView;
public UserViewHolder(@NonNull View itemView) {
super(itemView);
nameTextView = itemView.findViewById(R.id.tv_name);
emailTextView = itemView.findViewById(R.id.tv_email);
avatarImageView = itemView.findViewById(R.id.iv_avatar);
}
}
}
使用适配器:
public class UserListActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private UserAdapter adapter;
private List<User> userList;
@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));
// 初始化数据
userList = new ArrayList<>();
userList.add(new User("张三", "zhangsan@example.com", R.drawable.avatar1));
userList.add(new User("李四", "lisi@example.com", R.drawable.avatar2));
userList.add(new User("王五", "wangwu@example.com", R.drawable.avatar3));
adapter = new UserAdapter(this, userList);
recyclerView.setAdapter(adapter);
}
}
2.3 Fragment的使用
Fragment是可重用的UI片段,常用于构建灵活的界面。
创建Fragment:
public class DetailFragment extends Fragment {
private static final String ARG_USER_ID = "user_id";
private String userId;
public DetailFragment() {
// Required empty public constructor
}
public static DetailFragment newInstance(String userId) {
DetailFragment fragment = new DetailFragment();
Bundle args = new Bundle();
args.putString(ARG_USER_ID, userId);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
userId = getArguments().getString(ARG_USER_ID);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_detail, container, false);
TextView tvUserId = view.findViewById(R.id.tv_user_id);
tvUserId.setText("用户ID: " + userId);
return view;
}
}
在Activity中使用Fragment:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 动态添加Fragment
DetailFragment fragment = DetailFragment.newInstance("user123");
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
}
}
第三部分:数据存储与管理
3.1 SharedPreferences存储
SharedPreferences是Android中最简单的数据存储方式,适合存储少量的键值对数据。
保存数据:
public class SharedPreferencesHelper {
private static final String PREF_NAME = "my_app_prefs";
private static final String KEY_USER_NAME = "user_name";
private static final String KEY_IS_LOGGED_IN = "is_logged_in";
private SharedPreferences sharedPreferences;
public SharedPreferencesHelper(Context context) {
sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
}
public void saveUserName(String userName) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(KEY_USER_NAME, userName);
editor.apply(); // 异步提交
}
public String getUserName() {
return sharedPreferences.getString(KEY_USER_NAME, "默认用户");
}
public void setLoggedIn(boolean isLoggedIn) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(KEY_IS_LOGGED_IN, isLoggedIn);
editor.apply();
}
public boolean isLoggedIn() {
return sharedPreferences.getBoolean(KEY_IS_LOGGED_IN, false);
}
public void clearData() {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.apply();
}
}
使用示例:
public class LoginActivity extends AppCompatActivity {
private EditText etUsername;
private EditText etPassword;
private Button btnLogin;
private SharedPreferencesHelper prefsHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
prefsHelper = new SharedPreferencesHelper(this);
// 检查是否已登录
if (prefsHelper.isLoggedIn()) {
navigateToMain();
return;
}
etUsername = findViewById(R.id.et_username);
etPassword = findViewById(R.id.et_password);
btnLogin = findViewById(R.id.btn_login);
btnLogin.setOnClickListener(v -> {
String username = etUsername.getText().toString();
String password = etPassword.getText().toString();
// 模拟登录验证
if (username.equals("admin") && password.equals("123456")) {
prefsHelper.saveUserName(username);
prefsHelper.setLoggedIn(true);
navigateToMain();
} else {
Toast.makeText(this, "用户名或密码错误", Toast.LENGTH_SHORT).show();
}
});
}
private void navigateToMain() {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
}
3.2 SQLite数据库操作
SQLite是Android内置的轻量级数据库,适合存储结构化数据。
数据库帮助类:
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "my_app.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, " +
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);
}
// 插入用户
public long insertUser(String name, String email, int age) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_NAME, name);
values.put(COLUMN_EMAIL, email);
values.put(COLUMN_AGE, age);
long id = db.insert(TABLE_USERS, null, values);
db.close();
return id;
}
// 查询所有用户
public List<User> getAllUsers() {
List<User> users = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(
TABLE_USERS,
null,
null,
null,
null,
null,
COLUMN_NAME + " ASC"
);
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(cursor.getColumnIndex(COLUMN_ID));
String name = cursor.getString(cursor.getColumnIndex(COLUMN_NAME));
String email = cursor.getString(cursor.getColumnIndex(COLUMN_EMAIL));
int age = cursor.getInt(cursor.getColumnIndex(COLUMN_AGE));
User user = new User(name, email, R.drawable.avatar1);
user.setId(id);
user.setAge(age);
users.add(user);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return users;
}
// 更新用户
public int updateUser(int id, String name, String email, int age) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_NAME, name);
values.put(COLUMN_EMAIL, email);
values.put(COLUMN_AGE, age);
int rowsAffected = db.update(
TABLE_USERS,
values,
COLUMN_ID + " = ?",
new String[]{String.valueOf(id)}
);
db.close();
return rowsAffected;
}
// 删除用户
public int deleteUser(int id) {
SQLiteDatabase db = this.getWritableDatabase();
int rowsAffected = db.delete(
TABLE_USERS,
COLUMN_ID + " = ?",
new String[]{String.valueOf(id)}
);
db.close();
return rowsAffected;
}
}
使用数据库:
public class DatabaseActivity extends AppCompatActivity {
private DatabaseHelper dbHelper;
private List<User> userList;
private UserAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_database);
dbHelper = new DatabaseHelper(this);
userList = new ArrayList<>();
// 添加测试数据
dbHelper.insertUser("张三", "zhangsan@example.com", 25);
dbHelper.insertUser("李四", "lisi@example.com", 30);
// 查询数据
userList = dbHelper.getAllUsers();
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new UserAdapter(this, userList);
recyclerView.setAdapter(adapter);
}
}
3.3 Room数据库(推荐)
Room是Google推荐的SQLite抽象层,提供了更简洁的API和编译时检查。
实体类:
@Entity(tableName = "users")
public class UserEntity {
@PrimaryKey(autoGenerate = true)
private int id;
@ColumnInfo(name = "name")
private String name;
@ColumnInfo(name = "email")
private String email;
@ColumnInfo(name = "age")
private int age;
// 构造函数
public UserEntity(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
// 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 int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
DAO(数据访问对象):
@Dao
public interface UserDao {
@Query("SELECT * FROM users")
List<UserEntity> getAll();
@Query("SELECT * FROM users WHERE id = :userId")
UserEntity getById(int userId);
@Insert
void insert(UserEntity user);
@Insert
void insertAll(List<UserEntity> users);
@Update
void update(UserEntity user);
@Delete
void delete(UserEntity user);
@Query("DELETE FROM users WHERE id = :userId")
void deleteById(int userId);
}
数据库类:
@Database(entities = {UserEntity.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
private static volatile AppDatabase INSTANCE;
public static AppDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (AppDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
context.getApplicationContext(),
AppDatabase.class,
"app_database"
).build();
}
}
}
return INSTANCE;
}
}
使用Room:
public class RoomActivity extends AppCompatActivity {
private AppDatabase db;
private UserDao userDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_room);
db = AppDatabase.getDatabase(this);
userDao = db.userDao();
// 在后台线程执行数据库操作
new Thread(() -> {
// 插入数据
UserEntity user = new UserEntity("张三", "zhangsan@example.com", 25);
userDao.insert(user);
// 查询数据
List<UserEntity> users = userDao.getAll();
// 更新UI
runOnUiThread(() -> {
// 更新UI显示
updateUI(users);
});
}).start();
}
private void updateUI(List<UserEntity> users) {
// 更新界面显示
}
}
第四部分:网络通信
4.1 Retrofit网络请求
Retrofit是目前最流行的Android网络请求库,基于OkHttp实现。
添加依赖:
// build.gradle (Module: app)
dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
}
定义API接口:
public interface ApiService {
// GET请求示例
@GET("users/{id}")
Call<User> getUserById(@Path("id") int userId);
// POST请求示例
@POST("users")
Call<User> createUser(@Body User user);
// 带查询参数的GET请求
@GET("users")
Call<List<User>> getUsers(
@Query("page") int page,
@Query("limit") int limit
);
// 带Header的请求
@GET("profile")
Call<Profile> getProfile(
@Header("Authorization") String token
);
}
创建Retrofit实例:
public class RetrofitClient {
private static final String BASE_URL = "https://api.example.com/";
private static Retrofit retrofit;
public static Retrofit getInstance() {
if (retrofit == null) {
// 创建OkHttpClient
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
// 添加日志拦截器
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(logging);
// 创建Retrofit实例
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(httpClient.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
public static ApiService getApiService() {
return getInstance().create(ApiService.class);
}
}
发起网络请求:
public class NetworkActivity extends AppCompatActivity {
private TextView resultTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_network);
resultTextView = findViewById(R.id.resultTextView);
// 获取用户数据
fetchUserData(1);
}
private void fetchUserData(int userId) {
ApiService apiService = RetrofitClient.getApiService();
Call<User> call = apiService.getUserById(userId);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful() && response.body() != null) {
User user = response.body();
resultTextView.setText("用户: " + user.getName() + "\n邮箱: " + user.getEmail());
} else {
resultTextView.setText("请求失败: " + response.code());
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
resultTextView.setText("网络错误: " + t.getMessage());
}
});
}
}
4.2 Volley网络请求
Volley是Google官方提供的网络请求库,适合简单的网络请求。
添加依赖:
dependencies {
implementation 'com.android.volley:volley:1.2.1'
}
使用Volley:
public class VolleyActivity extends AppCompatActivity {
private TextView resultTextView;
private RequestQueue requestQueue;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_volley);
resultTextView = findViewById(R.id.resultTextView);
requestQueue = Volley.newRequestQueue(this);
// 发起GET请求
fetchJsonData();
}
private void fetchJsonData() {
String url = "https://api.example.com/users/1";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(
Request.Method.GET,
url,
null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
String name = response.getString("name");
String email = response.getString("email");
resultTextView.setText("用户: " + name + "\n邮箱: " + email);
} catch (JSONException e) {
resultTextView.setText("JSON解析错误: " + e.getMessage());
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
resultTextView.setText("网络错误: " + error.getMessage());
}
}
);
requestQueue.add(jsonObjectRequest);
}
}
4.3 协程与Flow处理异步操作
Kotlin协程是处理异步操作的现代方式,比传统的回调更简洁。
添加依赖:
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
}
使用协程:
class CoroutineActivity : AppCompatActivity() {
private lateinit var viewModel: UserViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_coroutine)
// 初始化ViewModel
viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
// 观察LiveData
viewModel.userLiveData.observe(this) { user ->
// 更新UI
findViewById<TextView>(R.id.resultTextView).text =
"用户: ${user.name}\n邮箱: ${user.email}"
}
// 发起网络请求
viewModel.fetchUserData(1)
}
}
class UserViewModel : ViewModel() {
private val _userLiveData = MutableLiveData<User>()
val userLiveData: LiveData<User> get() = _userLiveData
fun fetchUserData(userId: Int) {
viewModelScope.launch {
try {
// 在IO线程执行网络请求
val user = withContext(Dispatchers.IO) {
// 模拟网络请求
delay(2000) // 模拟延迟
User("张三", "zhangsan@example.com", R.drawable.avatar1)
}
// 更新LiveData
_userLiveData.value = user
} catch (e: Exception) {
// 处理错误
Log.e("UserViewModel", "Error fetching user data", e)
}
}
}
}
第五部分:性能优化
5.1 内存优化
避免内存泄漏:
public class MemoryLeakActivity extends AppCompatActivity {
private static class MyHandler extends Handler {
private final WeakReference<MemoryLeakActivity> activityRef;
public MyHandler(MemoryLeakActivity activity) {
activityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MemoryLeakActivity activity = activityRef.get();
if (activity != null) {
// 处理消息
activity.updateUI();
}
}
}
private final MyHandler handler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_memory_leak);
// 发送延迟消息
handler.sendEmptyMessageDelayed(0, 5000);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 移除所有消息
handler.removeCallbacksAndMessages(null);
}
}
使用LeakCanary检测内存泄漏:
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
}
5.2 UI性能优化
使用ViewHolder模式:
// 在RecyclerView适配器中
public class OptimizedAdapter extends RecyclerView.Adapter<OptimizedAdapter.ViewHolder> {
private List<String> dataList;
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textView);
imageView = itemView.findViewById(R.id.imageView);
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_optimized, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
String item = dataList.get(position);
holder.textView.setText(item);
// 使用Glide加载图片,避免内存溢出
Glide.with(holder.itemView.getContext())
.load(getImageUrl(item))
.into(holder.imageView);
}
@Override
public int getItemCount() {
return dataList.size();
}
}
使用Glide加载图片:
dependencies {
implementation 'com.github.bumptech.glide:glide:4.13.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0'
}
5.3 电池优化
使用WorkManager进行后台任务:
public class SyncWorker extends Worker {
public SyncWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
// 执行后台同步任务
try {
// 模拟同步操作
Thread.sleep(5000);
// 保存同步结果
SharedPreferences prefs = getApplicationContext()
.getSharedPreferences("sync_prefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putLong("last_sync_time", System.currentTimeMillis());
editor.apply();
return Result.success();
} catch (Exception e) {
return Result.failure();
}
}
}
安排WorkManager任务:
public class WorkManagerActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_work_manager);
// 创建WorkRequest
PeriodicWorkRequest syncWorkRequest = new PeriodicWorkRequest.Builder(
SyncWorker.class,
15, // 间隔时间,单位:分钟
TimeUnit.MINUTES
).build();
// 安排任务
WorkManager.getInstance(this).enqueue(syncWorkRequest);
}
}
第六部分:进阶技术
6.1 Jetpack Compose
Jetpack Compose是Android的现代UI工具包,使用声明式UI编程。
添加依赖:
dependencies {
implementation 'androidx.compose.ui:ui:1.2.0'
implementation 'androidx.compose.material:material:1.2.0'
implementation 'androidx.compose.ui:ui-tooling-preview:1.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1'
implementation 'androidx.activity:activity-compose:1.6.0'
}
创建Compose UI:
class ComposeActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// 使用Material Design主题
MyApplicationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
UserScreen()
}
}
}
}
}
@Composable
fun UserScreen() {
val viewModel: UserViewModel = viewModel()
val users by viewModel.users.collectAsState()
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Text(
text = "用户列表",
style = MaterialTheme.typography.h4,
modifier = Modifier.padding(bottom = 16.dp)
)
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
items(users) { user ->
UserItem(user)
Spacer(modifier = Modifier.height(8.dp))
}
}
}
}
@Composable
fun UserItem(user: User) {
Card(
modifier = Modifier
.fillMaxWidth()
.clickable { /* 处理点击 */ },
elevation = 4.dp
) {
Row(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = user.avatarResId),
contentDescription = user.name,
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
)
Spacer(modifier = Modifier.width(16.dp))
Column {
Text(
text = user.name,
style = MaterialTheme.typography.h6
)
Text(
text = user.email,
style = MaterialTheme.typography.body2,
color = Color.Gray
)
}
}
}
}
6.2 依赖注入(Dagger Hilt)
Dagger Hilt是Google推荐的依赖注入框架,简化了Dagger的使用。
添加依赖:
// build.gradle (Project)
buildscript {
dependencies {
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.44'
}
}
// build.gradle (Module: app)
dependencies {
implementation 'com.google.dagger:hilt-android:2.44'
annotationProcessor 'com.google.dagger:hilt-compiler:2.44'
}
创建Application类:
@HiltAndroidApp
public class MyApplication extends Application {
// Hilt会自动初始化
}
创建Module:
@Module
@InstallIn(SingletonComponent.class)
public class NetworkModule {
@Provides
@Singleton
public OkHttpClient provideOkHttpClient() {
return new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor())
.build();
}
@Provides
@Singleton
public Retrofit provideRetrofit(OkHttpClient okHttpClient) {
return new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
@Provides
@Singleton
public ApiService provideApiService(Retrofit retrofit) {
return retrofit.create(ApiService.class);
}
}
在Activity中使用:
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
ApiService apiService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 现在可以直接使用apiService
fetchUserData();
}
private void fetchUserData() {
// 使用注入的apiService
Call<User> call = apiService.getUserById(1);
// ... 网络请求逻辑
}
}
6.3 模块化架构
模块化项目结构:
MyApp/
├── app/ # 主应用模块
├── core/ # 核心模块
│ ├── common/ # 通用工具类
│ ├── data/ # 数据层
│ └── network/ # 网络层
├── feature-auth/ # 认证功能模块
├── feature-home/ # 主页功能模块
├── feature-settings/ # 设置功能模块
└── build.gradle # 项目级构建文件
模块化build.gradle配置:
// app/build.gradle
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}
android {
// ... 其他配置
// 动态功能模块
dynamicFeatures = [
":feature-auth",
":feature-home",
":feature-settings"
]
}
dependencies {
implementation project(':core:common')
implementation project(':core:data')
implementation project(':core:network')
// 其他依赖...
}
核心模块的build.gradle:
// core/common/build.gradle
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
}
android {
// ... 配置
// 导出模块供其他模块使用
consumerProguardFiles 'consumer-rules.pro'
}
dependencies {
// 核心模块的依赖
}
第七部分:测试
7.1 单元测试
添加依赖:
dependencies {
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:4.8.0'
testImplementation 'androidx.arch.core:core-testing:2.1.0'
}
编写单元测试:
@RunWith(MockitoJUnitRunner.class)
public class UserRepositoryTest {
@Mock
private UserDao userDao;
@Mock
private ApiService apiService;
private UserRepository userRepository;
@Before
public void setUp() {
userRepository = new UserRepository(userDao, apiService);
}
@Test
public void testGetUserById() {
// 准备测试数据
UserEntity userEntity = new UserEntity("张三", "zhangsan@example.com", 25);
userEntity.setId(1);
// 模拟Dao返回
when(userDao.getById(1)).thenReturn(userEntity);
// 执行测试
UserEntity result = userRepository.getUserById(1);
// 验证结果
assertNotNull(result);
assertEquals("张三", result.getName());
assertEquals("zhangsan@example.com", result.getEmail());
// 验证方法被调用
verify(userDao).getById(1);
}
@Test
public void testGetUserByIdFromNetwork() {
// 模拟网络请求返回
User networkUser = new User("李四", "lisi@example.com", R.drawable.avatar2);
Call<User> call = mock(Call.class);
Response<User> response = Response.success(networkUser);
when(apiService.getUserById(2)).thenReturn(call);
when(call.execute()).thenReturn(response);
// 执行测试
User result = userRepository.getUserFromNetwork(2);
// 验证结果
assertNotNull(result);
assertEquals("李四", result.getName());
}
}
7.2 仪器测试
添加依赖:
dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test:rules:1.4.0'
}
编写仪器测试:
@RunWith(AndroidJUnit4.class)
public class LoginActivityTest {
@Rule
public ActivityScenarioRule<LoginActivity> activityRule =
new ActivityScenarioRule<>(LoginActivity.class);
@Test
public void testLoginSuccess() {
// 在UI线程上执行测试
activityRule.getScenario().onActivity(activity -> {
// 查找视图
EditText usernameEditText = activity.findViewById(R.id.et_username);
EditText passwordEditText = activity.findViewById(R.id.et_password);
Button loginButton = activity.findViewById(R.id.btn_login);
// 输入测试数据
usernameEditText.setText("admin");
passwordEditText.setText("123456");
// 点击登录按钮
loginButton.performClick();
// 验证结果
// 检查是否跳转到主页面
Intent expectedIntent = new Intent(activity, MainActivity.class);
// 使用IntentMatchers进行验证
// ... 验证逻辑
});
}
@Test
public void testLoginFailure() {
activityRule.getScenario().onActivity(activity -> {
EditText usernameEditText = activity.findViewById(R.id.et_username);
EditText passwordEditText = activity.findViewById(R.id.et_password);
Button loginButton = activity.findViewById(R.id.btn_login);
// 输入错误的凭据
usernameEditText.setText("wrong");
passwordEditText.setText("wrong");
loginButton.performClick();
// 验证显示错误消息
// 使用Toast或Snackbar验证
});
}
}
第八部分:发布与部署
8.1 生成签名APK
创建签名密钥:
# 使用keytool生成密钥库
keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
配置gradle.properties:
# gradle.properties
MYAPP_RELEASE_STORE_FILE=my-release-key.jks
MYAPP_RELEASE_KEY_ALIAS=my-alias
MYAPP_RELEASE_STORE_PASSWORD=your_password
MYAPP_RELEASE_KEY_PASSWORD=your_password
配置build.gradle:
android {
signingConfigs {
release {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
8.2 优化APK大小
使用ProGuard/R8:
# proguard-rules.pro
-keep class com.example.myapp.** { *; }
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keepclassmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
使用App Bundle:
# 生成App Bundle
./gradlew bundleRelease
8.3 Google Play发布
准备发布材料:
- 应用图标(512x512 px)
- 截图(至少4张,不同尺寸)
- 应用描述(英文和本地语言)
- 隐私政策链接
- 内容分级问卷
发布步骤:
- 登录Google Play Console
- 创建新应用
- 填写商店信息
- 上传App Bundle
- 设置定价和分发范围
- 提交审核
第九部分:最佳实践与常见问题
9.1 代码规范
命名规范:
- 类名:使用PascalCase(如
UserActivity) - 方法名:使用camelCase(如
getUserById()) - 常量:使用UPPER_CASE(如
MAX_USERS) - 布局文件:使用snake_case(如
activity_main.xml)
代码组织:
com.example.myapp/
├── data/ # 数据层
│ ├── model/ # 数据模型
│ ├── repository/ # 数据仓库
│ └── source/ # 数据源(本地/远程)
├── domain/ # 领域层
│ ├── entity/ # 领域实体
│ └── usecase/ # 用例
├── presentation/ # 表现层
│ ├── view/ # 视图
│ ├── viewmodel/ # 视图模型
│ └── adapter/ # 适配器
├── di/ # 依赖注入
└── common/ # 通用工具类
9.2 常见问题解决
问题1:内存泄漏
- 原因:静态引用Activity、未取消的异步任务、监听器未移除
- 解决方案:
- 使用WeakReference
- 在onDestroy中取消任务
- 使用LeakCanary检测
问题2:ANR(应用无响应)
- 原因:主线程执行耗时操作
- 解决方案:
- 将耗时操作移到后台线程
- 使用协程或RxJava
- 优化数据库查询
问题3:网络请求失败
- 原因:网络权限缺失、URL错误、服务器问题
- 解决方案:
- 检查AndroidManifest.xml中的网络权限
- 使用OkHttp的拦截器调试
- 实现重试机制
问题4:UI卡顿
- 原因:过度绘制、频繁GC、布局嵌套过深
- 解决方案:
- 使用ConstraintLayout减少嵌套
- 使用RecyclerView优化列表
- 使用Systrace分析性能
第十部分:总结与展望
通过本文的实例分析,我们从Android开发的基础知识开始,逐步深入到UI设计、数据存储、网络通信、性能优化等核心领域,并介绍了Jetpack Compose、依赖注入等进阶技术。每个部分都提供了完整的代码示例,帮助读者理解并实践。
学习路径建议:
- 初学者:从基础组件开始,掌握Activity、Fragment、布局系统
- 中级开发者:深入学习数据存储、网络通信、性能优化
- 高级开发者:掌握架构模式、模块化、测试、发布流程
未来趋势:
- Jetpack Compose:将成为Android UI开发的主流
- Kotlin Multiplatform:跨平台开发的潜力
- AI集成:机器学习在移动端的应用
- 隐私保护:更严格的数据保护要求
持续学习资源:
- 官方文档:developer.android.com
- Google Codelabs:codelabs.developers.google.com
- Android Developers Blog
- GitHub开源项目
Android开发是一个不断演进的领域,保持学习和实践是成为优秀开发者的关键。希望本文能为你的Android开发之旅提供有价值的指导。
