结丹期
8. 什么是 Android 的 ViewModel?它在应用架构中起到什么作用?
ViewModel
是 Android
Jetpack 架构组件的一部分,负责保存和管理与 UI
相关的数据,使数据在屏幕旋转或 Activity/Fragment
重建时得以保留。
ViewModel
的作用
生命周期感知:
ViewModel
可以存活于Activity
或Fragment
的整个生命周期,即使界面重建(如屏幕旋转)也不会丢失数据。分离逻辑与界面:通过
ViewModel
,数据和业务逻辑可以与UI
完全分离,便于代码的维护和测试。
示例
public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> counter;
public LiveData<Integer> getCounter() {
if (counter == null) {
counter = new MutableLiveData<>();
counter.setValue(0);
}
return counter;
}
public void incrementCounter() {
counter.setValue(counter.getValue() + 1);
}
}
ViewModel
保存了 counter
变量,即使 Activity
重建,数据也不会丢失。
9. 如何在 Android 中实现数据持久化?常见的存储方式有哪些?
Android
提供了多种数据持久化方式,开发者可以根据数据的大小、类型和应用场景选择合适的存储方法。
常见的存储方式
SharedPreferences
:用于存储简单的键值对数据,适合保存用户设置等小型数据。文件存储:将数据保存到设备内部或外部存储,适合存储文件、图片等。
SQLite
数据库:用于存储结构化数据,适合处理复杂数据关系。Room
数据库:SQLite
的高级抽象,简化了数据库操作,提供了类型安全和易于使用的接口。Content Provider
:用于在不同应用之间共享数据。
每种存储方式都有不同的使用场景,应根据具体需求选择合适的方案。
10. 什么是 SharedPreferences?如何在应用中存储和读取简单的键值对数据?
SharedPreferences
是 Android
提供的用于存储简单键值对数据的轻量级存储机制,适合保存应用的设置、用户偏好等。
存储数据的示例
SharedPreferences sharedPref = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("username", "JohnDoe");
editor.putInt("age", 25);
editor.apply(); // 提交更改
读取数据的示例
SharedPreferences sharedPref = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
String username = sharedPref.getString("username", "defaultName");
int age = sharedPref.getInt("age", 0);
通过 putString()
、putInt()
等方法将数据存入 SharedPreferences
,并通过 getString()
、getInt()
等方法读取数据。
11. 如何在 Android 中使用 SQLite?如何通过 Room 库简化数据库操作?
SQLite
是 Android
内置的轻量级关系型数据库,用于存储结构化数据。通过 SQLiteOpenHelper
类,开发者可以创建和管理数据库。
SQLite
示例
public class MyDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "MyDatabase.db";
private static final int DATABASE_VERSION = 1;
public MyDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS users");
onCreate(db);
}
}
Room
是 Jetpack
提供的数据库库,它通过注解简化了 SQLite
的使用,并提供了类型安全的接口。
定义 Entity
和 DAO
的示例
@Entity
public class User {
@PrimaryKey
public int id;
public String name;
public int age;
}
@Dao
public interface UserDao {
@Insert
void insertUser(User user);
@Query("SELECT * FROM User")
List<User> getAllUsers();
}
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
通过 Room
注解简化了数据库表的创建、插入和查询操作,不再需要手动编写 SQL
语句。
12. 如何在 Android 中使用 Content Provider 共享数据?
Content Provider
是 Android
中的组件之一,允许不同应用之间共享数据。
开发者可以通过定义自己的 Content Provider
来公开应用的数据,或者使用系统提供的 Content Provider
(如联系人、媒体等)。
Content Provider
的工作流程
定义
Content Provider
,实现数据的插入、查询、更新和删除(CRUD
操作)。其他应用通过
ContentResolver
来访问Content Provider
提供的数据。
查询系统联系人数据的示例
Cursor cursor = getContentResolver().query(
ContactsContract.Contacts.CONTENT_URI,
null, null, null, null
);
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
// 处理联系人数据
} while (cursor.moveToNext());
}
cursor.close();
通过 ContentResolver
查询系统的联系人数据,遍历 Cursor
获取每个联系人的名称。
13. 什么是 Service?Service 的生命周期是怎样的?
Service
是 Android
中的一种组件,专门用于执行后台任务,即使应用界面不可见,Service
仍然可以在后台运行。
Service
的生命周期方法
onCreate()
:Service
创建时调用,进行初始化工作。onStartCommand()
:每次启动Service
时调用,用于处理实际的业务逻辑。onDestroy()
:Service
被销毁时调用,进行资源清理。
Service
的两种类型
前台服务(Foreground Service):在通知栏显示持续运行的通知,适用于长时间运行的任务。
后台服务(Background Service):没有用户界面的任务,但可能会被系统终止。
示例
public class MyService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 执行后台任务
return START_STICKY; // 服务在被终止后自动重启
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
14. 如何在 Android 中实现多线程?如何使用 AsyncTask 和 Handler?
Android
的主线程负责处理 UI
操作,因此耗时操作(如网络请求、数据库访问)必须在工作线程中执行,以避免阻塞 UI
线程。
AsyncTask
是 Android
提供的简化多线程开发的工具类,专门用于处理后台任务,并在任务完成后更新 UI
。
AsyncTask
示例
private class DownloadTask extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... voids) {
// 在后台执行耗时操作
return "Download Complete";
}
@Override
protected void onPostExecute(String result) {
// 更新 `UI`
textView.setText(result);
}
}
new DownloadTask().execute
();
Handler
用于在工作线程和主线程之间传递消息,适合更复杂的多线程通信场景。
Handler
示例
Handler handler = new Handler(Looper.getMainLooper());
new Thread(new Runnable() {
@Override
public void run() {
// 在后台执行任务
handler.post(new Runnable() {
@Override
public void run() {
// 更新 `UI`
textView.setText("Task Complete");
}
});
}
}).start();
Handler
将任务切换到主线程,在工作线程完成任务后更新 UI
。