前言

  对于一个应用程序而言,数据持久化是必不可少的,Android程序也不例外。这篇博客将介绍Android中关于SQLite的使用,SQLite是一种嵌入式的数据库引擎,专门适用于资源有限的设备上进行适量的数据存储,而Android就全面支持标准的SQLite数据库。在本片博客中,将说明SQLite数据库的创建以及维护,还有使用SQLite执行CRUD的两种方式,以及SQLite中事务的使用,最后都会使用示例讲解博客中所提到的概念性的内容。

SQLite

  Android对SQLite数据库,提供了完全的支持,而所有创建的SQLite数据库,仅限于当前应用访问,如果其他应用需要访问,则必须提供的Content Provider的支持,并且SQLite数据库会随着Android应用的卸载而被删除。SQLite是一个嵌入式的数据库引擎,最后是以文件的形式保存数据的。从本质上来看,SQLite的操作方式只是一种更为便捷的文件操作,当应用程序创建或打开一个SQLite数据库时,其实只是打开一个文件准备读写。因为SQLite仅适用于资源有限的小型设备,所以本身就不应该把大量数据存储在设备的SQLite数据库里,SQLite只适合存储一些小型的数据。

  为了使SQLite和其他数据库间的兼容性最大化,SQLite支持对列上类型进行“类型近似”,列的类型近似指的是存储在列上的数据进行推荐类型存储。所以虽然SQLite内部只支持NULL、INTEGER、REAL(浮点书)、TEXT(文本)和BLOB(大二进制对象)这五种数据类型,但实际上SQLite完全可以接受varchar(n)、char(n)、decimal(p,s)、date等类型数据,只不过SQLite会在运算或保存时将它们转换为上面五种数据类型中相应的类型。大多数数据库的引擎都是使用静态的、强类型的数据类型,数据的类型是由它的容器决定的,这个容器是指被存放的特定列。而SQLite使用的是动态类型,在SQLite中,值的数据类型跟值本身相关,而不是与它的容器相关,所以SQLite允许把各种类型的数据保存到任何类型字段中,开发者可以不用关心声明该字段说使用的数据类型。但是有一种情况例外,定义为INTEGER PRIMARY KEY的字段只能存储64位整数,当向这种字段保存除整数意外的其他类型的数据时,SQLite会产生错误。

SQLite数据库创建与维护

  从官方文档上了解到,在Android项目中,创建SQLite数据库推荐继承SQLiteOpenHelper类,然后重写其中的onCreate()方法,在onCreate()方法中,对执行数据库创建的SQL语句。而SQLiteOpenHelper不仅仅用于SQLite数据的创建,还可以对其进行维护,以及获得SQLiteDatabase这个数据库操作对象。

  SQLiteOpenHelper提供了两个构造器,用于传递当前上下文对象以及SQLite数据库版本信息,在SQLiteOpenHelper的继承类的构造函数中,会调用它,构造器的签名如下:

  • SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version).
  • SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactroy factory,int version,DatabaseErrorHandler errorHandler).

  上面的构造函数中,都是用于创建一个SQLite数据库,context为一个当前应用的上下文对象;name是数据库名称;factory是一个允许子类在查询时使用的游标,一般不用传Null;version是数据库版本号;errorHandler是一个接口,传递当数据库错误的时候,执行的补救方法。

  在SQLiteOpenHelper中,可以进行SQLite数据库的创建、维护、日志以及获取可读写的数据库对象,通过下面几个常用方法得到支持:

  • String getDatabaseName():获取数据库名。
  • SQLiteDatabase getReadableDatabase():创建或者打开一个可读的数据库对象。
  • SQLiteDatabase getWritableDatabase():创建或者打开一个可读/写的数据库对象。
  • abstract void onCreate(SQLiteDatabase db):当第一次调用SQLiteOpenHelper的时候执行,之后再次调用将不再执行,一般用于完成数据库初始化的工作。
  • void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion):当数据库版本号发生向上更新时,被执行。
  • void onDowngrade(SQLiteDatabase db,int oldVersion,int newVersion):当数据库版本号发生向下更新时,被执行。

  下面提供一个简单的SQLiteOpenHelper的继承类代码,用于创建数据库以及表结构:

 package com.example.sqlitedbdemo.db;

 import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; public class DbOpenHelper extends SQLiteOpenHelper {
private static String name = "mydb.db";
private static int version = 1; public DbOpenHelper(Context context) {
super(context, name, null, version);
} @Override
public void onCreate(SQLiteDatabase db) {
// 只能支持基本数据类型
String sql = "create table person(id integer primary key autoincrement,name varchar(64),address varchar(64))";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
String sql="alter table person add sex varchar(8)";
db.execSQL(sql);
}
}

  Tips:当创建好SQLite数据库的之后,可以在/data/data/<package name>/databases目录下找到SQLite数据库文件。

执行CRUD操作

  当使用SQLiteOpenHelper的getReadableDatabase()或者getWritableDatabase()方法获取到SQLiteDatabase对象,就可以对这个数据库进行操作了。

  对于熟悉SQL语句的开发者而言,其实只需要使用两个方法,即可执行所有CRUD操作,以下方法提供多个重载方法:

  • void execSQL():通过SQL语句执行一条非查询语句。
  • Cursor rawQuery():通过SQL语句执行一条查询语句。

  下面以一个示例讲解一下单纯使用SQL语句实现CRUD操作:

  接口代码:

 package com.examle.sqlitedbdemo.service;

 import java.util.List;
import java.util.Map; public interface PersonService { public boolean addPerson(Object[] params);
public boolean deletePerson(Object[] params);
public boolean updatePerson(Object[] params);
public Map<String, String> viewPerson(String[] selectionArgs);
public List<Map<String, String>> listPersonMaps(String[] selectionArgs);
}

  接口的实现代码:

 package com.examle.sqlitedbdemo.dao;

 import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import com.examle.sqlitedbdemo.service.PersonService;
import com.example.sqlitedbdemo.db.DbOpenHelper; public class PersonDao implements PersonService {
private DbOpenHelper helper = null; public PersonDao(Context context) {
helper = new DbOpenHelper(context);
} @Override
public boolean addPerson(Object[] params) {
boolean flag = false;
SQLiteDatabase database = null;
try {
// insert一条数据
String sql = "insert into person(name,address,sex) values(?,?,?)";
database = helper.getWritableDatabase();
// 执行SQL
database.execSQL(sql, params);
flag = true;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (database != null) {
// finally中关闭数据库
database.close();
}
}
return flag;
} @Override
public boolean deletePerson(Object[] params) {
boolean flag = false;
SQLiteDatabase database = null;
try {
// 删除一条数据
String sql = "delete from person where id=?";
database = helper.getWritableDatabase();
database.execSQL(sql, params);
flag = true;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (database != null) {
database.close();
}
}
return flag;
} @Override
public boolean updatePerson(Object[] params) {
boolean flag = false;
SQLiteDatabase database = null;
try {
// 更新一条数据
String sql = "update person set name=?,address=?,sex=? where id=?";
database = helper.getWritableDatabase();
// 执行SQL
database.execSQL(sql, params);
flag = true;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (database != null) {
database.close();
}
}
return flag;
} @Override
public Map<String, String> viewPerson(String[] selectionArgs) {
Map<String, String> map = new HashMap<String, String>();
SQLiteDatabase database = null;
try {
// 查询单条记录
String sql = "select * from person where id=?";
// 以只读的形式打开数据库
database = helper.getReadableDatabase();
// 执行SQL语句,返回一个游标
Cursor cursor = database.rawQuery(sql, selectionArgs); int colums = cursor.getColumnCount();
while (cursor.moveToNext()) {
for (int i = 0; i < colums; i++) {
String cols_name = cursor.getColumnName(i);
String cols_value = cursor.getString(cursor
.getColumnIndex(cols_name));
if (cols_value == null) {
cols_value = "";
}
map.put(cols_name, cols_value);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (database != null) {
database.close();
}
}
return map;
} @Override
public List<Map<String, String>> listPersonMaps(String[] selectionArgs) {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
String sql = "select * from person";
SQLiteDatabase database = null;
try {
database = helper.getReadableDatabase();
Cursor cursor = database.rawQuery(sql, selectionArgs);
int colums = cursor.getColumnCount();
while (cursor.moveToNext()) {
Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i < colums; i++) {
String cols_name = cursor.getColumnName(i);
String cols_value = cursor.getString(cursor
.getColumnIndex(cols_name));
if (cols_value == null) {
cols_value = "";
}
map.put(cols_name, cols_value);
}
list.add(map);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (database != null) {
database.close();
}
}
return list;
}
}

   再写一个测试类测试这个数据操作类是否有效,Android下JUnit的配置参见另外一篇博客:Android--JUnit单元测试

 package com.example.sqlitedbdemo.db;

 import java.util.List;
import java.util.Map; import com.examle.sqlitedbdemo.dao.PersonDao;
import com.examle.sqlitedbdemo.service.PersonService; import android.test.AndroidTestCase;
import android.util.Log; public class TestDb extends AndroidTestCase {
private final String TAG = "main"; public TestDb() {
// TODO Auto-generated constructor stub
} public void createDB() {
DbOpenHelper helper = new DbOpenHelper(getContext());
helper.getWritableDatabase();
} public void insertDb() {
PersonService service = new PersonDao(getContext());
Object[] params1 = { "张龙", "beijing", "male" };
boolean flag = service.addPerson(params1);
Object[] params2 = { "赵虎", "shanghai", "male" };
flag = flag&&service.addPerson(params2);
Object[] params3 = { "王朝", "HK", "male" };
flag = flag&&service.addPerson(params3);
Object[] params4 = { "马汉", "beijing", "female" };
flag = flag&&service.addPerson(params4);
Log.i(TAG, "-----插入数据----->>" + flag);
} public void deleteDb() {
PersonService service = new PersonDao(getContext());
Object[] params = { 1 };
boolean flag = service.deletePerson(params);
Log.i(TAG, "-----删除数据----->>" + flag);
} public void updateDb() {
PersonService service=new PersonDao(getContext());
Object[] params = { "张三", "上海", "男","2" };
boolean flag=service.updatePerson(params);
Log.i(TAG, "---------->>" + flag);
} public void getDb(){
PersonService service=new PersonDao(getContext());
Map<String, String> map = service.viewPerson(new String[]{"2"});
Log.i(TAG, "---------->>" + map.toString());
} public void listDb() {
PersonService service = new PersonDao(getContext());
List<Map<String, String>> list = service.listPersonMaps(null);
Log.i(TAG, "---------->>" + list.toString());
}
}

  insertDB()后,如果是在模拟器上调试,可以使用FIle Explorer工具导出mydb.db文件,使用SQLite Expert Professional(这是一个SQLite的管理软件,博客最后提供下载地址),打开数据库:

  执行deleteDb()删除第一条数据:

  执行updateDb()更新第二条数据:

  执行getDb(),查询第二条数据,执行listDb(),查询全部数据,查看日志输出:

  

  而如果是从事Android开发,还有必要了解另外一种操作SQLite的方式,使用SQLiteDatabase所提供的方法实现CRUD操作。主要有以下几个方法:

  • long insert(String table ,String nullColumnHack,ContentValues values):插入一条数据。
  • int delete(String table ,String whereCaluse,String[] whereArgs):根据条件,删除数据。
  • int updata(String table,ContentValues values,String whereCaluse,String[] whereArgs):根据条件,更新数据
  • Cursor query(...):根据条件,查询数据。提供多种重载方法,主要查询不同的条件。

  下面以一个示例程序讲解一下使用SQLiteDatabase所提供的方法实现CRUD操作:

  接口代码:

 package com.examle.sqlitedbdemo.service;

 import java.util.List;
import java.util.Map; import android.content.ContentValues; public interface PersonService2 { public boolean addPerson(ContentValues values); public boolean deletePerson(String whereClause, String[] whereArgs); public boolean updatePerson(ContentValues values, String whereClause,
String[] whereArgs); public Map<String, String> viewPerson(String selection,
String[] selectionArgs); public List<Map<String, String>> listPersonMaps(String selection,
String[] selectionArgs);
}

  实现代码:

 package com.examle.sqlitedbdemo.dao;

 import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import com.examle.sqlitedbdemo.service.PersonService2;
import com.example.sqlitedbdemo.db.DbOpenHelper; public class PersonDao2 implements PersonService2 {
private DbOpenHelper helper = null; public PersonDao2(Context context) {
helper = new DbOpenHelper(context);
} @Override
public boolean addPerson(ContentValues values) {
boolean flag = false;
SQLiteDatabase database = null;
long id = -1;
try {
database = helper.getWritableDatabase();
// 执行insert,返回当前行ID
id = database.insert("person", null, values);
flag = (id != -1 ? true : false);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (database != null) {
database.close();
}
}
return flag;
} @Override
public boolean deletePerson(String whereClause, String[] whereArgs) {
boolean flag = false;
SQLiteDatabase database = null;
int count = 0;
try {
database = helper.getWritableDatabase();
// 执行删除操作,返回影响行数
count = database.delete("person", whereClause, whereArgs);
flag = (count > 0 ? true : false);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (database != null) {
database.close();
}
}
return flag;
} @Override
public boolean updatePerson(ContentValues values, String whereClause,
String[] whereArgs) {
boolean flag = false;
SQLiteDatabase database = null;
int count = 0;
try {
database = helper.getWritableDatabase();
// 执行更新操作,返回影响行数
count = database.update("person", values, whereClause, whereArgs);
flag = (count > 0 ? true : false);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (database != null) {
database.close();
}
}
return flag;
} @Override
public Map<String, String> viewPerson(String selection,
String[] selectionArgs) {
SQLiteDatabase database = null;
Cursor cursor = null;
Map<String, String> map = new HashMap<String, String>();
try {
database = helper.getReadableDatabase();
// 设置查询条件
cursor = database.query(true, "person", null, selection,
selectionArgs, null, null, null, null);
int cols_len = cursor.getColumnCount();
while (cursor.moveToNext()) {
for (int i = 0; i < cols_len; i++) {
String cols_key = cursor.getColumnName(i);
String cols_value = cursor.getString(cursor
.getColumnIndex(cols_key));
if (cols_value == null) {
cols_value = "";
}
map.put(cols_key, cols_value);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
} @Override
public List<Map<String, String>> listPersonMaps(String selection,
String[] selectionArgs) {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
SQLiteDatabase database = null;
Cursor cursor = null;
try {
database = helper.getReadableDatabase();
cursor = database.query(false, "person", null, selection,
selectionArgs, null, null, null, null);
int cols_len = cursor.getColumnCount();
while (cursor.moveToNext()) {
Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i < cols_len; i++) {
String cols_key = cursor.getColumnName(i);
String cols_value = cursor.getString(cursor
.getColumnIndex(cols_key));
if (cols_value == null) {
cols_value = "";
}
map.put(cols_key, cols_value);
}
list.add(map);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
} }

  最后和上面一下,创建一个测试类来测试这个数据库操作:

 package com.example.sqlitedbdemo.db;

 import java.util.List;
import java.util.Map; import com.examle.sqlitedbdemo.dao.PersonDao2;
import com.examle.sqlitedbdemo.service.PersonService2; import android.content.ContentValues;
import android.test.AndroidTestCase;
import android.util.Log; public class TestDb2 extends AndroidTestCase {
private final String TAG = "main"; public TestDb2() {
// TODO Auto-generated constructor stub
} public void addPerson() {
PersonService2 service2 = new PersonDao2(getContext());
ContentValues values1 = new ContentValues();
values1.put("name", "张龙");
values1.put("address", "beijing");
values1.put("sex", "male");
boolean flag = service2.addPerson(values1);
ContentValues values2 = new ContentValues();
values2.put("name", "赵虎");
values2.put("address", "shanghai");
values2.put("sex", "male");
flag = flag&&service2.addPerson(values2);
ContentValues values3 = new ContentValues();
values3.put("name", "王朝");
values3.put("address", "HK");
values3.put("sex", "male");
flag = flag&&service2.addPerson(values3);
ContentValues values4 = new ContentValues();
values4.put("name", "王朝");
values4.put("address", "HK");
values4.put("sex", "male");
flag = flag&&service2.addPerson(values4);
Log.i(TAG, "----------->>" + flag);
} public void deletePerson() {
PersonService2 service2 = new PersonDao2(getContext());
boolean flag = service2.deletePerson(" id =?", new String[]{"1"});
Log.i(TAG, "----------->>" + flag);
} public void updatePerson(){
PersonService2 service2 = new PersonDao2(getContext());
ContentValues values = new ContentValues();
values.put("name", "张三");
values.put("address", "上海");
values.put("sex", "男");
boolean flag=service2.updatePerson(values, " id=? ", new String[]{"2"});
Log.i(TAG, "----------->>" + flag);
} public void viewPerson(){
PersonService2 service2 = new PersonDao2(getContext());
Map<String, String> map=service2.viewPerson(" id=? ", new String[]{"2"});
Log.i(TAG, "----------->>" + map.toString());
}
public void listPerson(){
PersonService2 service2 = new PersonDao2(getContext());
List<Map<String, String>> list=service2.listPersonMaps(null,null);
Log.i(TAG, "----------->>" + list.toString());
}
}

  实现的功能和上面一样,这里就不展示效果图了,但是因为是上面两种操作数据库的方式是在一个应用中完成的,并且数据一样,执行第二个测试类的时候,需要把之前创建的数据库删除,详情参见源码。

 SQLite事务

  SQLite的事务通过SQLiteDatabase中包含的两个方法对其进行控制:beginTransaction(),开始事务;endTransaction(),结束事务。除此之外,SQLiteDatabase还提供了一个inTransaction()方法用来判断当前上下文是否处于事务环境中。当程序执行endTransaction()方法时将会结束事务,到底是回滚事务还是提交事务取决于SQLiteDatabase是否调用了setTransactionSuccessful()方法来设置事务标志,如果程序事务执行中调用该方法设置了事务成功则提交事务,否则程序将回滚事务。

  示例源码下载

总结

  上面就基本讲解了SQLite在Android中的时候,虽然有两种操作方式,并且直接使用SQL语句操作数据库对于熟悉SQL语句的开发者开说,是非常贴心的,但是在Android中,还是有必要了解一下使用SQLiteDatabase提供的方法操作数据库的方式,因为Android有一个内容提供者(Content Provider),可以使用外部应用访问内部应用的数据,它传递数据的形式,大部分是与SQLiteDatabase内置方法的参数一致的,所以如果同一使用SQLiteDatabase提供的方法操作数据库,是很方便的,无需额外转换SQL语句。

SQLiteExpertSetup下载地址:part1part2

  请支持原创,尊重原创,转载请注明出处。谢谢。

Android--数据持久化之SQLite的更多相关文章

  1. Android数据存储:SQLite

    Android数据存储之SQLite SQLite:Android提供的一个标准的数据库,支持SQL语句.用来处理数据量较大的数据.△ SQLite特征:1.轻量性2.独立性3.隔离性4.跨平台性5. ...

  2. Android数据存储之SQLite数据库

    Android数据存储 之SQLite数据库简介 SQLite的相关知识,并结合Java实现对SQLite数据库的操作. SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎. ...

  3. 【转载】Android数据存储之SQLite

    SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎.它支持大多数的SQL92标准,并且可以在所有主要的操作系统上运行. 在Android中创建的SQLite数据库存储在:/d ...

  4. android数据存储之Sqlite(二)

    SQLite学习笔记 前言:上一章我们介绍了sqlite的一些基本知识以及在dos命令下对sqlite进行的增删改查的操作,这一章我们将在android项目中实际来操作sqlite. 1. SQLit ...

  5. Android数据存储之SQLite的操作

    Android作为一个应用在移动设备上的操作系统,自然也就少不了数据的存储.然而SQLite作为一个轻型的关系型数据库,基于其轻量.跨平台.多语言接口及安全性等诸多因数考虑,因而Android较大的数 ...

  6. Android数据存储之SQLite使用

    SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎.它支持大多数的SQL92标准,并且可以在所有主要的操作系统上运行. 在Android中创建的SQLite数据库存储在:/d ...

  7. Android数据读取之Sqlite数据库操作

    咱们书接上文,继续来说说Android数据读取,这回,我们要讲的是Sqlite数据库的相关操作.以一个实例开始吧: 首先,上图,看看做成后的效果: 大概描述:类似于浏览器的收藏夹,网站名称,网站地址, ...

  8. Android 数据存储之 SQLite数据库存储

    ----------------------------------------SQLite数据库---------------------------------------------- SQLi ...

  9. Android数据存储之Sqlite的介绍及使用

    前言: 本来没有打算整理有关Sqlite数据库文章的,最近一直在研究ContentProvider的使用,所有觉得还是先对Sqlite进行一个简单的回顾,也方便研究学习ContentProvider. ...

  10. android数据存储之Sqlite(一)

    SQLite学习笔记 1. Sqlite简介 SQLite是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入 式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低 ...

随机推荐

  1. mysql第一课,数据库的简单简单操作方法(配图略虐狗)

    mysql -u root -p 并输入密码进入mysql管理界面 show databases; 显示数据库列表 use 数据库名; 进入该数据库 show tables;显示表列表 建立新表 添加 ...

  2. IE9及以下input无背景时,层级混乱问题

    IE9及以下版本:input输入框 background:none;时,层级比input的低的元素会显示在input之上,导致input点击不了. 解决方案: background:url(" ...

  3. 直播流RTMP 知识

    分享直播相关知识点: http://blog.csdn.net/kingroc/article/details/50839994 #!/bin/bash# Order Finish Startup# ...

  4. Spring的声明式事务管理<tx:advice/>

    <tx:advice/> 有关的设置 这一节里将描述通过 <tx:advice/> 标签来指定不同的事务性设置.默认的 <tx:advice/> 设置如下: 事务传 ...

  5. 在windows上安装VTK

    看了很多教程,花了1天半的时间装上了,记录下. 前置条件:我安装了VS2015,用来编译工程. 参考资料 官方:http://www.vtk.org/Wiki/VTK/Building 安装:http ...

  6. Donald Knuth

    看了<李开复给计算机系大学生的建议>这篇文章,让我对Donald Knuth这个人产生了兴趣,他是何许人也?于是便有下文. 引用:(1)练内功.不要只花功夫学习各种流行的编程语言和工具,以 ...

  7. 【adb】执行adb devices 设备offline

    解决办法: 1.执行adb kill-server,在执行adb devices 2.重启手机 ---------------------------------------------------- ...

  8. Beta冲刺 (2/7)

    Part.1 开篇 队名:彳艮彳亍团队 组长博客:戳我进入 作业博客:班级博客本次作业的链接 Part.2 成员汇报 组员1(组长)柯奇豪 过去两天完成了哪些任务 熟悉并编写小程序的自定义控件 展示G ...

  9. Java学习前知识补充

    1  Java  面向对象的编程语言:为了实现人机交互需要语言的过渡(翻译)这时就需要Java虚拟机! 不同系统需要不同的虚拟机 2  学习语言第一件事 搭建环境(运行 Java需要的环境) 在甲骨文 ...

  10. 卷积神经网络中的channel 和filter

    在深度学习的算法学习中,都会提到 channels 这个概念.在一般的深度学习框架的 conv2d 中,如 tensorflow .mxnet,channels 都是必填的一个参数. channels ...