Android 开发过程中遇到的问题
Gradle 同步
在 Android Studio 进行项目同步的时候总会遇到一些问题:如果长时间都未同步成功,大概率是下载依赖出错了。可以依次使用下面的方法进行检查。
如果是 Gradle 下载版本出错,可以使用国内的镜像地址下载 Gradle,推荐使用腾讯的 Gradle 镜像。修改当前项目 gradle/wrapper/gradle-wrapper.properties 里的 distributionUrl 地址。
https\://mirrors.cloud.tencent.com/gradle
前置要求
- 检查网络是否通畅
- 如果电脑设置了访问 Google 的工具,检查是否能够正常访问 Google。
具体方法:
- 设置国内的 Gradle 的镜像地址
- 查看 Global Gradle Properties 文件是否设置代理,代理服务器及端口是否正常工作。
Global Gradle Properties 文件路径.gradle/gradle.properties
,如果是在 Android Studio 里查看,在 Android 面板找到下面这个文件即可。
Gradle Maven 阿里云效 ==="Groovy"
```Groovy
allprojects {
repositories {
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url "https://maven.aliyun.com/repository/jcenter" }
maven { url "https://maven.aliyun.com/repository/spring" }
maven { url "https://maven.aliyun.com/repository/spring-plugin" }
maven { url "https://maven.aliyun.com/repository/gradle-plugin" }
maven { url "https://maven.aliyun.com/repository/google" }
maven { url "https://maven.aliyun.com/repository/grails-core" }
maven { url "https://maven.aliyun.com/repository/apache-snapshots" }
}
}
```
OkHttp 中 DNS 超时时长过长
自定义 DNS 实现类,实现可设置超时时间。
public class XDns implements Dns {
private long timeout;
public XDns(long timeout) {
this.timeout = timeout;
}
@Override
public List<InetAddress> lookup(final String hostname) throws UnknownHostException {
if (hostname == null) {
throw new UnknownHostException("hostname == null");
} else {
try {
FutureTask<List<InetAddress>> task = new FutureTask<>(
new Callable<List<InetAddress>>() {
@Override
public List<InetAddress> call() throws Exception {
return Arrays.asList(InetAddress.getAllByName(hostname));
}
});
new Thread(task).start();
return task.get(timeout, TimeUnit.MILLISECONDS);
} catch (Exception var4) {
UnknownHostException unknownHostException =
new UnknownHostException("Broken system behaviour for dns lookup of " + hostname);
unknownHostException.initCause(var4);
throw unknownHostException;
}
}
}
}
数据库
Android API | SQLite Version |
---|---|
API 27 | 3.19 |
API 26 | 3.18 |
API 24 | 3.9 |
API 21 | 3.8 |
API 11 | 3.7 |
API 8 | 3.6 |
API 3 | 3.5 |
API 1 | 3.4 |
命令行获取当前设备的 SQLite Version
adb -e shell sqlite3 --version
运行时获取 SQLite 版本
String query = "select sqlite_version() AS sqlite_version";
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
Cursor cursor = db.rawQuery(query, null);
String sqliteVersion = "";
if (cursor.moveToNext()) {
sqliteVersion = cursor.getString(0);
}
名词解释
journal
是 SQLite 的读写的一种实现原子事件的一种机制:
原理:在修改数据库文件中的数据之前,先将修改所在分页中的数据备份在另外一个地方,然后才将修改写入到数据库文件中;如果事务失败,则将备份数据拷贝回来,撤销修改;如果事务成功,则删除备份数据,提交修改。
WAL
WAL 的全称是 Write Ahead Logging,它是很多数据库中用于实现原子事务的一种机制,SQLite 在 3.7.0 版本引入了该特性。
原理:修改并不直接写入到数据库文件中,而是写入到另外一个称为 WAL 的文件中;如果事务失败,WAL 中的记录会被忽略,撤销修改;如果事务成功,它将在随后的某个时间被写回到数据库文件中,提交修改。
同步 WAL 文件和数据库文件的行为被称为 checkpoint(检查点),它由 SQLite 自动执行,默认是在 WAL 文件积累到 1000 页修改的时候;当然,在适当的时候,也可以手动执行 checkpoint,SQLite 提供了相关的接口。执行 checkpoint 之后,WAL 文件会被清空。
在读的时候,SQLite 将在 WAL 文件中搜索,找到最后一个写入点,记住它,并忽略在此之后的写入点(这保证了读写和读读可以并行执行);随后,它确定所要读的数据所在页是否在 WAL 文件中,如果在,则读 WAL 文件中的数据,如果不在,则直接读数据库文件中的数据。
在写的时候,SQLite 将之写入到 WAL 文件中即可,但是必须保证独占写入,因此写写之间不能并行执行。
WAL 在实现的过程中,使用了共享内存技术,因此,所有的读写进程必须在同一个机器上,否则,无法保证数据一致性。
Room 导出问题
在使用 Room 进行开发的时,可能需要将数据库文件进行导出查看,如果仅导出 db_name.db 文件,则可能会出现文件无法打开或打开后未能成功加载数据库结构。
解决方法:与 db_name.db 同名的 wal 和 shm 文件一同导出即可。
tips: 团队内有小伙伴在初始化 db 的时候传入的 dbName 没有加扩展名 db,导出后 3 个文件后部分数据库软件无法识别,事实上这个文件已经是 SQLite 格式的,仅仅是未添加扩展名,需要注意的是,wal 和 shm 均需要增加 .db 的扩展名。
SQLite 返回异常码
官方地址:https://www.sqlite.org/rescode.html
SQLite_FULL
意味着磁盘空间不足,这里的磁盘空间,可能指代数据库的文件的主工程的文件空间,也可能指代数据库的临时文件的文件磁盘空间。