第五章详解广播机制
不得不佩服人的惰性.....要努力啊。
又学到了四大组件的一个组件BroadCastReceiver,霖神一开始简单谈到了(1)什么是广播机制,(2)然后是接收系统广播(动态注册和静态注册两种,两种都有优势劣势)、(3)自定义广播分为两种,一种是标准广播、一种是有序广播。(4)然后谈到了只能在程序内部传递而且只接受本程序发出的本地广播,(5)最后教给我们如何Git建立本地仓库并上传代码到GitHub。
(一)广播机制简介
标准广播:异步执行,所有广播接收器在同一时刻收到广播消息,无法被截断;
有序广播:同步执行,同一时刻只有一个广播接收器接收到消息,有先后顺序,可被后面广播接收器截断。
(二)接收系统广播
系统广播譬如:电量变化、时间时区变化等。在代码中注册广播称为动态注册,在AndroidManifest.xml中注册称为静态注册
2.1动态注册监听网络变化:
功能:监听网络变化
实现过程:
1.定义内部类,继承自BroadcastReceiver,并重写父类onReceive方法,创建广播接收器。
2.创建intentFilter实例,添加一个action的值,广播接收器想接受什么广播,在这里添加相应的Actiona:**一定要确定对应的Action,android.net.conn.CONNECTIVITY_CHANGE
3.创建NetworkChangeReceiver实例,调用registerReceiver来进行注册,实现动态监听功能。
4.ConnectivityManager管理网络服务系统服务类,通过getSystemService获得该实例,getActiveNetworkInfo获取networkInfo实例。通过networkInfo的isAvailable判断当前是否有网络。
*5.一定要在AndroidMAnifest.xml中设置权限声明。
*6.动态注册的广播一定要取消注册才行。unregisterReceiver注销广播。
2.2 静态注册实现开机启动
动态注册优势是灵活性高,缺点是必须启动之后才能接收到广播,而静态注册程序未启动就能接收到广播。
功能:开机启动弹窗
实现步骤:
1.右击包名->new->Other->BroadCast Receiver。勾选exported和enabled,exported允许广播接收器接收本程序之外的广播,enabled选择启用该广播接收器。
2.修改BootCopleteReceiver的代码,实现一个弹窗功能;
3.在Receiver中的
4.声明相应的权限:
这个不用注销掉广播哈,然后很恶心的一点是每次开机后十几秒才弹出弹窗,让我误以为不弹,各位老铁请注意。然后BootCopleteReceiver的onReceiver方法不能填加过多逻辑和耗时操作。若长时间不结束,会报错。
(三)发送自定义广播
刚才说到了系统广播,然后我们来看看自定义广播。
3.1 发送标准广播
1.新建广播接收器Broadcast_01,弹出弹窗,AndroidMainfest.xml中对于该receiver的intent_filter进行修改,接收到一条值为 nwu.hzk.p177.My_broad的广播。
2.MainActivity中建立按钮,用于发送广播触发点,构建Intent对象,将发送的广播植入,使用sendBroadcast(intent);发送广播,所有监听该广播的接收器就会接收到该消息。
3.2 发送有序广播
1.新建程序,注册接受广播Broadcast_02,让其接收上一个程序发送的nwu.hzk.p177.My_broad广播;
2.Broadcast_01将sendBroadcast(intent);变为sendOrderedBroadcast(intent,null);
3.再将Broadcast_02中receiver的intent_filter的优先级android:priority="100"设置为100;
4.在Broadcast_02中调用abortBroadcast();中断广播传递,这样Broadcast_01就不会接收到广播啦。
(四)使用本地广播
本地广播机制支持能在程序内部传递而且只接受本程序发出的广播。
与动态注册广播有一点点区别,大致一样:
1.使用LocalBroadcastManager的getInstance去获取一个实例;
2.发送广播接收器的时候是localBroadcastManager.sendBroadcast(intent);//发送
3.信号自己定。
(五)强制下线功能。
这块并不难,只是说自己觉得人写的高明的几点:
1.建立ActivityCollector来管理所有活动,添加活动,删除活动,结束所有活动;
2.创建BasicActivity作为所有活动父类。复写Oncreate和OnDestroy方法;
3.建立布局和响应点击事件,判断是否相等跳到MainActivity相应界面;
4.在Activity实现广播的发送。
5.在BasicActivity实现广播的监听,在onResume()方法中实现广播监听的注册,广播监听注册的ForceOfflineReceiver是一个AlterDialog,然后点击ok键是销毁所有活动,启动登录界面的操作,因为此时活动一定处于返回栈栈顶,准备好和用户进行交互时调用;在onPause()方法中实现广播的注销,因为此时系统去启动或者回复另一个活动的时候调用,当一个活动失去栈顶位置时会自动取消广播接收器的注册。
6.改变主函数的入口,从MainActivity改到LoginActivity
(六)Git-初识版本控制工具
是一款分布式版本控制工具。下面来教教大家如何使用Git建立本地仓库并上传代码到GitHub
1.到本地项目文件夹右键选择git bash here
2.输入个人信息(代码提交者)
git config --global user.name "xxxx"
git config --global user.email [email protected]
3.在本地项目目录创建本地仓库,输入命令后项目目录会有一个隐藏的.git文件夹
git init
4.上传所有代码到本地仓库
git add .
git commit -m "initial commit"
5.上传代码到github
新建repository,复制仓库地址
6.关联本地仓库并上传代码
git remote add origin ***.git(刚才复制的仓库地址)
git push origin master
第六章 数据存储全方案-持久化技术
保存在内存中的数据是瞬时状态的,保存在存储设备中的数据是处于持久状态的,文件存储、SharedPerference存储和数据库存储三种方式。(1)文件存储就是利用输入输出流等Java常用的方法将文件写入,可以用于存储文本或二进制数据;(2)SharedPreferences用于存储键值对,可以支持不同类型的数据;(3)SQLite可以存储复杂的关系型数据库,实现创建、增删查改等功能。(4)作者维护的一个开源库LitePal,相比于SQLite,它采用对象关系映射(ORM)的模式,对数据库功能进行封装,较为简单。利用对象的思想去解决关系型数据库的问题,什么时候自己能维护一个就厉害了。
(一)文件存储
不做格式化处理,原封不动存储文本数据和二进制数据。
1.1.将数据存储到文件中
第一步:openFileOutput将数据存储到指定的文件当中去。第一个是文件名,第二个是文件的操作模式,MODE_PRIVATE为默认,会覆盖之前内容,APPEND会追加内容。默认存储到/data/data/pacak name/file下
第二步:获得FileOutputStream对象,借助他构建OutputStreamWriter对象,在构建BufferedWriter对象,使用Java流方式将其写到文件当中去。
第三步:输入结束关闭输入流。
第四步:onDestroy中复写存储方法,确保活动销毁之前调用save方法。
查看好像不太好查看,在Android Device Monitor中没有看到file文件下的data。(可能需要刷机吧)
1.2.从文件中读取数据
第一步.openFileInput获得FileInputStream对象;
第二步.借助上一步结果构建InputStreamReader对象,在构建BufferedReader对象,再一行行构读取文本中的所有内容,存放至Stringbuilder对象中去。读取并返回,关闭Reader流。
第三步.在onCreate方法中调用load()方法,获取字符串。!TextUtils.isEmpty(inputText)判断字符串不为null或空时,setText设置字符串。使用editText.setSelection(inputText.length());将光标移至末尾。
此方法不适合保存一些复杂的文本数据,故而....我们来看下一种存储方式。
(二)SharedPreferences存储
使用键值对存储数据,支持多种不同类型数据存储。
2.1将数据存储至SharedPreferences中
第一步.使用三种方法获得SharedPreferences对象,第一种是getSharedPreferences:参数是文件名和指定的操作模式;第二种是getPreferences获得对象,只有一个参数,文件名类名;第三种是getDefaultPreferences,程序包名存储。
第二步.SharedPreferences的edit方法获取editor对象。
第三步.在Editor对象中添加数据,比如添加布尔类型putBoolean,添加字符串putString
第四步.将添加的数据进行提交。
2.2从SharedPreferences中拿数据
第一步.getSharedPreferences获得sharedPreferences对象;
第二步.getString、getInt获得相应数值,若没有,则用后面的默认值替代。
第三步.logd输出
2.3实现记住密码功能
复用P185代码。需要注意的有以下几点:
1.加入复选框,如果选定就记住密码,若没有选中就不记住密码。
2.点击之后会将几个值存进sharedPreferences中,用boolean类型更改为true。下一次在执行OnCreate的时候讲boolean,用户名,密码setText和setChecked进去。刚开始默认boolean是false。
很简单。
(三)SQLite
轻量级关系型数据库,速度快,占用资源少,遵循数据库ACID事务。当存储度咋的关系型数据库时,以上两种存储方式就会有比较大的问题。
3.1创建数据库
SQliteHelper帮助类来对数据库进行创建和升级。其中有两个抽象方法。分别是onCreate和onUpgrade,在这两个方法中创建和升级数据库的逻辑。使用getReadableDatabase()和getWritableDatabase()来创建或打开一个数据库。主分为以下几步:
(1).创建MyDatabaseHelper继承自SQLiteHelper,创建数据库的语句,将建表语句定义成字符串常量。
public static final String CREATE_BOOK = "create table Book("
+"id integer primary key autoincrement,"
+"author text,"
+"price real,"
+"pages integer,"+"name text)";
(2).在onCreate调用SQLiteDatabase的execSQL执行这条建表语句,弹出Toast提示成功。
(3).创建相应的布局。
(4).MyDatabaseHelper的getWritableDatabase方法创建并打开数据库。Adb shell如何配置于系统中,进入相应的Database目录下,ls命令看里面内容(必须要root权限),sqlite3 BookStore.db打开数据库;.table查看哪些表;.schema查看建表语句。
3.2升级数据库
(1).在Book表基础之上再添加Category表;
(2).在onUpgrade中增加两条Drop语句,若存在则删除该表,并转而执行onCreate方法;
(3)在onCreate方法中执行创表语句;
(4)dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);将版本号改为比1大的。
3.3 添加数据
数据操作无非就是4种。C(Create添加->insert)R(Retrieve查询->select)U(Update更新->update)D(Delete删除->delete),调用SQLIteOpenHelper的getWritableDatabase可以用于创建和升级数据库,而且其会返回一个SQLiteDatabase对象供我们去进行GUID操作。示例如下:
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
//1.开始组装并插入第一条数据;
values.put("name","The Da Vinci Code");
values.put("author","Dan Brown");
values.put("pages",454);
values.put("price",16.96);
db.insert("Book",null,values);
values.clear();
3.4 更新数据库
首先构建一个ContentValues对象,指定更改后的数据,调用SQLiteDatabase的update对象,第三个参数对应SQL语句的where部分,表明更新所有name等于?的行,而?相当于一个占位符,第四个参数为占位符指定的内容。
SQLiteDatabase db=dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price",10.99);
db.update("Book",values,"name=?",new String[]{"The Da Vinci Code"});
3.5 删除数据库
没什么好说的。很简单。
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book","pages>?",new String[]{"500"});
//通过第二三参数来删除页数超过500的书。
3.6查询数据
较为复杂,总共七个参数;调用query之后会返回一个Cursor对象。查询到的数据从中取出。
(1)db.query("Book",null...)查询Book表中的所有数据,并将数据以Cursor对象进行返回。
(2)将数组指针通过moveToFirst移到第一行的位置。
(3)遍历Cursor对象,取出数据并打印,通过getColumnIndex获取某一列在表中对应的位置索引,然后将这索引传入到相应的取值方法中,这样便可以得到从数据库中读取到的数据了。
(4)Log输出。moveToNext获取下一条数据。
(5)调用Close方法来关闭Cursor流。
3.7使用SQL操作数据库
(四)LitePal
LitePal是一款开源数据库框架,采用对象关系映射(ORM)的模式,对数据库功能进行封装,较为简单。
4.1配置LitePal
(1)Build.gradle中的dependencies中添加compile 'org.litepal.android:core:1.3.2'
(2)在main目录下建立assets目录,在assets目录下建立litepal.xml,编辑里面内容。指定相应的数据库名、数据库版本名、以及list所指的所有映射模型。
(3)在AndroidManifest.xml中增加Appliacation配置
android:name="org.litepal.LitePalApplication"
4.2创建和升级数据库
(1)建立Book类,定义id、author、price、pages、name这几个字段及相应的get和set方法,每个字段对应表中的每一列。
(2)将Book类添加至4.1的第(2)中的List中。
(3)在MainActivity中进行Connector.getDatabase();完成一次最简单的数据库操作,这时数据库就会自动创建完成了。
(4)升级数据库的话,若是在一张表里面添加列,则只需要在Book中添加相应的变量名和相应的set和get方法;若是需要添加表,则新建Category类并在list映射模型中添加新的模型类。
4.3使用LitePal添加数据
(1)先将模型类继承自DataSupport类,这样才能进行GUID操作;
public class Book extends DataSupport{
(2)创建出Book的实例,然后各种set方法,最后调用book.save()方法完成数据添加操作。
4.4使用LitePal更新数据库
(1)对已存储的对象进行操作;直接setPrice()对价格进行修改,然后save完成该条数据的更新。
(2)更为灵活的更新书名、印刷商。更新所有该条件判断语句下的对象。
Book book = new Book();
book.setPrice(14.95);
book.setAuthor("Anchor");
book.updateAll("name=? and author=?","The Lost Symbol","Dan Brown");
(3)将Pages字段更新为默认值。
Book book = new Book();
book.setToDefault("pages");
book.updateAll();
4.5使用Litepal删除数据
DataSupport.deleteAll删除数据,第一个参数用于指定那个表,第二个和第三个是约束条件。
DataSupport.deleteAll(Book.class,"price < ?","15");
4.6利用LitePal查询数据
使用List
4.7其他操作语句