资料

学习过程记录

照着各种文章写,简单的实现都一样,可跑起来总是挂

java.lang.RuntimeException: cannot find implementation for com.charliesong.roomtest.room.JavaDatabase. JavaDatabase_Impl does not exist

at androidx.room.Room.getGeneratedImplementation(Room.java:94)

at androidx.room.RoomDatabase$Builder.build(RoomDatabase.java:723)

就是我们那个database类里获取实例Room.databaseBuilder().build(),调用build方法的时候就挂了。

提示很明显,这个database按道理系统应该自动生成一个Impl类的,可我们没有自动生成,可也不知道咋让他自动生成

public abstract class JavaDatabase extends RoomDatabase

各种解决都不行啊,不过好像和kotlin有关,最后我把room相关的类,都改成java写,然后就可以了。

如下

image.png

后记

后来发现,room库分kotlin版本和java版本的,引用的不同的东西,具体用啥,下边有room的文档地址可以查

kotlin写的

apply plugin: 'kotlin-kapt'

//room

def room_version = "2.2.5"

implementation "androidx.room:room-runtime:$room_version"

kapt "androidx.room:room-compiler:$room_version"

// optional - Kotlin Extensions and Coroutines support for Room

implementation "androidx.room:room-ktx:$room_version"

java写的

def room_version = "2.2.5"

implementation "androidx.room:room-runtime:$room_version"

annotationProcessor "androidx.room:room-compiler:$room_version"

整理下基本操作

最新的room版本可以到官网查询,20190827目前都2.2了

room

第一步app的build.gradle下添加库

def room_version = "1.1.1"

// or, for latest rc, use "1.1.1-rc1"

implementation "android.arch.persistence.room:runtime:$room_version"

// annotationProcessor "android.arch.persistence.room:compiler:$room_version"

kapt "android.arch.persistence.room:compiler:$room_version"

// optional - RxJava support for Room

implementation "android.arch.persistence.room:rxjava2:$room_version"

// optional - Guava support for Room, including Optional and ListenableFuture

implementation "android.arch.persistence.room:guava:$room_version"

// Test helpers

testImplementation "android.arch.persistence.room:testing:$room_version"

或者是androidx的

def room_version = "2.1.0-alpha02"

implementation "androidx.room:room-runtime:$room_version"

kapt "androidx.room:room-compiler:$room_version" // Kotlin 的话用kapt

// 如果需要用到 rxjava

implementation "androidx.room:room-rxjava2:$room_version"

// 如果需要用到 guava

implementation "androidx.room:room-guava:$room_version"

// 需要用到相关测试工具的话

testImplementation "androidx.room:room-testing:$room_version"

如果用kotlin的话,最上边应该是这样的

apply plugin: 'com.android.application'

apply plugin: 'kotlin-kapt'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {

compileSdkVersion 27

defaultConfig {

applicationId "com.charliesong.demo0327"

minSdkVersion 18

targetSdkVersion 27

versionCode 2

versionName "1.1"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

multiDexEnabled true

//指定room.schemaLocation生成的文件路径

javaCompileOptions {

annotationProcessorOptions {

arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]

}

}

}

添加实体类

当一个类用@Entity注解并且被@Database注解中的entities属性所引用,Room就会在数据库中为那个entity创建一张表。

默认Room会为entity中定义的每一个field都创建一个column。如果一个entity中有你不想持久化的field,那么你可以使用@Ignore来注释它们

另外记得entity必须有一个@PrimaryKey 主键字段

import android.arch.persistence.room.ColumnInfo;

import android.arch.persistence.room.Entity;

import android.arch.persistence.room.PrimaryKey;

@Entity

public class Userjava {

@PrimaryKey(autoGenerate = true)

public int uid;

public String firstName;

public String lastName;

public int age;

@ColumnInfo(name = "region")//列的名字可以改

public String address;

}

添加数据访问对象dao

import android.arch.lifecycle.LiveData;

import android.arch.persistence.room.Dao;

import android.arch.persistence.room.Delete;

import android.arch.persistence.room.Insert;

import android.arch.persistence.room.Query;

import android.arch.persistence.room.Update;

import java.util.List;

@Dao

public interface UserJavaDao {

@Insert

void insertAll(Userjava... userjava);

@Query("select * from Userjava")

LiveData> getUsersFromSync();

@Delete

int delete(Userjava userjava);//参数可以是数组,集合,返回的是删除成功的条数

@Update

int update(Userjava... userjava);//参数可以是数组,集合,返回的是update成功的条数

}

database类

版本号必须>=1

import android.arch.persistence.db.SupportSQLiteDatabase;

import android.arch.persistence.room.Database;

import android.arch.persistence.room.Room;

import android.arch.persistence.room.RoomDatabase;

import android.arch.persistence.room.migration.Migration;

import android.support.annotation.NonNull;

import com.charliesong.demo0327.app.MyApplication;

//所有的entity注解的类,都得在这里声明

@Database(entities = {Userjava.class},version =4)

public abstract class JavaDatabase extends RoomDatabase {

//定义了几个Dao注解的类,这里就写几个抽象方法

public abstract UserJavaDao userJavaDao();

private static JavaDatabase javaDatabase;

public static JavaDatabase instance(){

if(javaDatabase==null){

synchronized (JavaDatabase.class){

if(javaDatabase==null){

javaDatabase= Room.databaseBuilder(MyApplication.myApplication,JavaDatabase.class,"test").

addCallback(new Callback() {

@Override

public void onCreate(@NonNull SupportSQLiteDatabase db) {

super.onCreate(db);

System.out.println("onCreate==========="+db.getVersion()+"==="+db.getPath());

}

@Override

public void onOpen(@NonNull SupportSQLiteDatabase db) {

super.onOpen(db);

System.out.println("onOpen==========="+db.getVersion()+"==="+db.getPath());

}

})

.allowMainThreadQueries()//允许在主线程查询数据

.addMigrations(migration)//迁移数据库使用,下面会单独拿出来讲

.fallbackToDestructiveMigration()//迁移数据库如果发生错误,将会重新创建数据库,而不是发生崩溃

.build();

}

}

}

return javaDatabase;

}

//数据库升级用的

static Migration migration=new Migration(1,4) {

@Override

public void migrate(@NonNull SupportSQLiteDatabase database) {

System.out.println("migrate============"+database.getVersion());

database.execSQL("ALTER TABLE Userjava "+ " ADD COLUMN address TEXT");

}

};

}

然后就可以测试拉。

使用livedata比较方便,只处理数据库的增删改,发生变化livedata自动会变化,我们弄个observer就ok了,列表会自动刷新的

UtilRoomDB.getUserDao().usersFromSync.observe(this, Observer {

myAdapter.submitList(it)

})

我用的listAdapter

inner class MyAdapter(callback: DiffUtil.ItemCallback): ListAdapter(callback)

顺道记录些其他问题

Error:(22, 17) 警告: Schema export directory is not provided to the annotation processor so we cannot export the schema.

You can either provide `room.schemaLocation` annotation processor argument OR set exportSchema to false.

方法1

添加 exportSchema = false 就是不需要这个表的json数据

@Database(entities = { YourEntity.class }, version = 1, exportSchema = false)

public abstract class MovieDatabase extends RoomDatabase {

...

}

android {

compileSdkVersion 26

buildToolsVersion "26.0.2"

defaultConfig {

applicationId "com.xingen.architecturecomponents"

minSdkVersion 15

targetSdkVersion 26

versionCode 1

versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

//指定room.schemaLocation生成的文件路径

javaCompileOptions {

annotationProcessorOptions {

arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]

}

}

}

}

运行以后就能看到下边的东西了,json文件里可以看到我们定义的表以及其包含的字段,主键等信息

image.png

版本升级

打印下可以看到,第一次操作数据库的时候,先create,再open

System.out.println("onCreate==========="+db.getVersion()+"==="+db.getPath());

onCreate===========0===/data/user/0/com.charliesong.demo0327/databases/test

onOpen===========1===/data/user/0/com.charliesong.demo0327/databases/test

升级操作

如果你改了版本,然后没有写Migration,那么升级以后数据库就被清空了。

这两个方法,要么别写,要写了你就得有对应的migration,

// .addMigrations(migration,migration2)//迁移数据库使用,下面会单独拿出来讲

// .fallbackToDestructiveMigration()//迁移数据库如果发生错误,将会重新创建数据库,而不是发生崩溃

我们一般升级数据库,应该是增加了字段或者修改了字段之类的。

//数据库升级用的,从版本1升级到版本2

static Migration migration=new Migration(1,2) {

@Override

public void migrate(@NonNull SupportSQLiteDatabase database) {

System.out.println("migrate12============"+database.getVersion());

database.execSQL("ALTER TABLE Userjava "+ " ADD COLUMN country TEXT");

}

};

版本2升级到版本4,打算删除表中的一列

如果想改某列的类型,名称啥的也一样操作

.addMigrations(migration,migration2,migration3)

好像drop column不好使,所以就新建个临时表,复制下数据然后删除老的,再把新表名字改回去

static Migration migration2=new Migration(2,3) {

@Override

public void migrate(@NonNull SupportSQLiteDatabase database) {

System.out.println("migrate23============"+database.getVersion());

database.execSQL("create table aaaa(uid int primary key,firstName text,lastName text,age text,address text)");

database.execSQL("insert into aaaa select uid ,firstName ,lastName ,age,address from Userjava");

database.execSQL("drop table Userjava");

database.execSQL("alter table aaaa rename to Userjava");

}

};

static Migration migration3=new Migration(3,4) {

@Override

public void migrate(@NonNull SupportSQLiteDatabase database) {

System.out.println("migrate34============"+database.getVersion());

// database.execSQL("ALTER TABLE Userjava "+ " ADD COLUMN address TEXT");

}

};

日志如下,2个print都出来了,然后挂了

看了下,我们上边新建那个aaaa的表,数据类型有点问题,那就改一下

Process: com.charliesong.demo0327, PID: 30844

java.lang.IllegalStateException: Migration didn't properly handle Userjava(com.charliesong.demo0327.room.Userjava).

Expected:

TableInfo{name='Userjava', columns={address=Column{name='address', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, lastName=Column{name='lastName', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, firstName=Column{name='firstName', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, uid=Column{name='uid', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}}, foreignKeys=[], indices=[]}

Found:

TableInfo{name='Userjava', columns={address=Column{name='address', type='text', affinity='2', notNull=false, primaryKeyPosition=0}, lastName=Column{name='lastName', type='text', affinity='2', notNull=false, primaryKeyPosition=0}, firstName=Column{name='firstName', type='text', affinity='2', notNull=false, primaryKeyPosition=0}, uid=Column{name='uid', type='int', affinity='3', notNull=false, primaryKeyPosition=1}, age=Column{name='age', type='text', affinity='2', notNull=false, primaryKeyPosition=0}}, foreignKeys=[], indices=[]}

at com.charliesong.demo0327.room.JavaDatabase_Impl$1.validateMigration(JavaDatabase_Impl.java:75)

at android.arch.persistence.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:87)

at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onUpgrade(FrameworkSQLiteOpenHelper.java:133)

at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:256)

at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)

at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:96)

at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:54)

at android.arch.persistence.room.RoomDatabase.query(RoomDatabase.java:233)

at com.charliesong.demo0327.room.UserJavaDao_Impl$4.compute(UserJavaDao_Impl.java:165)

at com.charliesong.demo0327.room.UserJavaDao_Impl$4.compute(UserJavaDao_Impl.java:151)

at android.arch.lifecycle.ComputableLiveData$2.run(ComputableLiveData.java:100)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)

at java.lang.Thread.run(Thread.java:818)

这是成功的日志

11-15 09:15:27.546 com.charliesong.demo0327 I/System.out: migrate23============2

11-15 09:15:27.556 com.charliesong.demo0327 I/System.out: migrate34============2

11-15 09:15:27.606 com.charliesong.demo0327 I/System.out: onOpen===========4===/data/user/0/com.charliesong.demo0327/databases/test

new Migration(4,6) 里边2个版本号到底指的啥

为了测试,

@1 版本从4直接改到8,然后添加2个Migration

new Migration(4,6)和new Migration(4,8)

打印了下,发现只走了4到8

@2 然后版本从8改成11,添加下边2个

new Migration(8,10) new Migration(9,11)

然后2个都没走,然后数据被清空了

看下Migration的查询条件

存储的时候是存在这个集合里的

private SparseArrayCompat> mMigrations =

new SparseArrayCompat<>();

比如(4,6)和(4,8)那么就是append一个key是4的,然后里边包含的key是6和8的sparsearray

简单分析下,我们只说升级,不说降级。

如下逻辑,从4升级到8,那么根据start=4,找到一个sparsearray,这里包含2个key是6和8,它是倒着来,找到第一个小于等于endVersion也就是8了,这个刚刚好就找一次。

然后分析下从8升级到11,有个(8,10)和(9,11)

先查8,找到一个end10,然后 从10开始查,结果10 没找到,所以返回一个null。因为返回的null。再下边那个方法可以看到,返回null的话数据库就被清空了。

private List findUpMigrationPath(List result, boolean upgrade,

int start, int end) {

final int searchDirection = upgrade ? -1 : 1;

while (upgrade ? start < end : start > end) {

SparseArrayCompat targetNodes = mMigrations.get(start);

if (targetNodes == null) {

return null;

}

// keys are ordered so we can start searching from one end of them.

final int size = targetNodes.size();

final int firstIndex;

final int lastIndex;

if (upgrade) {

firstIndex = size - 1;

lastIndex = -1;

} else {

firstIndex = 0;

lastIndex = size;

}

boolean found = false;

for (int i = firstIndex; i != lastIndex; i += searchDirection) {

final int targetVersion = targetNodes.keyAt(i);

final boolean shouldAddToPath;

if (upgrade) {

shouldAddToPath = targetVersion <= end && targetVersion > start;

} else {

shouldAddToPath = targetVersion >= end && targetVersion < start;

}

if (shouldAddToPath) {

result.add(targetNodes.valueAt(i));

start = targetVersion;

found = true;

break;

}

}

if (!found) {

return null;

}

}

return result;

}

这里是调用的方法

public void onUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {

boolean migrated = false;

if (mConfiguration != null) {

List migrations = mConfiguration.migrationContainer.findMigrationPath(

oldVersion, newVersion);

if (migrations != null) {

for (Migration migration : migrations) {

migration.migrate(db);

}

mDelegate.validateMigration(db);

updateIdentity(db);

migrated = true;

}

}

if (!migrated) {//如果没找到List migrations,那么就会清空表的

if (mConfiguration != null && !mConfiguration.isMigrationRequiredFrom(oldVersion)) {

mDelegate.dropAllTables(db);

mDelegate.createAllTables(db);

} else {

throw new IllegalStateException("A migration from " + oldVersion + " to "

+ newVersion + " was required but not found. Please provide the "

+ "necessary Migration path via "

+ "RoomDatabase.Builder.addMigration(Migration ...) or allow for "

+ "destructive migrations via one of the "

+ "RoomDatabase.Builder.fallbackToDestructiveMigration* methods.");

}

}

}

添加一个新的entity

错误日志,说这个实体类没有加到database,啥鬼啊,搞不懂。后来才查到,注解那里要添加的,忘了

@Database(entities = {Userjava.class,HourseJava.class},version =1)

public abstract class JavaDatabase extends RoomDatabase

E:\androidStudio\RoomTest\app\src\main\java\com\charliesong\roomtest\room\HourseJavaDao.java:9:

错误: com.charliesong.roomtest.room.HourseJavaDao

is part of com.charliesong.roomtest.room.JavaDatabase

but this entity is not in the database. Maybe you forgot to add com.charliesong.roomtest.room.HourseJava

to the entities section of the @Database?

void insertHourse(HourseJava ...hourseJavas);

^

添加新的entity步骤

需要在database的注解字段entities里添加,完事需要升级版本号,记得添加migration,

比如你从2升级到3,那么必须添加一个Migration(2,3),否则如果没找到这玩意,数据库就被清空了。还得自己在migration方法里添加create table的命令,建立新表,要不会报错的。

后记

room这东西是编译的时候生成相关的类的,databinding也是,有时候是room这边有问题,导致databinding生成失败,结果你看错误信息都是databinding的。

注解学习

错误记录

Cannot figure out how to save this field into database. You can consider adding a type converter for it.

原因,实体类里有个自定义对象,不认识

public DataType dataType;//这玩意就是个枚举类型

解决办法

@TypeConverters(DataTypeConverter.class)//注解用哪个类来解析存储数据

public DataType dataType;

import androidx.room.TypeConverter;

//写一个转化类,其实就是需要两个方法可以互相转化这个自定义类,转化为基本数据类型,也就是可以存入数据库的

public class DataTypeConverter{

@TypeConverter

public OneTouchBean.DataType toDataType(int index){

return OneTouchBean.DataType.values()[index];

}

@TypeConverter

public int toIndex(OneTouchBean.DataType dataType){

return dataType.ordinal();

}

}

这个注解@TypeConverters可以写在要解析的类上边,也可以写在@Database注解的类里,可以参考workManager相关的包里边有,如下代码

@Database(entities = {

Dependency.class,

WorkSpec.class,

WorkTag.class,

SystemIdInfo.class,

WorkName.class},

version = 6)

@TypeConverters(value = {Data.class, WorkTypeConverters.class})

public abstract class WorkDatabase extends RoomDatabase {

kotlin写在属性上,还是报错,必须写在类上边

java.lang.IllegalStateException: getDatabase called recursively

代码如下

在onCreate里,数据库创建成功以后,执行插入一些默认的数据操作,出错了

public abstract class LocalDatabase extends RoomDatabase {

private static LocalDatabase database;

public static LocalDatabase instance() {

if (database == null) {

synchronized (LocalDatabase.class) {

if (database == null) {

database = Room.databaseBuilder(MainApplication.getCurrentInstance(), LocalDatabase.class, "test").

addCallback(new Callback() {

@Override

public void onCreate(@NonNull SupportSQLiteDatabase db) {

super.onCreate(db);

System.out.println("onCreate===========" + db.getVersion() + "===" + db.getPath());

resetOneTouchData();//这里的代码挂了

}

//方法如下,就是插入数据,没别的

private static void resetOneTouchData(){

database.oneTouchDao().insertAll();}

根源就在于db还没关,我们又开了个db

简单的修改,把这个插入数据的操作放到一个新的线程中,让当前的db结束掉就好了。

Entity的实体类,有多个构造方法的时候会出错

错误: Room cannot pick a constructor since multiple constructors are suitable. Try to annotate unwanted constructors with @Ignore.

按照提示注解掉多余的,留下一个即可

注意

当初看demo也没看到关闭数据库,所以我也没关,当然,关不关好像对数据没啥影响

如果不关,那么可以看到多了2个临时文件,只有关闭的时候临时文件的数据才会写入db里,否则db文件可能是空的,当然数据没有丢失,你打开还在,不过是在临时文件里而已。

public static void closeDb(){

if(javaDatabase!=null){

javaDatabase.close();

javaDatabase=null;

}

}

image.png

数据库升级,表添加一列问题多多

需求:给表加一列如下的字段

private long placeUID =-1;

完事我就加了

public void migrate(@NonNull SupportSQLiteDatabase database) {

final String addColumn="alter table XXXBean add placeUID long default -1";

database.execSQL(addColumn);

}

结果挂了,异常提示expected 和found的不一样

Expected:

placeUID = Column {

name = 'placeUID', type = 'INTEGER', affinity = '3', notNull = true, primaryKeyPosition = 0, defaultValue = 'null'

},

Found:

placeUID = Column {

name = 'placeUID', type = 'Long', affinity = '1', notNull = false, primaryKeyPosition = 0, defaultValue = '-1'

},

我实体类里定义的是long,实际上room是当做int来处理的,所以,我只好把sql语句改了,类型改成INTEGER 了

final String addColumn="alter table XXXBean add placeUID INTEGER default -1";

完事还是挂,再对比提示信息,还有一个不一样的notNull = true

继续修改

final String addColumn="alter table XXXBean add placeUID INTEGER default -1";

终于完事了,不挂了

后记

没事可以看看work这个库,这里也用到了room,看看人家咋存的

image.png

常用的简单的增删改查

@Dao

public interface MyPlaceDao {

@Insert

void insertAll(MyPlaceBean... myPlaceBeans);

@Insert

long insertAll(MyPlaceBean myPlaceBeans);

@Query("select * from MyPlaceBean order by uid desc")

LiveData> getMyPlacesFromSync();

@Query("select * from myplacebean where locationData = :json")

MyPlaceBean getMyPlaceBeanByLocationJson(String json);

//COLLATE NOCASE 忽略大小写

@Query("select * from myplacebean where changedName = :name COLLATE NOCASE and uid != :uid")

List getMyPlaceBeanByChangedName(String name,long uid);

@Delete

int delete(MyPlaceBean ...myPlaceBean);//参数可以是数组,集合,返回的是删除成功的条数

@Delete

int delete(List myPlaceBean);//参数可以是数组,集合,返回的是删除成功的条数

@Update

int update(MyPlaceBean... myPlaceBeans);//参数可以是数组,集合,返回的是update成功的条数

@Update

int update(List myPlaceBeans);//参数可以是数组,集合,返回的是update成功的条数

@Query("update myplacebean set changedName = :name where uid = :uid")

int updateName(String name, long uid);

}

需要注意下,这里返回的只能是List,而不能是ArrayList,否则编译就挂了

LiveData> getMyPlacesFromSync();

kotlin需要注意的地方

TypeConverters注解是写在class上了,

下边这个自增的主键要写到构造方法里,否则,它没法自动生成id,默认就是个0

@PrimaryKey(autoGenerate = true)

var id:Int=0

@Entity

@TypeConverters(DataTypeConverter::class)

data class Task(

val name: String,

val deadline: String,

val priority: TaskPriority =TaskPriority.MEDIUM ,

var completed: Boolean = false,

@PrimaryKey(autoGenerate = true)

var id:Int=0

)

比如这样写,你会发现数据库里id都是0

data class Task(

val name: String,

val deadline: String,

val priority: TaskPriority =TaskPriority.MEDIUM ,

var completed: Boolean = false

){

@PrimaryKey(autoGenerate = true)

var id:Int=0

}

android room 简书,android Room库使用问题相关推荐

  1. android 购物车 简书,Android仿饿了么购物车效果

    先看下效果图: ezgif-1-8f133ca916.gif 1.首先列表布局采用Recycleview android:id="@+id/container" android:l ...

  2. android matrix 简书,[Android] ImageView ScaleType完全解析

    ImageView有一个ScaleType的属性,该属性决定了图片在ImageView上的展现形式,包括:是否进行缩放.如何进行缩放.缩放之后图片的摆放位置等等.官方介绍如下: Options for ...

  3. android spinner 简书,Android NiceSpinner

    NiceSpinner 是 Android 端的一款第三方控件,自带箭头动画效果 真的是简单又好用哦!有需要的小伙伴们可以试试啦. 效果图如下: image 1. 导入模块 在 Github 下载并导 ...

  4. Android入门简书,android ndk开发入门随笔(一)

    ndk,jni入门随笔 因为工作缘故最近在研究jni,ndk方面知识,在此总结入坑以来的一些问题. 配置环境可以在下面geogle官方看.下面是链接 我一说ndk,jni可能小伙伴要问了这是什么,在此 ...

  5. android opengl 简书,Android OpenGL入门

    如今VR这么火,感觉有必要先把OpenGL学好,为以后转VR奠定一些基础.一年前,接触过Android的OpenGL,当时是实现了在Android上显示标准的3D文件(STL格式).现在打算整理一下O ...

  6. android room 简书,Android Room 的坑

    在添加依赖时,官网给出的是: def room_version = "2.0.0-beta01" implementation "androidx.room:room-r ...

  7. android 音乐 简书,Android音频开发(7):音乐可视化-FFT频谱图

    Android 音频开发 目录 一.演示 image 二.实现 实现流程: 使用MediaPlayer播放传入的音乐,并拿到mediaPlayerId 使用Visualizer类拿到拿到MediaPl ...

  8. android 心跳 简书,Android Socket保持心跳长连接,断线重连

    昨天三点钟才睡觉的,现在胸口感觉闷闷的,兄弟们,我是不是要GG了?如果我G了,求大佬们给我烧个女朋友, ss.gif 1.在使用Socket连接客户端和服务器端的时候,如果服务端断开了连接,我们客户端 ...

  9. android zxing简书,Android集成zxing 版本3.4.1

    第一步:去官网下载最新jar 或者 'implementation 'com.google.zxing:core:3.4.1''引入项目. 如下图: yhx.png 如何查看最新版本: yhx.png ...

  10. android realm 简书,android 数据库SQLite realm

    一.SQLite android内置了数据库SQLite,这是一款轻量级的关系型数据库,通常只需要几百K的内存.数据库文件存放在/data/data//databases/目录下. 为了方便管理数据库 ...

最新文章

  1. 计算机仿真的过程,计算机仿真的过程与方法.doc
  2. 工信部部长苗圩于CITE发表致辞,指引三个方向推动国内电子信息产业持续发展...
  3. html中代码执行顺序
  4. Jmeter-3.0的源码导入eclipse并执行
  5. 电脑html外链加密,WordPress 无需插件外链加密转内链
  6. mysql 报错注入输出多个字段_SQL注入浅析
  7. 卷积神经网络问题总结
  8. 【2019-2020春学期】数据库作业18:第八章: 数据库编程(实验课大作业)
  9. MacBook 右键查询英文查词无法翻译成中文
  10. 华科计算机学院硕士武汉理工推免,武汉理工大学2021届保研率14.9%,主要保研本校、武大、华科...
  11. 一套键鼠操控多台电脑Mouse without Borders
  12. 人脸识别——OpenCV调取摄像头识别人脸
  13. 开发中的各种时间格式转换(一)
  14. Hive中的left semi join和left anti join
  15. 机器学习复盘(2):机器学习主要应用场景及典型案例
  16. 梅科尔工作室-华为云ModelArts的简单使用(附详细图解)
  17. NLP的“第四范式”之Prompt Learning总结:44篇论文逐一梳理
  18. XGBoost feature importance特征重要性-实战印第安人糖尿病数据集
  19. 基于Attention_CNN_GRU的野生动物监测图像分类
  20. python调用百度翻译-Python 调用百度翻译API

热门文章

  1. response.sendRedirect()的用法
  2. PMI-PBA 商业分析师 认证简介
  3. 百思不得姐php源码,百思不得姐源代码(xcode)
  4. C# worksheet设置Excel样式
  5. linux路由器还原,openwrt路由器恢复出厂设置的方法
  6. 你需要权限来执行此操作 你需要来自Administrators的权限才能对此文件夹进行更改
  7. 学习fullpage的使用
  8. leetcode加一
  9. Unity Shader 实现PS图层混合效果
  10. Android模拟PC键盘输入法,黑科技:用电脑键盘代替手机输入法