PS:好久没写博客了...

学习内容:

1.DAO介绍,通用DAO的简单调度过程..

2.数据库映射关系...

3.使用泛型+反射+注解封装通用DAO..

4.使用AndBase框架实现对DAO的调用实现数据库基本操作..

1.DAO..

  DAO..这个说法大家都不陌生..数据库操作访问对象的抽象接口层..在DAO内部封装好通用的方法..然后再使用一个具体类来进行实现..在我们想要调用这些方法对数据库进行相关操作时..只需要传递数据实体对象,就可以通过实体对象的传递从而实现对数据库进行操作..

  一个典型的DAO首先要有一个父类..这个父类是抽象出来的DAO接口层..内部封装了通用的抽象方法..一个简单的例子:

package com.example.databaseactivity;

import java.util.List;
import java.util.Map;
import android.database.sqlite.SQLiteOpenHelper; /*
* 通用DAO父类..
* */
public interface DBDAO<T>{ public SQLiteOpenHelper getDbHelper(); /*
* insert 函数..默认主键自增...
* */
public abstract long insert(T entity); /*
* insert 函数..flag的值决定主键是否自增...
* */
public abstract long insert(T entity,boolean flag); /*
* 插入实体类列表,默认主键自增..
* */
public abstract long insertList(List<T>entityList); /*
* 插入实体类列表,flag决定主键是否自增..
* */
public abstract long insertList(List<T>entityList,boolean flag); /*
* 根据id删除数据..
* */
public abstract long delete(int id); /*
* 根据id删除多个数据..
* */
public abstract long delete(Integer...ids); /*
* 根据指定条件删除数据..
* */
public abstract long delete(String whereCaluse,String[] whereArgs); /*
* 删除所有数据..
* */
public abstract long deleteAll(); /*
* 更新数据..
* */
public abstract long update(T entity); /*
* 根据数据列表更新数据..
* */
public abstract long updateList(List<T> entityList); /*
* 根据ID获取一行数据..
* */
public abstract T queryOne(int id); /*
* 执行SQL查询语句..
* class<T> 返回对象类型..
* */
public abstract List<T> rawQuery(String sql,String[] selectionArgs,Class<T> clazz); /*
* 查询列表..
* */
public abstract List<T> queryList(); /*
* 根据多种限制条件进行查询..
* */
public abstract List<T> queryList(String[] columns,String selections,String[] selectionArgs,String groupBy,String having,String orderby,String limit); /*
* 根据where条件进行查询..
* */
public abstract List<T> queryList(String selection,String selectionArgs); /*
* 检查数据是否存在..
* */
public abstract boolean isExist(String sql,String[] selectionArgs); /*
* 根据条件执行查询结果..将数据封装在map中..
* */
public List<Map<String, String>>queryMapList(String sql,String selectionArgs); /*
* 返回查询结果条数..
* */
public int queryCount(String sql,String[] selectionArgs); /*
* 封装执行sql代码..
* */
public void execSql(String sql, Object[] selectionArgs);
}

  这就是一个DAO父类..内部提供了众多的抽象方法..那么有了抽象的方法..自然要有实现的子类..并且这个抽象的DAO接口层是不提供类型的..使用泛型的方式,那么为什么直接使用泛型呢?为什么不直接定义一个接口,后面还需要加上泛型..其实目的就是为了实现良好的扩展性..那么这个良好扩展的体现就是通过使用泛型来完成的...

  比如说我们把上面的类仅仅定义成一个抽象类..

public interface DBDao{...封装了许多抽象函数...}

  那么只要我们想要进行数据库操作的时候,我们就需要implements这个接口...那么如果一个数据库中存在了多个表,那么就需要多个子类去implements这个抽象接口..那么这多个子类中的方法我们还是需要自己去人为去书写..这样就会导致每implements一次DBDao..我们都需要对内部的方法进行重写..这样显然是给我们自己去找麻烦..何必不再向上抽取呢?向上抽取目的就是为了减少这样的操作..避免一次次的重写..那么向上抽取就需要使用泛型了..

public interface DBDao<T> {..抽闲函数..}

  我们同样使用一个泛型类进行实现..实现的过程需要使用到Java的注解和Java强大的反射机制..这里原理我们先不说..一会下面会有相关的解释..那么实现类就这样定义..

public class AbDBDaoImpl<T> extends AbBasicDBDao implements AbDBDao<T>{..实现的过程..}

  这里实现的过程仍然以泛型的方式去实现...使用泛型的好处就是..无论我们传递的是什么类型..我们通过反射机制就能够获取传递来的实体类型从而去实例化对象..通过使用注解的方式我们就能够获取实体类型中的相关属性..有了实体对象以及实体对应的属性...那么就可以对数据表进行操作了...也就是说无论是一个表还是多个表的操作..我们只需要重写一次父类DAO的方法..在进行表操作的时候..我们只需要传递数据实体对象就可以了...或许还有点抽象..那么就来个实例..比如说上面的DBDAO<T>和DBDaoImpl<T>都已经写好了..那么我们就可以直接调用

private UserInsideDao userDao = new UserInsideDao(MainActivity.this);//实例化对象..
userDao.startReadableDatabase(false);//获取数据库..
userDao.queryList(null,null,null,null,null,"create_time desc limit "+String.valueOf(pageSize)+" offset "+0,null);//直接可以执行查询函数..

  UserInsideDao其实就是一个服务层..使用它来传递我们想要初始化的数据表..以及获取数据库辅助类...这里的UserInsideDao继承了实现Dao抽象层的子层..那么UserInsideDao就可以去调用实现层的构造函数..将想初始化的表传递过去..那么这些表就会根据解析注解的方式对表进行相关的创建..

public class UserInsideDao extends AbDBDaoImpl<LocalUser> {
public UserInsideDao(Context context) {
super(new DBInsideHelper(context),LocalUser.class);
}
}

  这里的DBInsideHelper才是真正对数据库进行操作的类...DBInsideHelper继承了AbDBHelper..获取数据库辅助类的同时..同时把LocalUser实体传递给AbDBDaoImpl..这就表示当前我需要对LocalUser表进行相关操作了..以下是DBInsideHelper的实现...

public class DBInsideHelper extends AbDBHelper {
// 数据库名
private static final String DBNAME = "andbasedemo.db"; // 当前数据库的版本
private static final int DBVERSION = 1;
// 要初始化的表
private static final Class<?>[] clazz = { User.class,LocalUser.class,Stock.class,ChatMsg.class}; public DBInsideHelper(Context context) {
super(context, DBNAME, null, DBVERSION, clazz);
} }

  总之最后会去调用AbDBDaoImpl中的构造函数..从而完成对数据表的一些初始化操作...然后就可以在主类中直接去调用相关函数来完成对数据库的基本操作了...

2.数据库映射关系..

  数据库映射关系..说起来有点抽象..实际理解起来还是非常的简答的...数据库映射关系无非三种..一对一,一对多,多对多..这三种映射关系..映射关系其实就是实体和实体之间的实在关系..什么是一对一,一对多,多对多..拿一个简单的例子来说...

  比如说我们有三个数据表:

学生表(学号,姓名,性别,年龄)    不难看出学生ID是主键..
课程表(课程号,课程名称) 这里课程ID是主键..
成绩表(学号,课程号,成绩) 这里的主键由学生ID和课程ID共同构成..

  一对一:比如说我们想要查询学生表ID为1,课程号ID为1的成绩..那么这行成绩只能对应学生表和课程表的一行数据..这就是一对一..也就是说表与表之间的数据相互对应只能是一行..

  一对多:查询学号为1的学生的成绩..这样在成绩表中会对应多条数据..但成绩表中的多条数据在学生表中只会对应一条..这个关系数据一对多..

  多对多:查询所有学生的成绩..那么数据表中多条数据对应多行...

  数据库映射关系如果真的理解过来还是比较容易的..千万不要理解反了..就拿查询一个班级里学号为1的学生...这个映射关系是一对一的关系...千万不要理解成一对多的关系...不要以为经过了多个层次就表示是一对多..这样去理解反而理解错了..这个关系是实体与实体之间的一对一,一对多,多对多..而不是经过了几层...这里还是需要注意的...

3.使用泛型+反射+注解书写通用DAO...

  其实通用DAO最难实现的部分是使用反射去解析注解..也就是AbDBDaoImpl中方法的书写..这部分还是比较费劲的...

  通用DAO就拿这个例子来说吧...方法就一个..我就不多列举了..玩过JavaEE的对这方面还是非常清楚的...Hibernate DAO和SpringJDBC DAO都是以这种方式来对数据库进行操作的..不过传递数据对象的时候..类需要进行序列化操作..由于自己对SSH并不是很了解..就不在这班门弄斧了...还是说如何去实现的...

public interface AbDBDao<T> {

     //获取数据库辅助类..
public SQLiteOpenHelper getDbHelper();
//查询数据,,以列表的形式进行展示..
public abstract List<T> queryList(String[] columns, String selection,String[] selectionArgs, String groupBy, String having,String orderBy, String limit);
}

  实现过程就需要AbDBDaoImpl类去实现了...

public class AbDBDaoImpl<T> extends AbBasicDBDao implements AbDBDao<T> {

    /** The tag. */
private String TAG = "AbDBDaoImpl"; /** The db helper. */
private SQLiteOpenHelper dbHelper; /**锁对象*/
private final ReentrantLock lock = new ReentrantLock(); /** The table name. */
private String tableName; /** The id column. */
private String idColumn; /** The clazz. */
private Class<T> clazz; /** The all fields. */
private List<Field> allFields; /** The Constant METHOD_INSERT. */
private static final int METHOD_INSERT = 0; /** The Constant METHOD_UPDATE. */
private static final int METHOD_UPDATE = 1; /** The Constant TYPE_NOT_INCREMENT. */
private static final int TYPE_NOT_INCREMENT = 0; /** The Constant TYPE_INCREMENT. */
private static final int TYPE_INCREMENT = 1; /**这个Dao的数据库对象*/
private SQLiteDatabase db = null; /**
* 用一个对象实体初始化这个数据库操作实现类.
*
* @param dbHelper 数据库操作实现类
* @param clazz 映射对象实体
*/
public AbDBDaoImpl(SQLiteOpenHelper dbHelper, Class<T> clazz) {
this.dbHelper = dbHelper;
if (clazz == null) {
this.clazz = ((Class<T>) ((java.lang.reflect.ParameterizedType) super
.getClass().getGenericSuperclass())
.getActualTypeArguments()[0]); //这里是获取传递过来的实体类型,比如说LocalUser.class...
} else {
this.clazz = clazz; //这里是直接获取...
} if (this.clazz.isAnnotationPresent(Table.class)) { //如果存在声明的注解...这个注解数据表名属性..
Table table = (Table) this.clazz.getAnnotation(Table.class);
this.tableName = table.name(); //获取数据表名..
} // 加载所有字段
this.allFields = AbTableHelper.joinFields(this.clazz.getDeclaredFields(),
this.clazz.getSuperclass().getDeclaredFields()); // 找到主键
for (Field field : this.allFields) {
if (field.isAnnotationPresent(Id.class)) { //这里都是对注解的解析...这里的注解信息为ID...
Column column = (Column) field.getAnnotation(Column.class);
this.idColumn = column.name();
break;
}
} Log.d(TAG, "clazz:" + this.clazz + " tableName:" + this.tableName
+ " idColumn:" + this.idColumn);
} /**
* 初始化这个数据库操作实现类.
*
* @param dbHelper 数据库操作实现类
*/
public AbDBDaoImpl(SQLiteOpenHelper dbHelper) {
this(dbHelper, null);
} /**
* 描述:TODO.
*
* @return the db helper
* @see com.ab.db.orm.dao.AbDBDao#getDbHelper()
*/
@Override
public SQLiteOpenHelper getDbHelper() {
return dbHelper;
}
@Override
public List<T> queryList(String[] columns, String selection,
String[] selectionArgs, String groupBy, String having,
String orderBy, String limit) { List<T> list = new ArrayList<T>();
Cursor cursor = null;
try {
lock.lock(); //获取锁..避免多次操作导致问题发生...
Log.d(TAG, "[queryList] from"+this.tableName+" where "+selection+"("+selectionArgs+")"+" group by "+groupBy+" having "+having+" order by "+orderBy+" limit "+limit);
cursor = db.query(this.tableName, columns, selection,
selectionArgs, groupBy, having, orderBy, limit); //执行查询函数... getListFromCursor(this.clazz,list, cursor); closeCursor(cursor); //获取关联域的操作类型和关系类型
String foreignKey = null;
String type = null;
String action = null;
//需要判断是否有关联表
for (Field relationsField : allFields) {
if (!relationsField.isAnnotationPresent(Relations.class)) {
continue;
} Relations relations = (Relations) relationsField.getAnnotation(Relations.class);
//获取外键列名
foreignKey = relations.foreignKey();
//关联类型
type = relations.type();
//操作类型
action = relations.action();
//设置可访问
relationsField.setAccessible(true); if(!(action.indexOf(ActionType.query)!=-1)){
return list;
} //得到关联表的表名查询
for(T entity:list){ if(RelationsType.one2one.equals(type)){
//一对一关系
//获取这个实体的表名
String relationsTableName = "";
if (relationsField.getType().isAnnotationPresent(Table.class)) {
Table table = (Table) relationsField.getType().getAnnotation(Table.class);
relationsTableName = table.name();
} List<T> relationsList = new ArrayList<T>();
Field[] relationsEntityFields = relationsField.getType().getDeclaredFields();
for (Field relationsEntityField : relationsEntityFields) { //这里涉及到对主表进行再次遍历..这里主要原因是受到了外键的影响...
Column relationsEntityColumn = (Column) relationsEntityField.getAnnotation(Column.class);
//获取外键的值作为关联表的查询条件
if (relationsEntityColumn.name().equals(foreignKey)) { //主表的用于关联表的foreignKey值
String value = "-1";
for (Field entityField : allFields) {
//设置可访问
entityField.setAccessible(true);
Column entityForeignKeyColumn = (Column) entityField.getAnnotation(Column.class);
if(entityForeignKeyColumn==null){
continue;
}
if (entityForeignKeyColumn.name().equals(foreignKey)) {
value = String.valueOf(entityField.get(entity));
break;
}
}
//查询数据设置给这个域
cursor = db.query(relationsTableName, null, foreignKey+" = ?",new String[]{value}, null, null, null, null);
getListFromCursor(relationsField.getType(),relationsList, cursor);
if(relationsList.size()>0){
//获取关联表的对象设置值
relationsField.set(entity, relationsList.get(0));
} break;
}
} }else if(RelationsType.one2many.equals(type) || RelationsType.many2many.equals(type)){
//一对多关系 //得到泛型里的class类型对象
Class listEntityClazz = null;
Class<?> fieldClass = relationsField.getType();
if(fieldClass.isAssignableFrom(List.class)){
Type fc = relationsField.getGenericType();
if(fc == null) continue;
if(fc instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) fc;
listEntityClazz = (Class)pt.getActualTypeArguments()[0];
} } if(listEntityClazz==null){
Log.e(TAG, "对象模型需要设置List的泛型");
return null;
} //得到表名
String relationsTableName = "";
if (listEntityClazz.isAnnotationPresent(Table.class)) {
Table table = (Table) listEntityClazz.getAnnotation(Table.class);
relationsTableName = table.name();
} List<T> relationsList = new ArrayList<T>();
Field[] relationsEntityFields = listEntityClazz.getDeclaredFields();
for (Field relationsEntityField : relationsEntityFields) {
Column relationsEntityColumn = (Column) relationsEntityField.getAnnotation(Column.class);
//获取外键的值作为关联表的查询条件
if (relationsEntityColumn.name().equals(foreignKey)) { //主表的用于关联表的foreignKey值
String value = "-1";
for (Field entityField : allFields) {
//设置可访问
entityField.setAccessible(true);
Column entityForeignKeyColumn = (Column) entityField.getAnnotation(Column.class);
if (entityForeignKeyColumn.name().equals(foreignKey)) {
value = String.valueOf(entityField.get(entity));
break;
}
}
//查询数据设置给这个域
cursor = db.query(relationsTableName, null, foreignKey+" = ?",new String[]{value}, null, null, null, null);
getListFromCursor(listEntityClazz,relationsList, cursor);
if(relationsList.size()>0){
//获取关联表的对象设置值
relationsField.set(entity, relationsList);
} break;
}
} }
}
} } catch (Exception e) {
Log.e(this.TAG, "[queryList] from DB Exception");
e.printStackTrace();
} finally {
closeCursor(cursor);
lock.unlock();
} return list;
}
}

  这就是实现的过程..主要是通过使用反射机制+解析注解的方式来实现的...这里涉及到了一个关联表的事情...就拿刚才的那三个表来说吧...我想要查询学生号为1,课程号为1的成绩..这样成绩表就涉及到了两个表...因此还需要对关联表进行相关的操作..因此需要对所有的关联表进行遍历..然后进行相关的操作..我们可以看到这里又涉及到了主表的再次遍历...原因取决于外键的影响...

  简单的说一下外键..我们知道成绩表中主键是学生ID和课程ID的组合...但是学生ID又在学生列表中是主键..因此学生ID在成绩表中被称为成绩表关于学生表的外键...同样课程ID是成绩表关于课程表的外键...因为成绩表中的主键是复合型的..因此需要对外键进行一一获取..外键的获取通过对主表的遍历...最后把所有获取的外键进行保存..用来进行联合查询..这也就是那个步骤的目的...

  这样就简单的书写了一个通用的DAO..虽然只有一个方法..其他方法的实现我们可以自己去重写...

4.使用AndBase中提供的DAO来完成对数据库的一系列操作...

  在AndBase中...源码就是通过对上面的封装给我们直接提供了一个通用的DAO接口层...我们都不需要去进行实现..直接就可以完成方法的调度过程...如果想要重写更多的方法..请继承实现类AbDBDaoImpl,然后在子类中去书写更多的方法...

  private UserInsideDao userDao = null
//初始化数据库操作实现类
userDao = new UserInsideDao(DBInsideSampleActivity.this); //(1)获取数据库
userDao.startReadableDatabase(false);
//(2)执行查询
userList = userDao.queryList(null, null, null, null, null, "create_time desc limit "+String.valueOf(pageSize)+ " offset " +0, null);
totalCount = userDao.queryCount(null, null);
//(3)关闭数据库
userDao.closeDatabase(false);

  使用AndBase直接操作数据库...非常的简单...UserInsideDao类..这里表示我要对LocalUser实体对象进行操作...也就是对LocalUser表进行操作..剩下所有函数的调用都是对这个表进行相关的操作...

package com.andbase.demo.dao;

import android.content.Context;

import com.ab.db.orm.dao.AbDBDaoImpl;
import com.andbase.db.DBInsideHelper;
import com.andbase.demo.model.LocalUser; public class UserInsideDao extends AbDBDaoImpl<LocalUser> {
public UserInsideDao(Context context) {
super(new DBInsideHelper(context),LocalUser.class);
}
}

  DBInsideHelper类...获取数据库辅助类的过程...初始化所有的数据表...

package com.andbase.db;

import android.content.Context;

import com.ab.db.orm.AbDBHelper;
import com.andbase.demo.model.LocalUser;
import com.andbase.demo.model.Stock;
import com.andbase.friend.ChatMsg;
import com.andbase.model.User; public class DBInsideHelper extends AbDBHelper {
// 数据库名
private static final String DBNAME = "andbasedemo.db"; // 当前数据库的版本
private static final int DBVERSION = 1;
// 要初始化的表
private static final Class<?>[] clazz = {LocalUser}; public DBInsideHelper(Context context) {
super(context, DBNAME, null, DBVERSION, clazz);
} }

  最后贴一下LocalUser类...传递的Class仅仅是一个LocalUser表..一般会传递多个表的..传递多个表就需要定义多个实体类就行了...

package com.andbase.demo.model;

import java.util.List;

import com.ab.db.orm.annotation.Column;
import com.ab.db.orm.annotation.Id;
import com.ab.db.orm.annotation.Relations;
import com.ab.db.orm.annotation.Table;
@Table(name = "local_user")
public class LocalUser { // ID @Id主键,int类型,数据库建表时此字段会设为自增长
@Id
@Column(name = "_id")
private int _id; @Column(name = "u_id")
private String uId; // 登录用户名 length=20数据字段的长度是20
@Column(name = "name", length = 20)
private String name; // 用户密码
@Column(name = "password")
private String password; // 年龄一般是数值,用type = "INTEGER"规范一下.
@Column(name = "age", type = "INTEGER")
private int age; // 创建时间
@Column(name = "create_time")
private String createTime; // 包含实体的存储,指定外键
@Relations(name="stock",type="one2one",foreignKey = "u_id",action="query_insert")
private Stock stock; // 包含List的存储,指定外键
@Relations(name="stocks",type="one2many",foreignKey = "u_id",action="query_insert")
private List<Stock> stocks; // 有些字段您可能不希望保存到数据库中,不用@Column注释就不会映射到数据库.
private String remark; public int get_id() {
return _id;
} public void set_id(int _id) {
this._id = _id;
} public String getuId() {
return uId;
} public void setuId(String uId) {
this.uId = uId;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getCreateTime() {
return createTime;
} public void setCreateTime(String createTime) {
this.createTime = createTime;
} public List<Stock> getStocks() {
return stocks;
} public void setStocks(List<Stock> stocks) {
this.stocks = stocks;
} public String getRemark() {
return remark;
} public void setRemark(String remark) {
this.remark = remark;
} public Stock getStock() {
return stock;
} public void setStock(Stock stock) {
this.stock = stock;
} }

Android 学习笔记之AndBase框架学习(五) 数据库ORM..注解,数据库对象映射...的更多相关文章

  1. Android 学习笔记之AndBase框架学习(三) 使用封装好的函数完成Http请求..

    PS:踏踏实实走好每一步... 学习内容: 1.使用AndBase框架实现无参Http Get请求... 2.使用AndBase框架实现有参Http Post请求... 3.使用AndBase框架实现 ...

  2. Android 学习笔记之AndBase框架学习(二) 使用封装好的进度框,Toast框,弹出框,确认框...

    PS:渐渐明白,在实验室呆三年都不如在企业呆一年... 学习内容: 1.使用AbActivity内部封装的方法实现进度框,Toast框,弹出框,确认框...   AndBase中AbActivity封 ...

  3. Android 学习笔记之AndBase框架学习(一) 实现多功能标题栏

    PS:Volley框架终于通过看源码的方式完成了所有的学习..开始学习AndBase...AndBase的源码实在是多的离谱...因此就不对所有的源码进行分析了... 学习内容: 1.使用AndBas ...

  4. Android 学习笔记之AndBase框架学习(六) PullToRefrech 下拉刷新的实现

    PS:Struggle for a better future 学习内容: 1.PullToRefrech下拉刷新的实现...   不得不说AndBase这个开源框架确实是非常的强大..把大部分的东西 ...

  5. Android 学习笔记之AndBase框架学习(七) SlidingMenu滑动菜单的实现

    PS:努力的往前飞..再累也无所谓.. 学习内容: 1.使用SlidingMenu实现滑动菜单..   SlidingMenu滑动菜单..滑动菜单在绝大多数app中也是存在的..非常的实用..Gith ...

  6. Android 学习笔记之AndBase框架学习(四) 使用封装好的函数实现单,多线程任务

    PS:Force Is Meaningless Without Skill 学习内容: 1.使用AndBase实现单线程任务... 2.使用AndBase实现多线程任务...   AndBase内部封 ...

  7. Hadoop学习笔记—18.Sqoop框架学习

    一.Sqoop基础:连接关系型数据库与Hadoop的桥梁 1.1 Sqoop的基本概念 Hadoop正成为企业用于大数据分析的最热门选择,但想将你的数据移植过去并不容易.Apache Sqoop正在加 ...

  8. Hadoop学习笔记—15.HBase框架学习(基础实践篇)

    一.HBase的安装配置 1.1 伪分布模式安装 伪分布模式安装即在一台计算机上部署HBase的各个角色,HMaster.HRegionServer以及ZooKeeper都在一台计算机上来模拟. 首先 ...

  9. Hadoop学习笔记—16.Pig框架学习

    一.关于Pig:别以为猪不能干活 1.1 Pig的简介 Pig是一个基于Hadoop的大规模数据分析平台,它提供的SQL-LIKE语言叫Pig Latin,该语言的编译器会把类SQL的数据分析请求转换 ...

随机推荐

  1. RabbitMQ的工作队列和路由

    工作队列:Working Queue   工作队列这个概念与简单的发送/接收消息的区别就是:接收方接收到消息后,可能需要花费更长的时间来处理消息,这个过程就叫一个Work/Task.   几个概念 分 ...

  2. Android布局优化之过度绘制

    如果一个布局十分复杂,那么就需要来排查是否出现了过度绘制,如果出现了,那么很可能会造成刷新率下降,造成卡顿的现象.那么什么是过度绘制呢?过度绘制就是在同一个区域中叠加了多个控件.这就像小时候我们画画, ...

  3. 支付宝Wap支付你了解多少?

    上几篇文章详细介绍了支付宝APP支付.微信APP支付 此文章来介绍下支付宝Wap支付(也叫作手机网站支付) 目录 1.创建应用并获取APPID 2.配置应用环境 3.配置沙箱环境 4.服务端实现(Ma ...

  4. vim 多行注释消除注释,多行删除

    进入可视化模式: Ctrl+v 继续进入编辑模式: shift+i 注释: shift+# 注释生效: ESC 取消注释 d 删除 选中全部字符块区域,使用方向键上下右: 然后,按一下d

  5. ASP.NET MVC中的模型装配 封装方法 非常好用

    下面说一下 我们知道在asp.net mvc中 视图可以绑定一个实体模型 然后我们三层架构中也有一个model模型 但是这两个很多时候却是不一样的对象来的 就拿微软的官方mvc例子来说明 微软的视图实 ...

  6. 导出websphere内存镜像

    1.      将脚本放致profiles\appservername\bin下 2.      查看一下soap host(在控制台port中能够看到) 3.      运行例如以下命令:./wsa ...

  7. 【转】20个Cydia常见错误问题解决方法汇总

    对于已经越狱的用户来说,经常会使用Cydia来安装一些酷炫或实用插件,但是有时候它总是会出现一些问题,以下收集了在Cydia经常遇到的问题,供大家参考: 一.主屏幕没有 Cydia 图标 1.设备需已 ...

  8. 正则指引-量词demo

    class Program { static void Main(string[] args) { string str = "1\"3"; var re1 = Rege ...

  9. 菜鸟学JS(四)——javascript为按钮注册回车事件(设置默认按钮)

    不得不说,在JS方面,自己真的是个不折不扣的菜鸟.对于JS以及一些JS框架如JQuery等JS框架,自己也只是处在简单应用的阶段,当然自己也在不断的学习当中,希望将来能跟大家分享更多JS方面的心得.今 ...

  10. Web Design - The Viewport

    What is The Viewport? The viewport is the user's visible area of a web page. The viewport varies wit ...