GreenDao3使用完全解析
1,gradle配置(官网样例地址https://github.com/greenrobot/greenDAO/blob/master/examples/RxDaoExample/build.gradle) Module的gradle 里安装如下配置(官方给的配置样例) buildscript {
repositories {
jcenter()
mavenCentral()
} dependencies {
classpath 'com.android.tools.build:gradle:2.3.1'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
}
}
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.example.administrator.myapplication"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
} greendao {
targetGenDir 'src/main/java'
daoPackage 'com.example.administrator.myapplication'
/*
*schemaVersion 当前数据库结构的版本。结构版本变化时在OpenHelpers中被使用到。当你改变实体或者数据的结构时,这个值应该增加。
daoPackage 生成的DAO,DaoMaster和DaoSession的包名。默认是实体的包名。
targetGenDir 生成源文件的路径。默认源文件目录是在build目录中的(build/generated/source/greendao)。
generateTests 设置是否自动生成单元测试。
targetGenDirTest 生成的单元测试的根目录。
* */
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile 'org.greenrobot:greendao:3.2.2'
compile 'org.greenrobot:greendao-generator:3.2.2'
}
uploadArchives.enabled = false 2,GreenDao注解详解 /*
* A、
@Entity用于描述实体类名,其中active表示update/delete/refresh 方法是否自动生成,默认为false.
createInDb表示是否在数据库中创建表,默认为true,如果为false,将不创建该表.
generateConstructors表示是否自动生成构造方法(一个有参构造,一个无参构造).
indexes表示制定查询数据返回的默认排序规则.(@Index中的value制定排序的数据表中的列明加上排序规则即(ASC/DESC),
name表示......,unique表示是否唯一即SQL中的去重复
如果按照多个字段来排序可以这样(比如(indexes={@Index(value="ID ASC"),@Index(value="AGE DESC")}或者
indexes={@Index(value="ID ASC AGE DESC")})))
nameInDb表示该实体对应的数据表的名称,默认为实体名的拼音全大写
generateGettersSetters表示是否自动生成get/set方法,默认为true
B、@Id表示该字段是主键,autoincrement表示是否自增,默认为false.
C、@Property用于描述字段,nameInDb表示该字段在数据表中对应的列名,默认是实体字段名称.
D、@NotNull表示该字段不为null.
E、@Transient 表示在创建数据表时候忽略这个字段,也就是在创建表的时候不会创建这个字段.
F、@ToOne表示一对一的关系,也就是多条这个实体只对应一条标识的实体joinProperty标识这个实体表中的哪个字段和标识的实体表的主键关联.
G、@ToMany标识一对多的关系,也就是一条该实体数据通过指定列名和标识的数据实体的指定列名对应关系(@referencedJoinProperty表示当前标识的实体对应的数据表的
主键,@joinProperties表示当前表和标识的实体对应的数据表的属性对应关系)
H、@Convert定义当前标识的实体和数据表中字段之间装换规则.converter表示转换器.columnType表示对应的数据表列名在表中的数据类型,
* */ 以下是这些注释的详细例子: package com.example.administrator.myapplication; import org.greenrobot.greendao.DaoException;
import org.greenrobot.greendao.annotation.Convert;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Index;
import org.greenrobot.greendao.annotation.JoinProperty;
import org.greenrobot.greendao.annotation.NotNull;
import org.greenrobot.greendao.annotation.Property;
import org.greenrobot.greendao.annotation.Transient;
import java.util.List;
/**
* Created by Administrator on 2017/5/26.
*/
@org.greenrobot.greendao.annotation.Entity(
active = true//表示update/delete/refresh 方法是否自动生成,默认为false
,createInDb = true//表示是否在数据库中创建该表,默认为true
,generateConstructors = true//表示是否生成构造方法(一般有两个,一个有参数,一个无参数),默认为false
,indexes ={ @Index(value ="Id ASC"),@Index(value = "Age DESC")}
//indexes表示数据表查询返回数据默认排序,name中的字段是该实体在数据表中的列名,value表示改实体的真实名称,unique表示是否唯一(默认为false)
,nameInDb = "STUDENT"//表示数据表的名称默认为实体类的名称
,generateGettersSetters = true//表示是否生成get/set方法,默认为true
)
public class Student {
@org.greenrobot.greendao.annotation.Id(autoincrement = true)//设置数据表主键,autoincrement设置是否自增
@Property(nameInDb = "ID")//设置该字段在数据表中的名字,当字段设置为主键时候,那么该字段必须为Long型
public Long Id;
@NotNull
@Property(nameInDb = "AGE")
public int Age;
@NotNull
@Property(nameInDb = "NAME")
public String Name;
@Transient//表示在创建表是否会忽略掉这个字段
public String TransientName;
@org.greenrobot.greendao.annotation.ToOne(joinProperty = "Id")//设置多对一关系,即一条该实体数据对应多条ToOne数据的关系
public ToOne One;
@org.greenrobot.greendao.annotation.ToMany(referencedJoinProperty = "Age",joinProperties ={
@JoinProperty( referencedName ="Age",name = "Age")//建立多表连接,多对多的关系,当前表的name表示的字段和referencedName
//说表示的另外一个表的字段关联查询
})
public List<ToMany> mToManyList;
@Property(nameInDb = "TEST")
@Convert( converter = com.example.administrator.myapplication.Convert.class,columnType = String.class)//字段转换器,将实体数据装换为数据表中的数据
public Entity test;
/** Used to resolve relations */
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/** Used for active entity operations. */
@Generated(hash = 1943931642)
private transient StudentDao myDao;
@Generated(hash = 510098685)
public Student(Long Id, int Age, @NotNull String Name, Entity test) {
this.Id = Id;
this.Age = Age;
this.Name = Name;
this.test = test;
}
@Generated(hash = 1556870573)
public Student() {
}
public Long getId() {
return this.Id;
}
public void setId(Long Id) {
this.Id = Id;
}
public int getAge() {
return this.Age;
}
public void setAge(int Age) {
this.Age = Age;
}
public String getName() {
return this.Name;
}
public void setName(String Name) {
this.Name = Name;
}
public com.example.administrator.myapplication.Entity getTest() {
return this.test;
}
public void setTest(Entity test) {
this.test = test;
}
@Generated(hash = 907378687)
private transient Long One__resolvedKey;
/** To-one relationship, resolved on first access. */
@Generated(hash = 1410041857)
public ToOne getOne() {
Long __key = this.Id;
if (One__resolvedKey == null || !One__resolvedKey.equals(__key)) {
final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
ToOneDao targetDao = daoSession.getToOneDao();
ToOne OneNew = targetDao.load(__key);
synchronized (this) {
One = OneNew;
One__resolvedKey = __key;
}
}
return One;
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 2129737595)
public void setOne(ToOne One) {
synchronized (this) {
this.One = One;
Id = One == null ? null : One.getId();
One__resolvedKey = Id;
}
}
/**
* To-many relationship, resolved on first access (and after reset).
* Changes to to-many relations are not persisted, make changes to the target entity.
*/
@Generated(hash = 2087991423)
public List<ToMany> getMToManyList() {
if (mToManyList == null) {
final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
ToManyDao targetDao = daoSession.getToManyDao();
List<ToMany> mToManyListNew = targetDao._queryStudent_MToManyList(Age);
synchronized (this) {
if (mToManyList == null) {
mToManyList = mToManyListNew;
}
}
}
return mToManyList;
}
/** Resets a to-many relationship, making the next get call to query for a fresh result. */
@Generated(hash = 1358693666)
public synchronized void resetMToManyList() {
mToManyList = null;
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 1701634981)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getStudentDao() : null;
}
} package com.example.administrator.myapplication; import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Index;
import org.greenrobot.greendao.annotation.NotNull;
import org.greenrobot.greendao.annotation.Property;
import org.greenrobot.greendao.annotation.Unique;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.DaoException; /**
* Created by Administrator on 2017/5/26.
*/
@Entity(
nameInDb = "TOMANY"
,indexes = {@Index(value = "Id ASC")}
,active = true)
public class ToMany {
@org.greenrobot.greendao.annotation.Id(autoincrement = true)
@NotNull
@Unique
@Property(nameInDb = "ID")
public Long Id;
@Property(nameInDb = "NAME")
@NotNull
public String Name;
@Property(nameInDb = "AGE")
@NotNull
public int Age;
/** Used to resolve relations */
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/** Used for active entity operations. */
@Generated(hash = 1963614772)
private transient ToManyDao myDao;
@Generated(hash = 695029563)
public ToMany(@NotNull Long Id, @NotNull String Name, int Age) {
this.Id = Id;
this.Name = Name;
this.Age = Age;
}
@Generated(hash = 1463867877)
public ToMany() {
}
public Long getId() {
return this.Id;
}
public void setId(Long Id) {
this.Id = Id;
}
public String getName() {
return this.Name;
}
public void setName(String Name) {
this.Name = Name;
}
public int getAge() {
return this.Age;
}
public void setAge(int Age) {
this.Age = Age;
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 1942134982)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getToManyDao() : null;
}
} package com.example.administrator.myapplication; import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Index;
import org.greenrobot.greendao.annotation.NotNull;
import org.greenrobot.greendao.annotation.Property;
import org.greenrobot.greendao.annotation.Unique;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.DaoException; /**
* Created by Administrator on 2017/5/26.
*/
@Entity(
nameInDb = "TOONE"
,indexes = {@Index(value = "Id ASC")}
,active = true
)
public class ToOne {
@org.greenrobot.greendao.annotation.Id(autoincrement = true)
@Property(nameInDb = "ID")
@NotNull
@Unique
public Long Id;
@Property(nameInDb = "NAME")
@NotNull
public String Name;
@Property(nameInDb = "AGE")
@NotNull
public int Age;
/** Used to resolve relations */
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/** Used for active entity operations. */
@Generated(hash = 705594293)
private transient ToOneDao myDao;
@Generated(hash = 1228318430)
public ToOne(@NotNull Long Id, @NotNull String Name, int Age) {
this.Id = Id;
this.Name = Name;
this.Age = Age;
}
@Generated(hash = 348073711)
public ToOne() {
}
public Long getId() {
return this.Id;
}
public void setId(Long Id) {
this.Id = Id;
}
public String getName() {
return this.Name;
}
public void setName(String Name) {
this.Name = Name;
}
public int getAge() {
return this.Age;
}
public void setAge(int Age) {
this.Age = Age;
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 1862744651)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getToOneDao() : null;
}
} package com.example.administrator.myapplication; import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Index;
import org.greenrobot.greendao.annotation.NotNull;
import org.greenrobot.greendao.annotation.Property;
import org.greenrobot.greendao.annotation.Unique;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.DaoException; /**
* Created by Administrator on 2017/5/25.
*/
@Entity(
nameInDb = "USER"
,active = true
,indexes = {@Index(value = "Id ASC")}
)
public class User {
@org.greenrobot.greendao.annotation.Id(autoincrement = true)
@Property(nameInDb = "ID")
@NotNull
@Unique
public Long Id;
@Property(nameInDb = "NAME")
@NotNull
public String Name;
@Property(nameInDb = "AGE")
@NotNull
public int Age;
/** Used to resolve relations */
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/** Used for active entity operations. */
@Generated(hash = 1507654846)
private transient UserDao myDao;
@Generated(hash = 1925281583)
public User(@NotNull Long Id, @NotNull String Name, int Age) {
this.Id = Id;
this.Name = Name;
this.Age = Age;
}
@Generated(hash = 586692638)
public User() {
}
public Long getId() {
return this.Id;
}
public void setId(Long Id) {
this.Id = Id;
}
public String getName() {
return this.Name;
}
public void setName(String Name) {
this.Name = Name;
}
public int getAge() {
return this.Age;
}
public void setAge(int Age) {
this.Age = Age;
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 2059241980)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getUserDao() : null;
}
} 3,目前删除数据delete系列的方法只支持有主键的数据表,没主键的数据表目前只能通过sql语句来删除. 4,Insert系列方法,如果设置了主键并且主键为null则GreenDao会自动为我们添加设置主键(自增方式); 5,GreenDao缓存实现是将查询返回的结果保存到数组中如果有就从缓存的数组中查找,没有就从查询结果返回的游标中查找. 以Query.List()方法为例 public List<T> list() {
//检查线程是否是同一线程,如果不是就抛出异常
checkThread();
//查询返回游标,一般情况下这个返回的游标是CrossProcessCursor对象 Cursor cursor = dao.getDatabase().rawQuery(sql, parameters);
return daoAccess.loadAllAndCloseCursor(cursor); } 接着跳到 public List<T> loadAllAndCloseCursor(Cursor cursor) {
return dao.loadAllAndCloseCursor(cursor);
} 最终到 protected List<T> loadAllFromCursor(Cursor cursor) {
int count = cursor.getCount();
if (count == 0) {
return new ArrayList<T>();
}
List<T> list = new ArrayList<T>(count);
CursorWindow window = null;
boolean useFastCursor = false;
//如果是CrossProcessCursor对象
if (cursor instanceof CrossProcessCursor) {
window = ((CrossProcessCursor) cursor).getWindow();
if (window != null) { // E.g. Robolectric has no Window at this point
//如果两者数量相等,就将useFastCursor置为true
if (window.getNumRows() == count) {
cursor = new FastCursor(window);
useFastCursor = true;
} else {
DaoLog.d("Window vs. result size: " + window.getNumRows() + "/" + count);
}
}
} if (cursor.moveToFirst()) {
if (identityScope != null) {
identityScope.lock();
identityScope.reserveRoom(count);
} try {
//useFastCursor为false,IdentityScopeType置为IdentityScopeType.Session表示使用缓存
//这个是否useFastCursor就为true
if (!useFastCursor && window != null && identityScope != null) {
//如果不适用就转到这个方法
loadAllUnlockOnWindowBounds(cursor, window, list);
} else {
do {
//否则转到这个方法
list.add(loadCurrent(cursor, 0, false));
} while (cursor.moveToNext());
}
} finally {
if (identityScope != null) {
identityScope.unlock();
}
}
}
return list;
} final protected T loadCurrent(Cursor cursor, int offset, boolean lock) {
//如果identityScopeLong不为null,表示优先使用缓存中的数据
if (identityScopeLong != null) {
if (offset != 0) {
// Occurs with deep loads (left outer joins)
if (cursor.isNull(pkOrdinal + offset)) {
return null;
}
} long key = cursor.getLong(pkOrdinal + offset);
T entity = lock ? identityScopeLong.get2(key) : identityScopeLong.get2NoLock(key);
if (entity != null) {
return entity;
} else {
entity = readEntity(cursor, offset);
attachEntity(entity);
if (lock) {
identityScopeLong.put2(key, entity);
} else {
identityScopeLong.put2NoLock(key, entity);
}
return entity;
}
} else if (identityScope != null) {
K key = readKey(cursor, offset);
if (offset != 0 && key == null) {
// Occurs with deep loads (left outer joins)
return null;
}
T entity = lock ? identityScope.get(key) : identityScope.getNoLock(key);
if (entity != null) {
return entity;
} else {
entity = readEntity(cursor, offset);
attachEntity(key, entity, lock);
return entity;
}
} else {
// Check offset, assume a value !=0 indicating a potential outer join, so check PK
if (offset != 0) {
K key = readKey(cursor, offset);
if (key == null) {
// Occurs with deep loads (left outer joins)
return null;
}
}
T entity = readEntity(cursor, offset);
attachEntity(entity);
return entity;
}
} 6,如果想清除指定表缓存,调用 DaoConfig ().clearIdentityScope (); 或者 AbstractDao.detachAll() /**
* Detaches all entities (of type T) from the identity scope (session). Subsequent query results won't return any
* previously loaded objects.
*/
public void detachAll() {
if (identityScope != null) {
identityScope.clear();
}
} ,如果想清除所有表的缓存调用 DaoSession.clear () 如果想在查询返回结果中多返回几条数据库中没有的数据条数可以调用,可以按照这样做 protected final void attachEntity(K key, T entity, boolean lock) {
attachEntity(entity);
if (identityScope != null && key != null) {
if (lock) {
identityScope.put(key, entity);
} else {
identityScope.putNoLock(key, entity);
}
}
} ,如果想在查询结果中返回少几条指定数据,但是不删除数据表中的数据记录可以这样做 /** Detaches an entity from the identity scope (session). Subsequent query results won't return this object. */
public boolean detach(T entity) {
if (identityScope != null) {
K key = getKeyVerified(entity);
return identityScope.detach(key, entity);
} else {
return false;
}
} 以上只针对设置启用数据库缓存的情况 7,AbstractDao.refresh(T entity)是将entity实体恢复成数据表里的状态(如果启用了缓存也把缓存中的记录重置); AbstractDao.update(T entity)将对改实体的改动更新到数据表(如果启用了缓存,也把缓存中的记录更新); AbstractDao.delete(T entity)将该实体对应的数据表记录删除掉(如果启用了缓存,也把缓存中的记录删除掉); AbstractDao.save系列方法,如果数据库中存在该条数据就更新,如果不存在就添加. 8,GreenDao的delete系列删除数据记录的方法目前只支持有主键的数据表; 9,GreenDao也支持Rx操作,例如 RxDao<Student,Long> rxDAO=new RxDao < Student, Long > ( mDaoSession.getStudentDao ());
rxDAO.insertInTx ( sStudents ).subscribe ( new Action1 < Iterable < Student > > ( ) {
@Override
public void call ( Iterable < Student > pStudents ) { }
} );
GreenDao3使用完全解析的更多相关文章
- GreenDao3.0新特性解析(配置、注解、加密)
Greendao3.0release与7月6日发布,其中最主要的三大改变就是:1.换包名 2.实体注解 3.加密支持的优化 本文里面会遇到一些代码示例,就摘了官方文档和demo里的例子了,因为他们的例 ...
- Android框架之路——GreenDao3.2.2的使用
一.简介 GreenDAO是一个开源的安卓ORM框架,能够使SQLite数据库的开发再次变得有趣.它减轻开发人员处理低级数据库需求,同时节省开发时间. SQLite是一个令人敬畏的内嵌的关系数据库,编 ...
- GreenDao3.2的使用
原文:http://blog.csdn.net/qq_30379689/article/details/54410838 GreenDao3.2的使用,爱不释手 本篇文章包括以下内容: 前言 Gree ...
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- .NET Core中的认证管理解析
.NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...
- Html Agility Pack 解析Html
Hello 好久不见 哈哈,今天给大家分享一个解析Html的类库 Html Agility Pack.这个适用于想获取某网页里面的部分内容.今天就拿我的Csdn的博客列表来举例. 打开页面 用Fir ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
随机推荐
- PHP 支付类库, cURL开源HTTP类库
未做任何测试 支付类库地址:http://doc.yurunsoft.com/PaySDK cURL开源HTTP类库地址:http://doc.yurunsoft.com/YurunHttp/1
- 【题解】Luogu P2522 [HAOI2011]Problem b
原题传送门 这题需要运用莫比乌斯反演(懵逼钨丝繁衍) 我们看题面,让求对于区间\([a,b]\)内的整数x和\([c,d]\)内的y,满足$ gcd(x,y)=k$的数对的个数 我们珂以跟容斥原理(二 ...
- 大R玩家体验时空猎人折扣平台多角度分析
<时空猎人>讲述了时空裂隙的出现,导致大批魔物入侵阿达拉大陆.玩家可扮演狼人.机械师.异能者.冰魄等职业,与这片大陆的人们保卫家园. 游戏拥有宠物.等战斗培养元素,还引入竞技场.攻城战等P ...
- topcoder srm 515 div1
problem1 link 暴力枚举即可. problem2 link 一共有24小时,所以最多有24个顾客.设$f[x][y][z]$表示还剩下$x$把刀,现在时间是$y$,以及来过的顾客集合为$z ...
- cf水题
题意:输入多组数据,有的数据代表硬币的长宽,有的数据代表钱包的长宽,问你当这组数据代表钱包的长宽时,能不能把它前面出现的所有硬币全部装下. 思路:只要钱包的长宽大于前面出现的所有硬币的长宽就可以装下, ...
- 5.sql2008分组与嵌套
1.Group by基本介绍;2.Having的使用;3.分组综合应用;4.子查询基本介绍;5.In/Exists/Any/Some/All;6.子查询综合应用; 1.Group by基本介绍:依据B ...
- SpringBoot 使用Sharding-JDBC进行分库分表及其分布式ID的生成
为解决关系型数据库面对海量数据由于数据量过大而导致的性能问题时,将数据进行分片是行之有效的解决方案,而将集中于单一节点的数据拆分并分别存储到多个数据库或表,称为分库分表. 分库可以有效分散高并发量,分 ...
- 推荐一个静态博客兼笔记的工具:WDTP
简介 WDTP(山湖录)不止是一款开源免费的GUI桌面单机版静态网站生成器和简单方便的前端开发工具,更是一款跨平台的集笔记.录音.个人知识管理.写作/创作.博客/网站内容与样式管理等功能于一体的多合一 ...
- C++中的string常用函数用法
标准c++中string类函数介绍 注意不是CString 之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必 担心内存是否足够.字符串长度等等,而 ...
- [bzoj 4034][HAOI 2015]树上操作
Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...