Android 数据储存的方式有很多种 —— SharedPreferences 储存  、 文件储存 、 数据库储存 、 网络储存(储存到后台网络) ,虽然储存方式那么多,但是这些储存方式也有一定的规律可寻:

SharedPreferences :  存储 key value 键值对类型的简单少量的简单数据 (如用户名 ,密码 ,性别,年龄  。。。)

文件 :  没有固定规则的,大量的数据 (如:大量的图片 ,文字 。。。)

数据库 : 有固定规则的,大量数据(如:学生的信息:ID 姓名 年龄 班级 。。。每个学生都有的)

网络 : 。。。

今天这篇文章介绍的是数据储存之数据库储存:参考文献:http://blog.csdn.net/wu_wxc/article/details/49476779

先看下效果图:

使用数据库储存数据有四个方法必须要知道的:增  删  改  查

我们介绍下功能:既然是数据库的储存,功能无非就是增删改查。

1.添加黑名单是: 增。

2.删除黑名单是: 删。

3.长按条目显示弹出框,修改黑名单的拦截方式:改。

4.整个列表的展示:查。

接下来看下代码:

BlackNumDbHelper.java 继承SQLiteOpenHelper

/*** 新建一个数据库的类 db (database) 类要继承squliteOpenhelper* 再建一个操作数据库的工具类(增删改查)* Created by Administrator on 2017/6/29.*/
public class BlackNumDbHelper extends SQLiteOpenHelper {public BlackNumDbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {super(context, name, factory, version);}@Override/*** 第一次运行时,创建数据库,调用此方法*/public void onCreate(SQLiteDatabase db) {//建表:自增长的主键 , 号码 , 拦截模式db.execSQL("create table black_num(_id integer primary key autoincrement, number varchar(20) , mode integer);");}@Override/*** 当数据库版本不一样,升级数据库时,调用此方法*/public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}

用一个操作数据库的工具类 , 一般写成单例模式:BlackDao .java

/*** BlackDao 操作我们数据库的工具类  我们一般写成单例模式* 单例模式 :  在整个应用程序中  不管什么地方(类)  获得的都是同一个对象实例* @author Administrator*/
public class BlackDao {//把数据库创建出来private BlackNumDbHelper dbHelper;//black_num表名private String table_black_num ="black_num";//单例模式//不能让每一个类都能new一个  那样就不是同一个对象了 所以首先构造函数要私有化    以上下文作为参数private BlackDao(Context ctx){//由于数据库只需要调用一次,所以在单例中建出来dbHelper= new BlackNumDbHelper(ctx, "black_num.db", null, 1);}//public static 为静态类型  要调用就要有一个静态的变量    为私有的private static BlackDao instance;//既然BlackDao类是私有的  那么别的类就不能够调用    那么就要提供一个public static(公共的  共享的)的方法//方法名为getInstance 参数为上下文    返回值类型为BlackDao
//要加上一个synchronized(同步的)
//如果同时有好多线程 同时去调用getInstance()方法  就可能会出现一些创建(new)多个BlackDao的现象  所以要加上synchronizedpublic static synchronized BlackDao getInstance(Context ctx){//就可以判断  如果为空 就创建一个, 如果不为空就还用原来的  这样整个应用程序中就只能获的一个实例if(instance == null){instance = new BlackDao(ctx);}return  instance;}//常用方法  增删改查/*** 添加黑名单  至数据库* @param number* @param mode*/public void addBlackNum(String number,int mode){//获得一个可写的数据库的一个引用SQLiteDatabase db = dbHelper.getWritableDatabase();ContentValues values= new ContentValues();values.put("number", number); // KEY 是列名,vlaue 是该列的值values.put("mode", mode);// KEY 是列名,vlaue 是该列的值// 参数一:表名,参数三,是插入的内容// 参数二:只要能保存 values中是有内容的,第二个参数可以忽略db.insert(table_black_num, null, values);}/*** 删除黑名单* @param number*/public void deleteBlackNum(String number){
//      ??dad?asd??sad?asdasdasd?SQLiteDatabase db = dbHelper.getWritableDatabase();//表名  删除的条件db.delete(table_black_num, "number = ?", new String[] {number});}/*** 更新黑名单拦截模式* @param number* @param newMode*/public void updateBlackNumMode(String number,int newMode){SQLiteDatabase db = dbHelper.getWritableDatabase();ContentValues values= new ContentValues();values.put("mode",newMode);db.update(table_black_num, values," number = ?", new String[]{number});}/*** //查找 每一个黑名单都有 号码和模式  先把号码和模式封装一个bean* 获得所有的黑名单* @return*///分页查询 修改public List<BlackNumBean> getBlackNumByPage(int pageIndex, int pageSize){//public List<BlackNumBean> getAllBlackNum(){//创建集合对象List<BlackNumBean> allBlackNum = new ArrayList<BlackNumBean>();SQLiteDatabase db = dbHelper.getReadableDatabase();//Cursor cursor = db.query(table_black_num, null, null, null, null, null, null);//分页查询  修改//Cursor cursor = db.rawQuery("select * from black_num limit "+pageSize+"offent"+(pageIndex * pageSize)+";", null);//order by _id desc 根据_id倒叙排列   使每次添加的黑名单在下次打开时显示上面     同时每页限制20个Cursor cursor = db.rawQuery("select * from black_num order by _id desc limit "+pageSize+" offset "+(pageIndex*pageSize)+";", null);// 返回的 cursor 默认是在第一行的上一行//遍历while(cursor.moveToNext()){// cursor.moveToNext() 向下移动一行,如果有内容,返回trueString number = cursor.getString(cursor.getColumnIndex("number"));// 获得number 这列的值//获得模式   一共三列   mode为第二列int mode = cursor.getInt(2);//将number mode 封装到bean中BlackNumBean bean = new BlackNumBean(number, mode);//封装的对象添加到集合中allBlackNum.add(bean);}//关闭cursorcursor.close();SystemClock.sleep(1000);// 休眠2秒,模拟黑名单比较多,比较耗时的情况return allBlackNum;};/*** 获得黑名单的数量*/public int getBlackNumCount(){SQLiteDatabase db = dbHelper.getReadableDatabase();Cursor cursor = db.query(table_black_num, new String[] {"count(*)"}, null, null, null, null, null);cursor.moveToNext();int count = cursor.getInt(0);// 仅查了一列,count(*) 这一刻列cursor.close();return count;}/*   *//*** //查找 每一个黑名单都有 号码和模式  先把号码和模式封装一个bean* 获得所有的黑名单* @return*//*public List<BlackNumBean> getAllBlackNum(){//创建集合对象List<BlackNumBean> allBlackNum = new ArrayList<BlackNumBean>();SQLiteDatabase db = dbHelper.getReadableDatabase();Cursor cursor = db.query(table_black_num, null, null, null, null, null, null);// 返回的 cursor 默认是在第一行的上一行//遍历while(cursor.moveToNext()){// cursor.moveToNext() 向下移动一行,如果有内容,返回trueString number = cursor.getString(cursor.getColumnIndex("number"));// 获得number 这列的值//获得模式   一共三列   mode为第二列int mode = cursor.getInt(2);//将number mode 封装到bean中BlackNumBean bean = new BlackNumBean(number, mode);//封装的对象添加到集合中allBlackNum.add(bean);}//关闭cursorcursor.close();SystemClock.sleep(1000);// 休眠2秒,模拟黑名单比较多,比较耗时的情况return allBlackNum;};*//*** 根据号码,获得拦截模式* @param number* @return* 如果不是黑名单,那么,返回 -1*/public int getMOdeByNumber(String number) {int mode =  -1;//获得一个可读的数据库的一个引用SQLiteDatabase db = dbHelper.getReadableDatabase();//查询  表   列   条件Cursor cursor = db.query(table_black_num, null, "number = ?", new String []{number}, null, null, null);if( cursor.moveToNext()){// 如果查到了,移动成功mode = cursor.getInt(cursor.getColumnIndex("mode"));}cursor.close();return mode ;}}

BlackNumBean.java

/*** Created by Administrator on 2017/6/29.*/
public class BlackNumBean {public String number;public int mode;public BlackNumBean() {super();// TODO Auto-generated constructor stub}public BlackNumBean(String number, int mode) {super();this.number = number;this.mode = mode;}@Overridepublic String toString() {return "BlackNumBean [number=" + number + ", mode=" + mode + "]";}
}

MainActivity.java

/*** 具有固定规则的大量的数据 可以储存在数据库中    所以建库  然后增删改查* 可以有三列  _id主键列     number号码列   mode int 0全部拦截   1拦截电话    2拦截短信* 新建一个数据库的类 db (database) 类要继承squliteOpenhelper*/
public class MainActivity extends AppCompatActivity {private ListView listView;private LinearLayout llLoading;private ProgressBar progressBar;private TextView tvDesc;private MyAdapter adapter;/*** 黑名单操作的工具类*/private BlackDao blackDao;//黑名单的集合//private List<BlackNumBean> allBlackNum;private List<BlackNumBean> blackNums;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ctx = this;listView = (ListView) findViewById(R.id.li_listView);llLoading = (LinearLayout) findViewById(R.id.ll_loading);progressBar = (ProgressBar) findViewById(R.id.pb_progressBar);tvDesc = (TextView) findViewById(R.id.tv_desc);blackDao = BlackDao.getInstance(this);// 只有当onCraete 执行完了以后,页面才会显示出来,// 在onCreate 方法中不能有耗时的操作,哪怕是 1 秒也不行,会严重影响用户体验,// 如果有耗时的操作(加载数据),一定要开子线程fillData();//添加监听regListener();}//修改黑名单  当长按某一个条目时 弹出提个修改对话框//添加一个长按的监听private void regListener() {// listView 添加条目长按的监听listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {@Override/*** 长按某个条目时,调用此方法 ,* 注意,返回  true*/public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {showUpdataBlackNumDialog(position);return true;}});}/*** 显示更新黑名单对话框** @param position 长按的条目的下标*/protected void showUpdataBlackNumDialog(int position) {//复制添加黑名单的code 修改//在java代码中创建对话框AlertDialog.Builder adb = new AlertDialog.Builder(this);dialog = adb.create();//从集合中获取封装的对象final BlackNumBean blackNumBean = blackNums.get(position);//将布局转换为view对View view = getLayoutInflater().inflate(R.layout.dialog_updata_blacknum, null);final TextView tvBlackNum = (TextView) view.findViewById(R.id.tv_black_number);//获取电话号码 并赋值tvBlackNum.setText("黑名单:" + blackNumBean.number);final CheckBox cbStopCall = (CheckBox) view.findViewById(R.id.cb_stop_call);final CheckBox cbStopSms = (CheckBox) view.findViewById(R.id.cb_stop_sms);//获取模式  并初始化模式switch (blackNumBean.mode) {case 0:cbStopCall.setChecked(true);cbStopSms.setChecked(true);break;case 1:cbStopCall.setChecked(true);cbStopSms.setChecked(false);break;case 2:cbStopCall.setChecked(false);cbStopSms.setChecked(true);break;}Button btnCancel = (Button) view.findViewById(R.id.btn_cancel);Button btnOk = (Button) view.findViewById(R.id.btn_ok);//为两个按钮 添加点击事件//取消按钮btnCancel.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {dialog.dismiss();}});//点击确定按钮btnOk.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//获取输入框号码String number = tvBlackNum.getText().toString().trim();if (TextUtils.isEmpty(number)) {MyUtils.showToast(ctx, "号码不能为空");return;}//获取模式int newMode = 0;// 初始化模式if (cbStopCall.isChecked() && cbStopSms.isChecked()) {newMode = 0;} else if (cbStopCall.isChecked() && !cbStopSms.isChecked()) {newMode = 1;} else if (!cbStopCall.isChecked() && cbStopSms.isChecked()) {newMode = 2;} else {MyUtils.showToast(ctx, "请选择拦截模式");return;}//更新黑名单blackDao.updateBlackNumMode(blackNumBean.number, newMode);//显示至listview页面blackNumBean.mode = newMode;  //修改数据adapter.notifyDataSetChanged();//刷新//关闭对话框dialog.dismiss();}});dialog.setView(view);dialog.show();}/*** 当手指在listview上滑动时*/private void resListener() {//为ListView设置一个滑动监听listView.setOnScrollListener(new AbsListView.OnScrollListener() {@Override/*** 当滑动状态发生改变时*/public void onScrollStateChanged(AbsListView view, int scrollState) {
//              OnScrollListener.SCROLL_STATE_IDLE;  //空闲状态     idle空闲
//              OnScrollListener.SCROLL_STATE_FLING;// 快速滑东,  没有触摸  但在滑动
//              OnScrollListener.SCROLL_STATE_TOUCH_SCROLL; // 触摸并滑动//在空闲的时候 判断屏幕最后一个条目,是否是listvist 的最后一个条目, 如果是  说命该加载项更多的数据了if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {//获得可见的最后一个条目的下表int lastVisiblePosition = listView.getLastVisiblePosition();if (lastVisiblePosition == adapter.getCount() - 1) {// 看到最后一个条目了if (pageIndex < totalPage - 1) {//当前页面的下标 加一pageIndex++;fillData();} else {MyUtils.showToast(ctx, "没有数据了");}}}}@Override/*** 滑动时不断调用此方法*/public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}});}private void fillData() {//当点击上一页 下一页 是将加载狂显示出来llLoading.setVisibility(View.VISIBLE);// 进入页面后  加载数据(开子线程)  根据结果 显示页面new Thread() {public void run() {//当第一次加载后  会把数据设置给集合//当第二次加载后  会把数据追加在第一次后if (blackNums == null) {//第一次//所有的黑名单的集合//    allBlackNum = blackDao.getAllBlackNum();blackNums = blackDao.getBlackNumByPage(pageIndex, pageSize);} else { ///加载更多  ,数据追加blackNums.addAll(blackDao.getBlackNumByPage(pageIndex, pageSize));}//获取黑名单的数量int totalcount = blackDao.getBlackNumCount();if (totalcount % pageSize == 0) {// 判断是否能整除totalPage = totalcount / pageSize;} else {totalPage = totalcount / pageSize + 1;}//如果集的size 是0 则没有黑名单  ,如果不是零 则有黑名单 则要展示出来、、//而子线程不能改变页面   那么就要发送handler信息//发送一个空的消息 数据获取完了 可以刷新页面handler.sendEmptyMessage(FLUSH_UI);};}.start();}//黑名单数据加载的方式二   分批加载//生成变量/*** 当前页面的下标*/private int pageIndex = 0;/*** 每一页的数量*/private int pageSize = 20;/*** 总页数*/private int totalPage;protected Activity ctx;//刷新界面用的  当获得了数据后 就发送一个信息private final int FLUSH_UI = 100;private Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {switch (msg.what) {case FLUSH_UI://子线程获得了数据,开始刷新页面// 没有黑名单的情况if (blackNums.size() == 0) {// 没有黑名单的情况progressBar.setVisibility(View.GONE);tvDesc.setText("没有黑名单,请添加几个吧");} else {//  有黑名单,关闭加载框,listView 展示黑名单  就是为Listview 设置AdapterllLoading.setVisibility(View.GONE);if (adapter == null) { //第一次加载adapter = new MyAdapter();listView.setAdapter(adapter);} else {//追加数据adapter.notifyDataSetChanged();// 刷新listView 否则仍会从头开始 显示}}break;}};};/*** listview 如果不优化可能出现的问题:* 一: getView 方法 大量调用,创建大量的对象,造成内存的浪费,甚至是 OOM 异常* 二:如果getview 方法执行的时间过长,超过 150 毫秒,用户就会明显的感觉到卡顿现象** @author Administrator*         <p/>*         优化的目标:创建尽可能少的对象,执行getView的时间尽可能短*         <p/>*         listview 优化一:复用convertView*         优化的结果:当convertView 不为空时,不再创建新的 view 对象,省略了*         getLayoutInflater().inflate(R.layout.list_item_black_num, null);*         而  inflate 是一个比较耗时的动作。*         <p/>*         listView 优化二:使用ViewHolder*         优化的结果:当convertView 不为空时 ,通过 convertView 身上的背包,获得他的子view 然后,为子view赋值,*         从而,省略了 findViewById 这个方法*/private class MyAdapter extends BaseAdapter {@Override/*** 告诉 listview 有多少个条目*/public int getCount() {// TODO Auto-generated method stubreturn blackNums.size();}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn null;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn 0;}@Override/*** 返回第一个条目对应的 view ,* 当某个 条目 将要显示在屏幕上时,就会调用getView 方法 ,将该条目创建出来* @param position 条目的下标* 新建一个list_item_black_num.xml的条目布局*/public View getView(final int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubView view;ViewHolder vh;if (convertView == null) {view = getLayoutInflater().inflate(R.layout.list_item_black_num, null);//创建ViewHoldervh = new ViewHolder();// 找到  子 viewTextView tvNum = (TextView) view.findViewById(R.id.tv_number_list_item);TextView tvMode = (TextView) view.findViewById(R.id.tv_mode_list_item);ImageView ivDelete = (ImageView) view.findViewById(R.id.iv_delete_list_item);// 将子view 打包vh.tvMode = tvMode;vh.tvNum = tvNum;vh.ivDelete = ivDelete;// 将背包背在view的身上view.setTag(vh);} else {view = convertView;//取出背包vh = (ViewHolder) convertView.getTag();}BlackNumBean blackNumBean = blackNums.get(position);//用取出的背包赋值vh.tvNum.setText(blackNumBean.number);switch (blackNumBean.mode) {case 0:vh.tvMode.setText("全部拦截");break;case 1:vh.tvMode.setText("拦截电话");break;case 2:vh.tvMode.setText("拦截短信");break;}//删除黑名单
//          为ivdelete设置一个点击事件vh.ivDelete.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//从数据库中删除数据blackDao.deleteBlackNum(blackNums.get(position).number);//从集合中删除数据blackNums.remove(position);//刷新页面notifyDataSetChanged();}});return view;}}//优化二   先声明一个临时的辅助类  然后有几个子view  声明几个成员变量private static class ViewHolder {public ImageView ivDelete;TextView tvNum;TextView tvMode;}/*** 添加黑名单** @param v*/public void addBlackNum(View v) {// 展示天年黑名单的对话框showAddBlackNumDialog();}private AlertDialog dialog;private void showAddBlackNumDialog() {//在java代码中创建对话框AlertDialog.Builder adb = new AlertDialog.Builder(this);dialog = adb.create();//将布局转换为view对象View view = getLayoutInflater().inflate(R.layout.dialog_add_blacknum, null);final EditText etInputNum = (EditText) view.findViewById(R.id.et_input_number);final CheckBox cbStopCall = (CheckBox) view.findViewById(R.id.cb_stop_call);final CheckBox cbStopSms = (CheckBox) view.findViewById(R.id.cb_stop_sms);Button btnCancel = (Button) view.findViewById(R.id.btn_cancel);Button btnOk = (Button) view.findViewById(R.id.btn_ok);//为两个按钮 添加点击事件//取消按钮btnCancel.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {dialog.dismiss();}});//点击确定按钮btnOk.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//获取输入框号码String number = etInputNum.getText().toString().trim();if (TextUtils.isEmpty(number)) {MyUtils.showToast(ctx, "号码不能为空");return;}//先初始化modeint mode = 0;if (cbStopCall.isChecked() && cbStopSms.isChecked()) {mode = 0;} else if (cbStopCall.isChecked() && !cbStopSms.isChecked()) {mode = 1;} else if (!cbStopCall.isChecked() && cbStopSms.isChecked()) {mode = 2;} else {MyUtils.showToast(ctx, "请选择拦截模式");return;}//将黑名单信息插入数据库blackDao.addBlackNum(number, mode);//显示至listview页面//加入集合blackNums.add(0, new BlackNumBean(number, mode));//要 将黑名单添加至集合的第一位//祖传错误   当数据库中没有数据    会直接进入黑名单添加数据  但是adapter在这个时候并没有创建   所以刷新的时候会显示空指针异常//所以要先判断adapter 是否为空if (adapter == null) {adapter = new MyAdapter();//listView.setAdapter(adapter);}llLoading.setVisibility(View.GONE);adapter.notifyDataSetChanged();//刷新//关闭对话框dialog.dismiss();}});dialog.setView(view);dialog.show();}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="mp.zyqj.zz.mobilephone.MainActivity"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewstyle="@style/tv_title"android:text="黑名单拦截" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="addBlackNum"android:layout_alignParentRight="true"android:layout_margin="5dp"android:text="添加黑" /></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" ><LinearLayoutandroid:id="@+id/ll_loading"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="#6600ff00"android:gravity="center"android:orientation="vertical"android:padding="8dp" ><ProgressBarandroid:id="@+id/pb_progressBar"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/tv_desc"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="玩命加载中,请稍候..." /></LinearLayout><ListViewandroid:id="@+id/li_listView"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_alignParentLeft="true"android:layout_alignParentTop="true" ></ListView></RelativeLayout>
</LinearLayout>

源码:http://download.csdn.net/detail/lijinweii/9884809

Android 数据储存的方式之本地数据库储存相关推荐

  1. Android数据存储(三)----- SQLite数据库存储

    SQLite是Android系统内置的数据库,是一种轻量级的关系型数据库,它运算速度快,占用资源少,非常适合在移动设备上使用.同时,它不仅支持标准的SQL语法,还遵循了数据库的ACID事务. 一.创建 ...

  2. 在android手机端查看APP的本地数据库

    在软件测试过程中,有时可能会需要用到查看APP的本地数据库,那要如何才能实现呢 不管使用什么工具来查看数据库,首先一个前提是要获得手机或者Android设备的Root权限,接下来的操作才有意义. 一. ...

  3. Android怎么查看手机中的本地数据库

    我前几天做的项目中有本地数据库, 所以就 用的 SQLite,在调试数据库时,,很想看一下里面的表结构是否正确,这个时候就十分苦恼, 因为这个db文件不能够直接拿出来,我们知道,在DDMS里面有一个F ...

  4. Android数据的存储方式简介

    作为一个完整的应用程序,数据存储操作是必不可少的.因此,Android系统一共提供了四种数据存储方式.分别是:SharePreference.SQLite.Content Provider和File. ...

  5. windows下使用数据泵的方式导入导出数据库

    在导入导出之前需要先做一些准备工作. 1.创建表空间: CREATE TABLESPACE ORCL datafile 'E:\app\zxp\oradata\orcl\ORCL.dbf' size ...

  6. 微信小程序与本地数据库的进行基础数据交互的案例——使用Java后台

    微信小程序与本地数据库的进行基础数据交互的案例--使用Java后台 案例介绍 本地数据库储存用户信息表 后台Java访问数据库,获得需要数据 小程序端访问服务器 环境配置及需要的项目代码资源: 案例介 ...

  7. Android数据存储之GreenDao 3.0 详解

    前言: 今天一大早收到GreenDao 3.0 正式发布的消息,自从2014年接触GreenDao至今,项目中一直使用GreenDao框架处理数据库操作,本人使用数据库路线 Sqlite----> ...

  8. OPC服务器如何采集设备的信息,如何将OPC服务器采集的设备数据转为MQTT方式,实现云端发布或订阅...

    通过与PLC.智能仪表等硬件设备,以及OPC服务器.数据库等软件建立通讯,进行实时数据采集监控,然后将相关数据转换为数据库.OPC,以及MQTT.HTTP等多种服务接口,实现各类自动化与信息化系统软件 ...

  9. html5本地数据库 没有用,【HTML5初探之本地存储】如果没有数据库。。。

    导航 [初探HTML5之使用新标签布局]用html5布局我的博客页! [HTML5初探之form标签]解放表单验证.增加文件上传.集成拖放 [HTML5初探之绘制图像(上)]看我canvas元素引领下 ...

最新文章

  1. 抗侧力构件弹性位移如何计算_穿心棒法盖梁施工计算书(工字钢)
  2. 【计算机网络】网络层 : 路由算法 ( 路由算法分类 | 静态路由算法 | 动态路由算法 | 全局性动态路由算法 | 分散性动态路由算法 | 分层次路由选择协议 )
  3. zabbix历史数据mysql_处理Zabbix历史数据库办法一
  4. 【完整示例】采用jenkins pipeline实现自动构建并部署至k8s
  5. 2015年第六届蓝桥杯C/C++ A组国赛 —— 第五题:切开字符串
  6. java 资深工程师必备技能
  7. Mosquitto感知客户端上下线的方法
  8. [第二届构建之法论坛] 预培训文档(C++版)
  9. mysql 查询记录成纵向_Mysql中查询(数据库中的)纵向转(查询结果显示为)横向.
  10. 【2019银川网络赛:L】Continuous Intervals(线段树区间处理+单调栈+思维)
  11. InnoDB存储引擎MVCC实现原理
  12. tikz包 安装_LaTeX安装宏包
  13. 有参构造法和无参构造法
  14. 报错:找不到模块“antd-mobile (也可以是其他的模块)”或其相应的类型声明。
  15. 2020年就要过去了,我们决定用这种方式记住它
  16. 数据库逻辑设计之 三大范式 及 反范式化 优缺点
  17. 2015阿里校园招聘(2014.09.23)
  18. 从零开始编写自己的C#框架(8)——后台管理系统功能设计
  19. Swift字符串转16进制+字符串过滤
  20. 【简单】LCP 02. 分式化简

热门文章

  1. 2019电信网络诈骗犯罪情况介绍
  2. 求求你们了,MyBatis 批量插入别再乱用 foreach 了,5000 条数据花了 14 分钟。。
  3. 智能健康:智能家居带来健康保障
  4. matlab实现随机攻击网络节点+蓄意攻击网络节点(2)
  5. 百度小程序,字节跳动小程序支付总结
  6. P2P技术详解(四):P2P技术之STUN、TURN、ICE详解
  7. Web 服务器的搭建
  8. Google襄助,图灵奖金大涨
  9. jquery选项卡切换功能实现
  10. 动态规划——通配符匹配算法