数据存储,线程的知识总结
2016-06-18 22:49
330 查看
Data Storage(数据存储)
1.FAQ?
Android UI 负责呈现实现与用户的交互,与用户交互时的数据需要借助View去呈现,数据来自何方?
2.Android 中的数据来源?(外存)
1)外置sdcard (非手机自带,可以自行安装)
2)内置sdcard (手机自带,操作系统所在盘符)
3)外置网络服务器(例如云端
3.Android 中数据存储类型?
1)外部存储(外置sdcard的存储):I/O存储
2)内部存储(内置sdcard的存储)
a)直接I/O存储
b)偏好设置存储(SharedPreferencs)
c)SQLite存储(内置数据库系统的存储)
3)网络存储(现阶段不讲)
4.Android
中外部数据存储的实现?
4.1 FAQ?
1)外部存储状态(是否有外置sdcard,是否可用)
2)外部存储路径(数据存储的具体位置)
3)外部存储空间(是否有空间可以存储我们的数据)
4)外部存储权限(是否有权限向指定目录写入数据)
5)外部存储实现(如何向指定路径写入数据)
6)外部存储是否可以实现应用程序私有数据的存储
4.2 API?
1)Environment(sdcard状态,公共存储目录)
2)StatFs(获得指定目录大小)
3)Context(获得应用程序在外置sdcard的私有存储目录)
4) Log.i("TAG",
"privateCacheDir="+privateCacheDir.getPath());//mnt/sdcard/and
4)I/O(读写)
4.3 存储实现?
1)获得外部存储状态?
//1)获得外部存储状态,并判定状态?
//mounted(已挂载)
String state=Environment.getExternalStorageState();
//
Environment.isExternalStorageRemovable()
2)获得外部存储路径?(公有,私有:记得权限)
//2)获得外部存储路径?
//2.1)获得应用程序公有存储目录(例如下载的电影,音乐)
Filesdcard=Environment.getExternalStorageDirectory();
Log.i("TAG","sdcard.path="+sdcard.getPath());//mnt/sdcard
File picDir=Environment.
getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
Log.i("TAG","picDir.path="+picDir.getPath());
roid/data/项目包/cache
//2.2)获得应用程序私有存储目录(应用程序卸载数据也会被删除):必须有写权限
FileprivateDir=getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File privateCacheDir=getExternalCacheDir();//Context
Log.i("TAG",
"privateDir="+privateDir.getPath());//mnt/sdcard/android/data/项目包/files
3)获得外部存储空间大小?
//3)获得存储空间的小,及可用空间大小
StatFs sf=new StatFs(sdcard.getPath());
Log.i("TAG","blockcount="+sf.getBlockCount());
Log.i("TAG","blockSize="+sf.getBlockSize());
Log.i("TAG","sdcard.size="+
(sf.getBlockCount()*sf.getBlockSize()*1.0)/1024/1024);
doubleaSize=(sf.getAvailableBlocks()
*sf.getBlockSize()*1.0)/1024/1024;//M
Log.i("TAG","available.size="+aSize);
4)读写数据(I/O)
//4)向指定目录写入数据
String dataStr="139/123/AAA/A@t.com";
if(dataStr.getBytes().length>=(sf.getAvailableBlocks()*sf.getBlockSize())){
Toast.makeText(this,
"空间不足", 1).show();
return;
}
FileOutputStream fos=null;
try{
fos=new FileOutputStream(new File(
getExternalCacheDir(),"data.txt"));
fos.write(dataStr.getBytes());
Log.i("TAG",
"data write ok!");
}catch(Exception e){
e.printStackTrace();
Log.i("TAG",
"data write error");
}finally{
if(fos!=null)try{fos.close();}catch(Exception
e){}
}
5.Android 中内部数据存储中直接I/O存储实现?
5.1 FAQ?
1)内部存储路径
2)内部存储空间
3)内部存储实现(应用app不需要权限)
//1.获得存储目录?(Environment,Context)
Log.i("TAG",
"rootDir="+Environment.getRootDirectory());//system
Log.i("TAG",
"dataDir="+Environment.getDataDirectory());///data
Log.i("TAG",
"downCache="+
Environment.getDownloadCacheDirectory());///cache
Log.i("TAG","fileDir="+getFilesDir());///data/data/项目包/files
Log.i("TAG",
"cacheDir="+getCacheDir());///data/data/项目包/cache
//2.获得空间大小?(自己写)StatFS
//3.实现存储?
StringdataStr="139/123/AAA/A@t.com";
FileOutputStreamfos=null;
try{
fos=new FileOutputStream(new File(
getFilesDir(),
"data.txt"));
fos.write(dataStr.getBytes());
Log.i("TAG",
"datawrite ok!");
}catch(Exception e){
e.printStackTrace();
Log.i("TAG",
"datawrite error");
}finally{
if(fos!=null)try{fos.close();}catch(Exception
e){}
}
}
5.2 API?
1)Environment
2)Context
a)getFileDir() :data/data/项目包/files
b)getCacheDir():data/data/项目包/cache
c)openFileInput
b)openFileOutput
3)I/O
5.3 内部存储实现?
1)内部存储目录
a)getFileDir
b)getCacheDir
2)内部存储空间大小?(自己尝试)
3)内部存储直接I/O操作(读,写)
案例:获得应用程序缓存目录?
1)首先考虑外部存储目录
2)其次考虑内部存储目录
public File getImageCacheDir(){
//.......
}
6.Android 中内部存储偏好设置的实现?
6.1 FAQ?
1)何为偏好设置(用户喜好信息)
2)偏好设置存储目录(/data/data/项目包/share_prefs)
3)偏好设置存储的实现?
6.2 API?
1)Context
2)SharedPreferences
3)Editor
6.3 存储实现
1)获得SharedPreferences 对象(借助context)
2)读数据(调用对象的getXXX方法读)
3)写数据(获得Editor对象),借助此对象写数据
3.1)获得Editor对象(edit())
3.2)调用Editor的putXXX方法写数据(先存到内存)
3.3)提交数据(commit,将内存数据写到外存)
private
void saveDataToPrefs(){
//1.获得SharedPreferences对象
SharedPreferencessp=
getSharedPreferences("config",//文件名,config.xml
Context.MODE_PRIVATE);//文件操作模式(私有)
//2.获得editor对象
Editoret=sp.edit();
//3.存储数据
et.putBoolean("isUsed",true);//key/value
//et.putInt("count", 10);
et.putString("phone",
"138");
et.commit();//数据的持久化(此时文件不存则会创建,文件存在则更新)
Log.i("TAG",
"prefswrite ok!");
}
private
void getDataFromPrefs(){
//1.获得SharedPreferences对象
SharedPreferencessp=
getSharedPreferences("config",Context.MODE_PRIVATE);
//2.获得文件中数据
boolean isUsed=sp.getBoolean("isUsed",
false);
//int count=sp.getInt("count", -1);
Log.i("TAG",
"isUsed="+isUsed);
//Log.i("TAG", "count="+count);
}
}
6.4 偏好设置案例(系统设置页面的定制)登录记录账号密码
// 初始化SharePreferenecs
sp = getSharedPreferences("user", Context.MODE_PRIVATE);
cb = (CheckBox) findViewById(R.id.cb_1);
et_01 = (EditText) findViewById(R.id.phoneId);
et_02 = (EditText) findViewById(R.id.pwdId);
but = (Button) findViewById(R.id.logonId);
// 获得复选框的选中状态
boolean
isChecked = sp.getBoolean("isCb",
false);
// 通过获得复选框状态设置到复选框上
cb.setChecked(isChecked);
if (isChecked) {
// 在初始化控件时获得偏好设置的数据
name =
sp.getString("name",
"");
pwd =
sp.getString("pwd",
"");
// 将获得数据设置到输入框中
et_01.setText(name);
et_02.setText(pwd);
} else {
// 清空输入框中内容
et_01.setText("");
et_02.setText("");
}
}
private
void setListener() {
but.setOnClickListener(new OnClickListener() {
@Override
public
void onClick(View v) {
name=et_01.getText().toString();
pwd =
et_02.getText().toString();
Editoredit =
sp.edit();
if (cb.isChecked()){
// 保存数据
edit.putString("name",
name);
edit.putString("pwd",
pwd);
edit.putBoolean("isCb",
true);
} else {
edit.putBoolean("isCb",
false);
// 自行完成复选框不被选择的事件
}
edit.commit();
1)定义xml(res/xml/filename.xml)
2)加载xml(.....)
class SettingActivity extends PrefenceActivity{
onCreate(){
addPreferencesFromResource(R.xml.settings);
}
}
3)其它页面读取xml(借助SharedPrefences对象)
说明:以后做配置页面时通常会考虑使用fragment对象
SQLite 存储(内部存储)
1.SQlite 是什么?
1)软件(Software):开源,体积小,适合便携式设备(例如手机)
2)数据库管理系统(DBMS)
2.SQLite 应用场合?
1)更好的存储数据
2)更好的管理数据
3)提高数据的安全
FAQ?
1)将数据直接存储到一些文件有什么缺陷吗?
a)安全性相对较差
b)更新和查询效率较低
c)易读性相对较差
2)SQLite 存储数据的形式是怎样?
1)SQLite 是一个DBMS,此系统可以管理多个数据库(DB)
2)SQLite 中的一个DB可以存储多张二维表(行,列)
3)SQLite 中表(table)是数据的最基本存储单元,DB中
所有数据都是要存储在表中的,表中行通常称之为记录,
表中列通常称之为字段或数据项。
Android 和 IOS 目前的系统中都内置了SQLite数据库。
android 平台架构:
Application (AP):java 应用层
Application FrameWork (AF):java 框架
Libraries(SQLite,...)+虚拟机类库
Linux 内核系统
3.SQLite 在Android
中的应用?
3.1 FAQ?
1)Android 中有几个内置SQLite?(1个)
2)Android 系统中有内置的数据库(DB)?(有)
a)联系人
b)媒体库
c)便签(备忘录)
3)Android 中如何操作SQLite数据库?
1)java(api)
2)sql(结构化查询语言)
3.2 API?
1)Context(资源访问对象)
2)SQLiteDatabase (发送SQL,将sql语句发送到SQLite端)
3)SimpleCursorAdapter(将Cursor中的数据构建成item)
4)SQLiteOpenHelper (工具类,抽象类)
3.3 SQL?(基本应用)
1)DDL(数据定义语言):create,alter,drop,...
2)DML(数据操纵语言):insert,update,delete,select,...
3)DCL(数据控制语言):commit,rollback,......
3.4 SQLite 应用的基本步骤?
1)获得SQLiteDatabase对象
2)借助SQLiteDatabase对象发送SQL
3)释放资源(Cursor,SQLiteDatabase)
private SQLiteDatabase sdb;
/**创建或打开数据库*/
public
void createOrOpenDB(View v){
//借助context的方法创建或打开数据库,不存在则创建,存在则打开
sdb=openOrCreateDatabase(
"contacts.db",//数据库名称
Context.MODE_PRIVATE,//数据库操作模式
null);//CursorFactory
Log.i("TAG",
"contacts.dbcreated or opend");
}
/**创建一张表*/
public
void createTable(View v){
//定义SQL
Stringsql="create table if not exists contact("
+ "_id integer primary key autoincrement,"
+ "phone text not null,"
+ "name text)";
//发送SQL
sdb.execSQL(sql);
Log.i("TAG",
"contactcreated ok");
}
/**向表中写入数据*/
public
void insertTable(View v){
//1.方案1
/* String sql1="insert into contact "
+ "values (null,'139','A0')";
sdb.execSQL(sql1);*/
//2.方案2
/*String sql2="insert into contact (phone,name)"
+" values ('137','A1')";
sdb.execSQL(sql2);*/
//3.方案3
/* String sql3="insert into contact "
+" values (null,?,?)";//"?"代表占位符
sdb.execSQL(sql3,newObject[]{"138","A2"});
*/
//4.方案4
ContentValuesvalues=new ContentValues();//值对象
values.put("phone",
"135");//key 是列的名字
//values.put("name", "A3");//允许为空的列可以不给值
sdb.insert(
"contact",//tableName
null,//nullColumnHack
values);//底层自动拼接sql
Log.i("TAG",
"insertok!");
}
/**从表中查询数据*/
public
void queryTable(View v){
//1.方案1 (查询所有行所有列)
/* Stringsql="select * from contact";
Cursorc=sdb.rawQuery(sql, null);*/
//2.方案2
/*String sql="select * from contact where _id=?";
Cursorc=sdb.rawQuery(sql,new String[]{"1"});*/
/*String sql="select * from contact where phone like ?order by _id desc";
Cursorc=sdb.rawQuery(sql,new String[]{"%13%"});*/
//3.方案3:
Cursorc=sdb.query("contact",
//table
null,//columns(要查询的列,null代表所有列)
"phone like?",
//selection为where 子句
new String[]{"%3%"},
//selectionArgs为where子句?的值
null,//groupBy表示分组
null,//having表示分组以后的限制条件
"_iddesc");//desc表示降序
//取数据
if(c==null){
Log.i("TAG",
"query error");
return;
}
if(!c.moveToFirst()){
Log.i("TAG",
"no data");
return;
}
do{
Log.i("TAG",
c.getInt(c.getColumnIndex("_id"))+"/"+
c.getString(c.getColumnIndex("phone"))+"/"+
c.getString(c.getColumnIndex("name")));
}while(c.moveToNext());//循环一次取一行
//释放资源
c.close();
}
/**修改表中数据*/
public
void updateTable(View v){
//1.方案1
/* String sql="update contact set name=?where _id=?";
sdb.execSQL(sql,newObject[]{"A3","4"});*/
//2.方案2
ContentValuesvalues=new ContentValues();
values.put("name",
"A3");
sdb.update("contact", values,
"_id=?", new String[]{"4"});
Log.i("TAG",
"updateok!");
}
/**删除表中数据*/
public
void deleteTable(View v){
//1.方案1
/*String sql="delete from contact where _id=?";
sdb.execSQL(sql,newObject[]{"4"});*/
//2.方案2
sdb.delete("contact",
"_id=?", new String[]{"4"});
Log.i("TAG",
"deleteOK!");
}
/**删除表*/
public
void dropTable(View v){
Stringsql="drop table if exists contact";
sdb.execSQL(sql);
Log.i("TAG",
"droptable");
}
/**activity销毁时执行*/
@Override
protected
void onDestroy() {
// TODO Auto-generated methodstub
super.onDestroy();
if(sdb!=null)sdb.close();
}
在ListView上显示数据库
//1.获得listview
ListViewlsv=(ListView) findViewById(R.id.lsv);
//2.构建适配器(SimpleCursorAdapter)
//2.1 item data(借助cursor对象获得数据)
sdb=openOrCreateDatabase("contacts.db",Context.MODE_PRIVATE,null);
cursor=sdb.rawQuery("select * from contact",
null);
//2.2 item view
int resourceId=android.R.layout.simple_list_item_2;
//2.3 构建适配器
adapter=new SimpleCursorAdapter(this,
resourceId,
cursor,
new String[]{"_id","phone"},
new
int[]{android.R.id.text1,android.R.id.text2},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);//注册观察者(监测数据源的变化)
//3.关联适配器
lsv.setAdapter(adapter);
//4.注册上下文菜单
registerForContextMenu(lsv);
}
@Override
public
void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfomenuInfo) {
menu.add(0,100, 101, "删除");
}
@Override
public
boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfoacm=
(AdapterContextMenuInfo)
item.getMenuInfo();
if(item.getItemId()==100){
//1.获得要删除的数据id
long id=acm.id;//记录的主键值,现在不等于item的position
//2.执行删除动作
sdb.delete("contact","_id=?",new String[]{String.valueOf(id)});
//3.更新listview
cursor=sdb.rawQuery("select * from contact",null);
adapter.changeCursor(cursor);
}
return
super.onContextItemSelected(item);
}
/**activity销毁时执行此方法*/
@Override
protected
void onDestroy() {
super.onDestroy();
if(cursor!=null)cursor.close();
if(sdb!=null)sdb.close();
}
创建一个操作数据库的类
private DBHelper
db;
private SQLiteDatabase
sdb;
public SQLiteDatabase getSdb() {
return
sdb;
}
public
void setSdb(SQLiteDatabase sdb) {
this.sdb =
sdb;
}
public NoteProvider(Context
context) {
db=new DBHelper(context,"notepads" ,
null, 1);
sdb = db.getWritableDatabase();
}
/**返回值为插入记录的主键值*/
public
long insert(String table,ContentValues
values){
//1.创建或打开数据库
//2.写入数据
long
id=sdb.insert(table,
null,
values);
//3.释放资源
sdb.close();
return
id;
}
/**
* 查询全部数据
* @return
*/
public Cursor chaxun (){
Cursor c =
sdb.rawQuery("select* from notetab",
null);
return
c;
}
/**
* 按条件查询数据
* */
public Cursor chaxun1(String
table,String whereClause,String []whereArgs){
//2.执行查询动作
return
sdb.query(table,null,
whereClause, whereArgs,null,
null, null);
}
class DBHelper
extends SQLiteOpenHelper{
public DBHelper(Context
context, String name, CursorFactory
factory, int
version) {
super(context,
name, factory,
version);
// TODO Auto-generated constructor stub
}
/**
* 此方法在数据库创建时执行,此方法中做什么有业务而定,一般可以创建一些表
*/
@Override
public
void onCreate(SQLiteDatabase db) {
String sql="create table if not existsnotetab(_id integer primary key autoincrement, content text not null,createnttext not null)";
db.execSQL(sql);
}
/**
* 此方法在版本升级是执行
*/
@Override
public
void onUpgrade(SQLiteDatabase db,
int
oldVersion, int
newVersion) {
// TODO Auto-generated method stub
}
Android 中线程应用基础?
1.线程概述?(线程是什么)
线程是进程中的一个顺序的执行流,在程序中表现为一个
对象,多个这样的对象可以并发执行。但是一个线程内部的多个操作肯定是顺序执行。
进程可以理解为正在运行的程序,多个进程可以并发执行,
一个进程可以启动多个线程,所谓进程的并发可以理解为进程中的线程在并发执行。
并发如何理解?(一个CPU)
1)微观(多个线程顺序执行)
2)宏观(多个线程同时执行)
说明:支持多个进程并发执行的系统称之为多任务操作系统。
2.多线程的应用场合?
当我们需要并发的处理多个任务时,可以考虑使用多个线程。
例如:
1)并发的下载多个文件(多首音乐)
2)并发的加载多张图片(lisview中图片的显示)
3.多线程应用过程中的优势,劣势?
1)优势:提高系统的并发处理能力,改善用户体验。
2)劣势:数据的安全不好控制,代码的调试,维护难度加大。
4.Java 中的线程对象的创建,启动,运行?
Java中线程对象的类型为Thread类型,启动线程需调用
Thread对象的start方法,线程获得cpu执行时,会调用
thread对象的run方法,假如我们有任务要交给线程执行
通常是在thread类的run方法进行调度。
说明:
1)创建(参考构造方法)
a)Thread()
b)Thread(Runnable r)
2)启动(参考start方法)
3)运行(执行run方法,此方法不能自己调用,但可以重写)
/**jvm启动主线程,main方法运行在主线程*/
public
static void main(String[] args) {
new Thread(){//构建线程类型的子类类型对象,重写run方法
public
void run() {
method01();
};//run方法会运行在工作线程(何时执行?)
}.start();//在主线程中创建线程,并启动线程
//主线程启动线程以后可以继续向下顺序执行
new Thread(new Runnable() {//任务(target)
@Override
public
void run() {//此方法如何执行的?
method02();
}
}).start();//线程启动以后,假如获得了cpu会调用线程对象中的run方法
//要求,让以上两个方法并发执行
//记住
//1.线程何时运行存在不确定性
//2.方法运行在哪个线程取决于在哪个线程进行了调用。
//问题?
//一个对象中的不同方法可以运行在不同线程吗?可以
//转换为线程安全(将一个线程不安全转换为线程安全的集合)
list=Collections.synchronizedList(list);
5.Java 中线程对象状态及相关方法?
5.1 线程状态
1)新建状态(例如newThread())
2)就绪状态(例如start())
3)运行状态(例如正在执行run)
4)阻塞状态(例如sleep,i/o)
5)死亡状态(例如线程的run方法运行结束)
5.2 线程相关方法
1)start():启动线程,此时线程处于就绪状态
2)run():线程运行时执行此方法
3)sleep():让当前线程休眠,同时让出CPU
4)setName();给线程设置名字
5)getName();获得线程的名字
6)isAlive():判定线程是否还活着
7)setPriority();设置线程的优先级(1,5,10)
8)setDaemon(true);设置线程为守护线程(启动之前设置)
守护线程一般为服务性线程,当没有其他线程在执行时,
守护线程会自动销毁。
9)join();插入式线程,调用此方法的线程会优先执行。
例如A线程正在执行,此时在A线程的run方法中调用的B
线程的Join方法,此时A线程阻塞,B线程开始执行。
10)currentThread();静态方法获得当前线程
11).......
FAQ?
1)线程对象创建以后,可以调用run方法启动吗?不可以
2)线程对象启动以后,线程会立即执行run方法吗?不确定
3)多个线程可以并发执行吗?可以
4)工作线程中可以启动工作线程码?可以
5)多个线程可以并发执行同一个任务吗?可以
6)..................
---------------------------------------------------
Java 中线程的同步?
1.线程同步概述?
线程同步是多个线程并发执行时,在共享数据集上的互斥与作。互斥是为了保证数据的安全,协作是让多个线程在共享数据集上进行通讯,以确保业务的合理性。
2.线程同步FAQ?
1)为什么多个线程在共享数据集上要互斥执行(排队执行),所有
的操作都要互斥吗?什么情况下进行互斥呢?
2)多线程在共享数据集上的互斥如何实现呢?
3)多线程在共享数据集上通讯的目的是什么,如何实现多线程
之间的通讯?
3.Java 中线程的互斥?
多线程的互斥指的是让多个线程在共享数据集上排队执行:
实现手段:对共享数集加锁,加锁的方式为
1)同步代码块:synchronized (对象锁){}
2)同步方法:
a)public synchronized void method01(){}
实例方法对象锁默认为this。
b)public static synchronized void method02(){}
静态方法对象锁默认为"类名.class"(类对象)
FAQ?
1)使用同步代码块或同步方法会影响代码的执行效率吗?
2)多个线程在并发访问数据集时一定要加锁吗?
不一定,要看共享数据集上的操作是否是原子操作。
回顾:
1)StringBuffer是一个线程安全的StringBuilder
2)Vector是一个线程安全的ArrayList
3)HashTable是一个线程安全的HashMap
说明:现在已经不推荐使用Vetor和HashTable对象了,因为执行的效率比较低,可以考虑将线程不安全集合转换为线程安全集合(例如执行Collections.synchronizedXXX的方法转换集合),也可以率使用java.util.concurrent包下的一些集合,例如ConcurrentHashMap(此对象采用分段加锁方式实现数据安全,Hashtable是对底层哈希表(相当于商场)加锁,ConcurrentHashMap是对底层哈希表分段(相当于商场试衣间)加锁)
静态类
Static01 s1;
s1=new Static01();//第一步会首先检测内存中是否有Static01.class,没有则加载
Static01 s2;
s1=new Static01();//假如内存中已经存在Static01类型,则不在加载
}
//构建类的对象
//1.递归加载类字节码对象(加载内不存在):先加载父类再加载子类
//2.在堆内存分配实例空间
//3.先初始化父类属性,调用父类构造方法
//4.再初始化子类属性,调用子类构造方法
多线程同步中的协作
线程协作构建于线程互斥基础之上,需要借助Object类的
wait,notify,notifyall方法实现,以保证数据业务的合理性。
相关方法含义:
1)wait 调用此方法的线程阻塞,同时释放对象锁
2)notify/notifyall通知具备相同锁并且处于等待状态的线程
开始执行。
方法应用说明:
1)wait,notify,notifyall必须用在同步代码块或同步方法中
2)wait,notify,notifyall必须由对象锁调用
典型案例:生产者消费者应用模型
1)生产者线程对象(负责创建对象或者向容器放数据)
2)消费者线程对象(从容器获得对象)
3)容器对象(存储生产者线程放的数据):要考虑线程安全
要求:生产者可以不断向容器(容器有大小限制)放数据,
消费者可以不断的从容器取数据.
/**代表一个容器对象*/
class Container01{
/**借助此数组存储数据*/
private Object[] data;
/**通过此变量记录数组中有效元素(外界放入的)个数*/
private
int size;
public Container01(int cap) {
data=new Object[cap];
}
/**外界通过此方法向容器放数据:默认放在size位置*/
public
synchronized void put(Object obj){
//1.判定容器是否已满,满了生产者线程则等待
if(data.length==size){
try{this.wait();}catch(Exception e){}
}
//2.放数据
data[size]=obj;
//3.有效元素个数加1
size++;
//4.通知消费者线程取数据
this.notifyAll();
};
/**外界通过此方法取数据*/
public
synchronized Object take(){
//1.判定容器是否是空的,空的则让消费者等待
if(size==0)
try{this.wait();}catch(Exception e){}
//2.取数据(默认从第0个位置开始取)
Object obj=data[0];
//3.移动元素
System.arraycopy(data, 1, data, 0,size-1);
//4.将size-1位置元素设置为null
data[size-1]=null;
//5.有效元素个数减1
size--;
//6.通知生产者线程可以继续放数据
this.notifyAll();
return obj;
}
}
/**生产者线程:放在向container放数据*/
class Producer01 extends Thread{
private Container01 container;
public Producer01(Container01container) {
this.container=container;
}
@Override
public
void run() {
int i=1;
while(true){//不断的放数据
container.put(i++);
}
}
}
/**消费者线程*/
class Consumer01 extends Thread{
private Container01 container;
public Consumer01(Container01container) {
this.container=container;
}
@Override
public
void run() {
while(true){//不断的取数据
Object obj=container.take();
System.out.println("consumer.data="+obj);
try{Thread.sleep(2000);}catch(Exception e){}
}
}
}
public
class ThreadDemo03 {
public
static void main(String[] args) {
//1构建容器
Container01container=new Container01(5);
//2创建生产者对象
Producer01pro=new Producer01(container);
//3创建消费者对象
Consumer01con=new Consumer01(container);
//4.启动线程
pro.start();
con.start();
}
}
回顾:
Collection(List,Set,Queue)中的Queue接口在Android
中的应用非常广泛,尤其是BlockingQueue,BlockingDeque
这两个接口及相关实现类的应用。
---------------------------------------------------
Android 线程消息模型?
1.Android 中多线程应用机制?
1)Android 中所有的UI操作操作(UI更新,事件)都在主线程执行。
2)Android 中所有的耗时操作(例如下载)都应在工作线程执行
Android 系统这样做的目的是提高用户体验,让用户感觉使用
系统时是非常流畅的。
FAQ?
1)工作线程中的数据如何交给主线程?
2)主线程中的数据如何交给工作线程?
2.Android 中的消息模型相关概述?
Android 中的消息模型是实现Android中线程通讯的一种方式,
这种方式的实现依托于如下几个对象:
1)Message (消息对象:负责承载线程间需要传递数据)
2)MessageQueue(消息队列:负责存储多个消息对象)
3)Looper(迭代器:负责迭代消息队列)
4)Handler(处理器:发送和处理消息)
这些对象的伪代码简单实现:
class Message{
Object obj;
int what;
....
}
class MessageQueue{
Message []msg;
}
class Looper{
MessageQueuemsgQ;
public voidloop(){负责执行迭代操作
while(true){....}
}
}
class Handler{
public voidsendMessage(Message msg){}
public voidhandleMessage(Message msg){}
}
3.Android 中的消息模型案例应用?
1)工作线程发消息给主线程,主线程更新UI?
a)确定有工作线程
a1)工作线程要构建消息对象(Message)
a2)工作线程要获得一个handler对象,
此handler必须关联主线程的looper
a3)工作线程要将消息对象发送给主线程
b)确定有主线程
b.1)主线程获得消息对象
b.2)主线程要处理消息对象
lsv=(ListView)findViewById(R.id.lsv);
pBar=new ProgressBar(this);
lsv.addFooterView(pBar);//添加进度条
//lsv.setEmptyView(emptyView);
adapter=new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,data);
lsv.setAdapter(adapter);
loadDataFromNet();//模拟从网络加载数据
}
private
void loadDataFromNet(){
new Thread(){public
void run(){
//模拟正在加载数据
try{sleep(5000);}catch(Exception e){}
//从网络获得的数据(一般为xml或者json)
String dataStr="A/B/C/D";
//解析数据
String array[]=dataStr.split("/");
//将数据更新到页面
data.addAll(Arrays.asList(array));
//runOnUiThread是在主线程执行Runnable对象的run方法
//本质上底层也是借助handler在发送消息
runOnUiThread(new Runnable() {
@Override
public
void run() {//此方法运行在主线程
adapter.notifyDataSetChanged();
lsv.removeFooterView(pBar);
}
});
}}.start();
}
记住:
1)给谁发消息就要获得与谁的looper相关联的handler.
2)主线程默认有一个Looper,此Looper在创建时已经创建
了一个消息队列,用于存储多个消息对象。
3)每个线程最多只有一个Looper,自己构建的工作线程
默认都没有Looper.
Android 线程消息模型应用?
1.工作线程发消息给主线程?
2.主线程发消息给主线程?
1)实现回退操作(几秒内连续点击两次则退出系统)
2)欢迎页面(此页面为进入系统第一个页面,默认停留3秒)
3)系统banner条(广告条)自动滚动(发送延迟消息)
Handler h=new Handler();
h.postDelay(new Runnable(){
public voidrun(){
更新页面
h.postDelay(this,3000);
}
},3000)
3.主线程发送消息给工作线程?
1)工作线程默认没有Looper,需要自己创建looper;
2)主线程需要获得与工作线程Looper关联的handler.
扩展:HandlerThread对象的应用(此对象为一个线程对象
,它封装了Looper的创建及销毁过程,可以简化在工作线程
中对looper的操作);
-------------------------------------------------
Android 消息模型相关API及方法
1.Message(承载数据,数据载体)
1)属性:obj,what,arg1,arg2,...
2)方法:
a)obtainXXX();从消息池获得消息,消息池没有则创建消息对象
b)sendToTarget();底层借助handler发送消息
c)....
2.MessageQueue
3.Looper(迭代器,迭代消息队列)
1)prepare()
2)getMainLooper()
3)myLooper()
4)loop()
5)quit()
6).....
4.Handler(发送,处理消息)
1)sendMessage,sendEmptyMessage,......
2)handleMessage
3)post(...)
4)postDelay(....)
5)........
5.Activity
1)runOnUIThread();运行在主线程
--------------------------------------------------
Android 消息模型相关问题(FAQ)?
1.一个线程对象中可以有多个消息对象吗,此消息对象何时创建?
可以,何时需要何时创建。消息对象的创建方式一般建议
调用Message对象的obtain方法。
2.一个线程有几个消息队列,此消息队列何时创建?
一个线程一个消息队列,此消息队列在Looper创建时创建,
用于存储多个消息对象。
3.一个线程允许有几个Looper,此looper对象何时创建,此
Looper的作用是什么?
一个线程只能有一个Looper.
主线程默认有一个Looper.
其它线程默认没有Looper,需要时可以自己创建。
Looper主要用于在线程内部不断的迭代消息队列,执行任务。
4.一个线程允许有多个handler对象,此handler对象何时创建,
handler的作用是什么?
一个线程允许有多个handler.
handler对象何时需要何时创建。
handler对象的作用是发送消息,处理消息实现线程之间的通讯。
5.HandlerThread是一个什么样的对象,作用是什么?
HandlerThread一个线程对象,主要作用是封装了Looper
对象的操作,并可以在此线程中不断的处理一些耗时操作。
我觉得主线程的设计本质上就是一个HandlerThread.
6.给哪个线程发消息就获得与哪个线程的looper关联的
handler对象,正确吗?正确
----------------------------------------------------
Android中AsyncTask 对象
AsyncTask是Android中的一个工具类,此类实现了对异步
任务处理逻辑的封装,是对消息模型应用技巧的一种巧妙
实现。我们在使用AsyncTask对象时,需要构建此类类型
的子类对象,然后重写相关方法,这些方法有些运行在工
作线程,有些运行在主线程。
AsyncTask 相关泛型(决定类中属性类型,方法参数类型,方法返回值类型)
abstract classAsyncTask<Params,Progress,Result>{}
1)Params
2)Progress
3)Result
AsyncTask 对象相关方法:
1)execute (调用此方法执行任务,这些任务需要排队执行)
2)executeOnExecutor(调用此方法执行任务,这些任务可以并发执行)
3)onPreExecute(主线程,在doInBackground之前执行)
4)doInBackground(工作线程,用于执行耗时操作)
5)onPostExecute(主线程,在doInBackground之后执行)
6)publishProgress(发布进度,一般在工作线程调用)
7)onProgressUpdate(主线程,更新进度)
当调用异步任务的executeXXX方法,启动任务执行时,exexuteXXX
方法中的实际参数值会传递给doInBackground的形式参数。
-----------------------------------------------------
线程池?
1.何为线程池?
1)内存中的一块区域.
2)允许存储多个线程对象。
类似:整数池,字符串池,消息池,。。。
2.线程池应用的目的?
允许线程池中的线程可以重复使用,减少线程对象的
创建及销毁次数,以提高系统的执行效率。
3.线程池的应用场合?
需要反复创建线程,并发执行任务的场合。
例如:
1)同时下载多个文件。
2)同时处理多个用户请求。
4.Java 中线程池相关API?
1.Executor(线程池顶层接口):代表一个线程池对象
1)ExecutorService (接口)
2)ScheduledExecutorService(接口)
3)ThreadPoolExecutor(实现类)
4).....
我们通常可以调用ExecutorService,ScheduledExecutorService
的实现类的类型创建线程对象。
2.Executors(工具类:创建一些简单的线程池对象)
1)创建一个只有一个线程的线程池(newSingleThreadExecutor)
2)创建一个有固定上限的线程池(newFixedThreadPool)
3)创建一个没有固定上限的线程池(newCachedThreadPool)
说明:也可以直接构建ThreadPoolExecutor的对象。
线程池对象创建以后我们可以调用线程池的execute,submit等相关
方法执行任务。
1.FAQ?
Android UI 负责呈现实现与用户的交互,与用户交互时的数据需要借助View去呈现,数据来自何方?
2.Android 中的数据来源?(外存)
1)外置sdcard (非手机自带,可以自行安装)
2)内置sdcard (手机自带,操作系统所在盘符)
3)外置网络服务器(例如云端
3.Android 中数据存储类型?
1)外部存储(外置sdcard的存储):I/O存储
2)内部存储(内置sdcard的存储)
a)直接I/O存储
b)偏好设置存储(SharedPreferencs)
c)SQLite存储(内置数据库系统的存储)
3)网络存储(现阶段不讲)
4.Android
中外部数据存储的实现?
4.1 FAQ?
1)外部存储状态(是否有外置sdcard,是否可用)
2)外部存储路径(数据存储的具体位置)
3)外部存储空间(是否有空间可以存储我们的数据)
4)外部存储权限(是否有权限向指定目录写入数据)
5)外部存储实现(如何向指定路径写入数据)
6)外部存储是否可以实现应用程序私有数据的存储
4.2 API?
1)Environment(sdcard状态,公共存储目录)
2)StatFs(获得指定目录大小)
3)Context(获得应用程序在外置sdcard的私有存储目录)
4) Log.i("TAG",
"privateCacheDir="+privateCacheDir.getPath());//mnt/sdcard/and
4)I/O(读写)
4.3 存储实现?
1)获得外部存储状态?
//1)获得外部存储状态,并判定状态?
//mounted(已挂载)
String state=Environment.getExternalStorageState();
//
Environment.isExternalStorageRemovable()
2)获得外部存储路径?(公有,私有:记得权限)
//2)获得外部存储路径?
//2.1)获得应用程序公有存储目录(例如下载的电影,音乐)
Filesdcard=Environment.getExternalStorageDirectory();
Log.i("TAG","sdcard.path="+sdcard.getPath());//mnt/sdcard
File picDir=Environment.
getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
Log.i("TAG","picDir.path="+picDir.getPath());
roid/data/项目包/cache
//2.2)获得应用程序私有存储目录(应用程序卸载数据也会被删除):必须有写权限
FileprivateDir=getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File privateCacheDir=getExternalCacheDir();//Context
Log.i("TAG",
"privateDir="+privateDir.getPath());//mnt/sdcard/android/data/项目包/files
3)获得外部存储空间大小?
//3)获得存储空间的小,及可用空间大小
StatFs sf=new StatFs(sdcard.getPath());
Log.i("TAG","blockcount="+sf.getBlockCount());
Log.i("TAG","blockSize="+sf.getBlockSize());
Log.i("TAG","sdcard.size="+
(sf.getBlockCount()*sf.getBlockSize()*1.0)/1024/1024);
doubleaSize=(sf.getAvailableBlocks()
*sf.getBlockSize()*1.0)/1024/1024;//M
Log.i("TAG","available.size="+aSize);
4)读写数据(I/O)
//4)向指定目录写入数据
String dataStr="139/123/AAA/A@t.com";
if(dataStr.getBytes().length>=(sf.getAvailableBlocks()*sf.getBlockSize())){
Toast.makeText(this,
"空间不足", 1).show();
return;
}
FileOutputStream fos=null;
try{
fos=new FileOutputStream(new File(
getExternalCacheDir(),"data.txt"));
fos.write(dataStr.getBytes());
Log.i("TAG",
"data write ok!");
}catch(Exception e){
e.printStackTrace();
Log.i("TAG",
"data write error");
}finally{
if(fos!=null)try{fos.close();}catch(Exception
e){}
}
5.Android 中内部数据存储中直接I/O存储实现?
5.1 FAQ?
1)内部存储路径
2)内部存储空间
3)内部存储实现(应用app不需要权限)
//1.获得存储目录?(Environment,Context)
Log.i("TAG",
"rootDir="+Environment.getRootDirectory());//system
Log.i("TAG",
"dataDir="+Environment.getDataDirectory());///data
Log.i("TAG",
"downCache="+
Environment.getDownloadCacheDirectory());///cache
Log.i("TAG","fileDir="+getFilesDir());///data/data/项目包/files
Log.i("TAG",
"cacheDir="+getCacheDir());///data/data/项目包/cache
//2.获得空间大小?(自己写)StatFS
//3.实现存储?
StringdataStr="139/123/AAA/A@t.com";
FileOutputStreamfos=null;
try{
fos=new FileOutputStream(new File(
getFilesDir(),
"data.txt"));
fos.write(dataStr.getBytes());
Log.i("TAG",
"datawrite ok!");
}catch(Exception e){
e.printStackTrace();
Log.i("TAG",
"datawrite error");
}finally{
if(fos!=null)try{fos.close();}catch(Exception
e){}
}
}
5.2 API?
1)Environment
2)Context
a)getFileDir() :data/data/项目包/files
b)getCacheDir():data/data/项目包/cache
c)openFileInput
b)openFileOutput
3)I/O
5.3 内部存储实现?
1)内部存储目录
a)getFileDir
b)getCacheDir
2)内部存储空间大小?(自己尝试)
3)内部存储直接I/O操作(读,写)
案例:获得应用程序缓存目录?
1)首先考虑外部存储目录
2)其次考虑内部存储目录
public File getImageCacheDir(){
//.......
}
6.Android 中内部存储偏好设置的实现?
6.1 FAQ?
1)何为偏好设置(用户喜好信息)
2)偏好设置存储目录(/data/data/项目包/share_prefs)
3)偏好设置存储的实现?
6.2 API?
1)Context
2)SharedPreferences
3)Editor
6.3 存储实现
1)获得SharedPreferences 对象(借助context)
2)读数据(调用对象的getXXX方法读)
3)写数据(获得Editor对象),借助此对象写数据
3.1)获得Editor对象(edit())
3.2)调用Editor的putXXX方法写数据(先存到内存)
3.3)提交数据(commit,将内存数据写到外存)
private
void saveDataToPrefs(){
//1.获得SharedPreferences对象
SharedPreferencessp=
getSharedPreferences("config",//文件名,config.xml
Context.MODE_PRIVATE);//文件操作模式(私有)
//2.获得editor对象
Editoret=sp.edit();
//3.存储数据
et.putBoolean("isUsed",true);//key/value
//et.putInt("count", 10);
et.putString("phone",
"138");
et.commit();//数据的持久化(此时文件不存则会创建,文件存在则更新)
Log.i("TAG",
"prefswrite ok!");
}
private
void getDataFromPrefs(){
//1.获得SharedPreferences对象
SharedPreferencessp=
getSharedPreferences("config",Context.MODE_PRIVATE);
//2.获得文件中数据
boolean isUsed=sp.getBoolean("isUsed",
false);
//int count=sp.getInt("count", -1);
Log.i("TAG",
"isUsed="+isUsed);
//Log.i("TAG", "count="+count);
}
}
6.4 偏好设置案例(系统设置页面的定制)登录记录账号密码
// 初始化SharePreferenecs
sp = getSharedPreferences("user", Context.MODE_PRIVATE);
cb = (CheckBox) findViewById(R.id.cb_1);
et_01 = (EditText) findViewById(R.id.phoneId);
et_02 = (EditText) findViewById(R.id.pwdId);
but = (Button) findViewById(R.id.logonId);
// 获得复选框的选中状态
boolean
isChecked = sp.getBoolean("isCb",
false);
// 通过获得复选框状态设置到复选框上
cb.setChecked(isChecked);
if (isChecked) {
// 在初始化控件时获得偏好设置的数据
name =
sp.getString("name",
"");
pwd =
sp.getString("pwd",
"");
// 将获得数据设置到输入框中
et_01.setText(name);
et_02.setText(pwd);
} else {
// 清空输入框中内容
et_01.setText("");
et_02.setText("");
}
}
private
void setListener() {
but.setOnClickListener(new OnClickListener() {
@Override
public
void onClick(View v) {
name=et_01.getText().toString();
pwd =
et_02.getText().toString();
Editoredit =
sp.edit();
if (cb.isChecked()){
// 保存数据
edit.putString("name",
name);
edit.putString("pwd",
pwd);
edit.putBoolean("isCb",
true);
} else {
edit.putBoolean("isCb",
false);
// 自行完成复选框不被选择的事件
}
edit.commit();
1)定义xml(res/xml/filename.xml)
2)加载xml(.....)
class SettingActivity extends PrefenceActivity{
onCreate(){
addPreferencesFromResource(R.xml.settings);
}
}
3)其它页面读取xml(借助SharedPrefences对象)
说明:以后做配置页面时通常会考虑使用fragment对象
SQLite 存储(内部存储)
1.SQlite 是什么?
1)软件(Software):开源,体积小,适合便携式设备(例如手机)
2)数据库管理系统(DBMS)
2.SQLite 应用场合?
1)更好的存储数据
2)更好的管理数据
3)提高数据的安全
FAQ?
1)将数据直接存储到一些文件有什么缺陷吗?
a)安全性相对较差
b)更新和查询效率较低
c)易读性相对较差
2)SQLite 存储数据的形式是怎样?
1)SQLite 是一个DBMS,此系统可以管理多个数据库(DB)
2)SQLite 中的一个DB可以存储多张二维表(行,列)
3)SQLite 中表(table)是数据的最基本存储单元,DB中
所有数据都是要存储在表中的,表中行通常称之为记录,
表中列通常称之为字段或数据项。
Android 和 IOS 目前的系统中都内置了SQLite数据库。
android 平台架构:
Application (AP):java 应用层
Application FrameWork (AF):java 框架
Libraries(SQLite,...)+虚拟机类库
Linux 内核系统
3.SQLite 在Android
中的应用?
3.1 FAQ?
1)Android 中有几个内置SQLite?(1个)
2)Android 系统中有内置的数据库(DB)?(有)
a)联系人
b)媒体库
c)便签(备忘录)
3)Android 中如何操作SQLite数据库?
1)java(api)
2)sql(结构化查询语言)
3.2 API?
1)Context(资源访问对象)
2)SQLiteDatabase (发送SQL,将sql语句发送到SQLite端)
3)SimpleCursorAdapter(将Cursor中的数据构建成item)
4)SQLiteOpenHelper (工具类,抽象类)
3.3 SQL?(基本应用)
1)DDL(数据定义语言):create,alter,drop,...
2)DML(数据操纵语言):insert,update,delete,select,...
3)DCL(数据控制语言):commit,rollback,......
3.4 SQLite 应用的基本步骤?
1)获得SQLiteDatabase对象
2)借助SQLiteDatabase对象发送SQL
3)释放资源(Cursor,SQLiteDatabase)
private SQLiteDatabase sdb;
/**创建或打开数据库*/
public
void createOrOpenDB(View v){
//借助context的方法创建或打开数据库,不存在则创建,存在则打开
sdb=openOrCreateDatabase(
"contacts.db",//数据库名称
Context.MODE_PRIVATE,//数据库操作模式
null);//CursorFactory
Log.i("TAG",
"contacts.dbcreated or opend");
}
/**创建一张表*/
public
void createTable(View v){
//定义SQL
Stringsql="create table if not exists contact("
+ "_id integer primary key autoincrement,"
+ "phone text not null,"
+ "name text)";
//发送SQL
sdb.execSQL(sql);
Log.i("TAG",
"contactcreated ok");
}
/**向表中写入数据*/
public
void insertTable(View v){
//1.方案1
/* String sql1="insert into contact "
+ "values (null,'139','A0')";
sdb.execSQL(sql1);*/
//2.方案2
/*String sql2="insert into contact (phone,name)"
+" values ('137','A1')";
sdb.execSQL(sql2);*/
//3.方案3
/* String sql3="insert into contact "
+" values (null,?,?)";//"?"代表占位符
sdb.execSQL(sql3,newObject[]{"138","A2"});
*/
//4.方案4
ContentValuesvalues=new ContentValues();//值对象
values.put("phone",
"135");//key 是列的名字
//values.put("name", "A3");//允许为空的列可以不给值
sdb.insert(
"contact",//tableName
null,//nullColumnHack
values);//底层自动拼接sql
Log.i("TAG",
"insertok!");
}
/**从表中查询数据*/
public
void queryTable(View v){
//1.方案1 (查询所有行所有列)
/* Stringsql="select * from contact";
Cursorc=sdb.rawQuery(sql, null);*/
//2.方案2
/*String sql="select * from contact where _id=?";
Cursorc=sdb.rawQuery(sql,new String[]{"1"});*/
/*String sql="select * from contact where phone like ?order by _id desc";
Cursorc=sdb.rawQuery(sql,new String[]{"%13%"});*/
//3.方案3:
Cursorc=sdb.query("contact",
//table
null,//columns(要查询的列,null代表所有列)
"phone like?",
//selection为where 子句
new String[]{"%3%"},
//selectionArgs为where子句?的值
null,//groupBy表示分组
null,//having表示分组以后的限制条件
"_iddesc");//desc表示降序
//取数据
if(c==null){
Log.i("TAG",
"query error");
return;
}
if(!c.moveToFirst()){
Log.i("TAG",
"no data");
return;
}
do{
Log.i("TAG",
c.getInt(c.getColumnIndex("_id"))+"/"+
c.getString(c.getColumnIndex("phone"))+"/"+
c.getString(c.getColumnIndex("name")));
}while(c.moveToNext());//循环一次取一行
//释放资源
c.close();
}
/**修改表中数据*/
public
void updateTable(View v){
//1.方案1
/* String sql="update contact set name=?where _id=?";
sdb.execSQL(sql,newObject[]{"A3","4"});*/
//2.方案2
ContentValuesvalues=new ContentValues();
values.put("name",
"A3");
sdb.update("contact", values,
"_id=?", new String[]{"4"});
Log.i("TAG",
"updateok!");
}
/**删除表中数据*/
public
void deleteTable(View v){
//1.方案1
/*String sql="delete from contact where _id=?";
sdb.execSQL(sql,newObject[]{"4"});*/
//2.方案2
sdb.delete("contact",
"_id=?", new String[]{"4"});
Log.i("TAG",
"deleteOK!");
}
/**删除表*/
public
void dropTable(View v){
Stringsql="drop table if exists contact";
sdb.execSQL(sql);
Log.i("TAG",
"droptable");
}
/**activity销毁时执行*/
@Override
protected
void onDestroy() {
// TODO Auto-generated methodstub
super.onDestroy();
if(sdb!=null)sdb.close();
}
在ListView上显示数据库
//1.获得listview
ListViewlsv=(ListView) findViewById(R.id.lsv);
//2.构建适配器(SimpleCursorAdapter)
//2.1 item data(借助cursor对象获得数据)
sdb=openOrCreateDatabase("contacts.db",Context.MODE_PRIVATE,null);
cursor=sdb.rawQuery("select * from contact",
null);
//2.2 item view
int resourceId=android.R.layout.simple_list_item_2;
//2.3 构建适配器
adapter=new SimpleCursorAdapter(this,
resourceId,
cursor,
new String[]{"_id","phone"},
new
int[]{android.R.id.text1,android.R.id.text2},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);//注册观察者(监测数据源的变化)
//3.关联适配器
lsv.setAdapter(adapter);
//4.注册上下文菜单
registerForContextMenu(lsv);
}
@Override
public
void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfomenuInfo) {
menu.add(0,100, 101, "删除");
}
@Override
public
boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfoacm=
(AdapterContextMenuInfo)
item.getMenuInfo();
if(item.getItemId()==100){
//1.获得要删除的数据id
long id=acm.id;//记录的主键值,现在不等于item的position
//2.执行删除动作
sdb.delete("contact","_id=?",new String[]{String.valueOf(id)});
//3.更新listview
cursor=sdb.rawQuery("select * from contact",null);
adapter.changeCursor(cursor);
}
return
super.onContextItemSelected(item);
}
/**activity销毁时执行此方法*/
@Override
protected
void onDestroy() {
super.onDestroy();
if(cursor!=null)cursor.close();
if(sdb!=null)sdb.close();
}
创建一个操作数据库的类
private DBHelper
db;
private SQLiteDatabase
sdb;
public SQLiteDatabase getSdb() {
return
sdb;
}
public
void setSdb(SQLiteDatabase sdb) {
this.sdb =
sdb;
}
public NoteProvider(Context
context) {
db=new DBHelper(context,"notepads" ,
null, 1);
sdb = db.getWritableDatabase();
}
/**返回值为插入记录的主键值*/
public
long insert(String table,ContentValues
values){
//1.创建或打开数据库
//2.写入数据
long
id=sdb.insert(table,
null,
values);
//3.释放资源
sdb.close();
return
id;
}
/**
* 查询全部数据
* @return
*/
public Cursor chaxun (){
Cursor c =
sdb.rawQuery("select* from notetab",
null);
return
c;
}
/**
* 按条件查询数据
* */
public Cursor chaxun1(String
table,String whereClause,String []whereArgs){
//2.执行查询动作
return
sdb.query(table,null,
whereClause, whereArgs,null,
null, null);
}
class DBHelper
extends SQLiteOpenHelper{
public DBHelper(Context
context, String name, CursorFactory
factory, int
version) {
super(context,
name, factory,
version);
// TODO Auto-generated constructor stub
}
/**
* 此方法在数据库创建时执行,此方法中做什么有业务而定,一般可以创建一些表
*/
@Override
public
void onCreate(SQLiteDatabase db) {
String sql="create table if not existsnotetab(_id integer primary key autoincrement, content text not null,createnttext not null)";
db.execSQL(sql);
}
/**
* 此方法在版本升级是执行
*/
@Override
public
void onUpgrade(SQLiteDatabase db,
int
oldVersion, int
newVersion) {
// TODO Auto-generated method stub
}
Android 中线程应用基础?
1.线程概述?(线程是什么)
线程是进程中的一个顺序的执行流,在程序中表现为一个
对象,多个这样的对象可以并发执行。但是一个线程内部的多个操作肯定是顺序执行。
进程可以理解为正在运行的程序,多个进程可以并发执行,
一个进程可以启动多个线程,所谓进程的并发可以理解为进程中的线程在并发执行。
并发如何理解?(一个CPU)
1)微观(多个线程顺序执行)
2)宏观(多个线程同时执行)
说明:支持多个进程并发执行的系统称之为多任务操作系统。
2.多线程的应用场合?
当我们需要并发的处理多个任务时,可以考虑使用多个线程。
例如:
1)并发的下载多个文件(多首音乐)
2)并发的加载多张图片(lisview中图片的显示)
3.多线程应用过程中的优势,劣势?
1)优势:提高系统的并发处理能力,改善用户体验。
2)劣势:数据的安全不好控制,代码的调试,维护难度加大。
4.Java 中的线程对象的创建,启动,运行?
Java中线程对象的类型为Thread类型,启动线程需调用
Thread对象的start方法,线程获得cpu执行时,会调用
thread对象的run方法,假如我们有任务要交给线程执行
通常是在thread类的run方法进行调度。
说明:
1)创建(参考构造方法)
a)Thread()
b)Thread(Runnable r)
2)启动(参考start方法)
3)运行(执行run方法,此方法不能自己调用,但可以重写)
/**jvm启动主线程,main方法运行在主线程*/
public
static void main(String[] args) {
new Thread(){//构建线程类型的子类类型对象,重写run方法
public
void run() {
method01();
};//run方法会运行在工作线程(何时执行?)
}.start();//在主线程中创建线程,并启动线程
//主线程启动线程以后可以继续向下顺序执行
new Thread(new Runnable() {//任务(target)
@Override
public
void run() {//此方法如何执行的?
method02();
}
}).start();//线程启动以后,假如获得了cpu会调用线程对象中的run方法
//要求,让以上两个方法并发执行
//记住
//1.线程何时运行存在不确定性
//2.方法运行在哪个线程取决于在哪个线程进行了调用。
//问题?
//一个对象中的不同方法可以运行在不同线程吗?可以
//转换为线程安全(将一个线程不安全转换为线程安全的集合)
list=Collections.synchronizedList(list);
5.Java 中线程对象状态及相关方法?
5.1 线程状态
1)新建状态(例如newThread())
2)就绪状态(例如start())
3)运行状态(例如正在执行run)
4)阻塞状态(例如sleep,i/o)
5)死亡状态(例如线程的run方法运行结束)
5.2 线程相关方法
1)start():启动线程,此时线程处于就绪状态
2)run():线程运行时执行此方法
3)sleep():让当前线程休眠,同时让出CPU
4)setName();给线程设置名字
5)getName();获得线程的名字
6)isAlive():判定线程是否还活着
7)setPriority();设置线程的优先级(1,5,10)
8)setDaemon(true);设置线程为守护线程(启动之前设置)
守护线程一般为服务性线程,当没有其他线程在执行时,
守护线程会自动销毁。
9)join();插入式线程,调用此方法的线程会优先执行。
例如A线程正在执行,此时在A线程的run方法中调用的B
线程的Join方法,此时A线程阻塞,B线程开始执行。
10)currentThread();静态方法获得当前线程
11).......
FAQ?
1)线程对象创建以后,可以调用run方法启动吗?不可以
2)线程对象启动以后,线程会立即执行run方法吗?不确定
3)多个线程可以并发执行吗?可以
4)工作线程中可以启动工作线程码?可以
5)多个线程可以并发执行同一个任务吗?可以
6)..................
---------------------------------------------------
Java 中线程的同步?
1.线程同步概述?
线程同步是多个线程并发执行时,在共享数据集上的互斥与作。互斥是为了保证数据的安全,协作是让多个线程在共享数据集上进行通讯,以确保业务的合理性。
2.线程同步FAQ?
1)为什么多个线程在共享数据集上要互斥执行(排队执行),所有
的操作都要互斥吗?什么情况下进行互斥呢?
2)多线程在共享数据集上的互斥如何实现呢?
3)多线程在共享数据集上通讯的目的是什么,如何实现多线程
之间的通讯?
3.Java 中线程的互斥?
多线程的互斥指的是让多个线程在共享数据集上排队执行:
实现手段:对共享数集加锁,加锁的方式为
1)同步代码块:synchronized (对象锁){}
2)同步方法:
a)public synchronized void method01(){}
实例方法对象锁默认为this。
b)public static synchronized void method02(){}
静态方法对象锁默认为"类名.class"(类对象)
FAQ?
1)使用同步代码块或同步方法会影响代码的执行效率吗?
2)多个线程在并发访问数据集时一定要加锁吗?
不一定,要看共享数据集上的操作是否是原子操作。
回顾:
1)StringBuffer是一个线程安全的StringBuilder
2)Vector是一个线程安全的ArrayList
3)HashTable是一个线程安全的HashMap
说明:现在已经不推荐使用Vetor和HashTable对象了,因为执行的效率比较低,可以考虑将线程不安全集合转换为线程安全集合(例如执行Collections.synchronizedXXX的方法转换集合),也可以率使用java.util.concurrent包下的一些集合,例如ConcurrentHashMap(此对象采用分段加锁方式实现数据安全,Hashtable是对底层哈希表(相当于商场)加锁,ConcurrentHashMap是对底层哈希表分段(相当于商场试衣间)加锁)
静态类
Static01 s1;
s1=new Static01();//第一步会首先检测内存中是否有Static01.class,没有则加载
Static01 s2;
s1=new Static01();//假如内存中已经存在Static01类型,则不在加载
}
//构建类的对象
//1.递归加载类字节码对象(加载内不存在):先加载父类再加载子类
//2.在堆内存分配实例空间
//3.先初始化父类属性,调用父类构造方法
//4.再初始化子类属性,调用子类构造方法
多线程同步中的协作
线程协作构建于线程互斥基础之上,需要借助Object类的
wait,notify,notifyall方法实现,以保证数据业务的合理性。
相关方法含义:
1)wait 调用此方法的线程阻塞,同时释放对象锁
2)notify/notifyall通知具备相同锁并且处于等待状态的线程
开始执行。
方法应用说明:
1)wait,notify,notifyall必须用在同步代码块或同步方法中
2)wait,notify,notifyall必须由对象锁调用
典型案例:生产者消费者应用模型
1)生产者线程对象(负责创建对象或者向容器放数据)
2)消费者线程对象(从容器获得对象)
3)容器对象(存储生产者线程放的数据):要考虑线程安全
要求:生产者可以不断向容器(容器有大小限制)放数据,
消费者可以不断的从容器取数据.
/**代表一个容器对象*/
class Container01{
/**借助此数组存储数据*/
private Object[] data;
/**通过此变量记录数组中有效元素(外界放入的)个数*/
private
int size;
public Container01(int cap) {
data=new Object[cap];
}
/**外界通过此方法向容器放数据:默认放在size位置*/
public
synchronized void put(Object obj){
//1.判定容器是否已满,满了生产者线程则等待
if(data.length==size){
try{this.wait();}catch(Exception e){}
}
//2.放数据
data[size]=obj;
//3.有效元素个数加1
size++;
//4.通知消费者线程取数据
this.notifyAll();
};
/**外界通过此方法取数据*/
public
synchronized Object take(){
//1.判定容器是否是空的,空的则让消费者等待
if(size==0)
try{this.wait();}catch(Exception e){}
//2.取数据(默认从第0个位置开始取)
Object obj=data[0];
//3.移动元素
System.arraycopy(data, 1, data, 0,size-1);
//4.将size-1位置元素设置为null
data[size-1]=null;
//5.有效元素个数减1
size--;
//6.通知生产者线程可以继续放数据
this.notifyAll();
return obj;
}
}
/**生产者线程:放在向container放数据*/
class Producer01 extends Thread{
private Container01 container;
public Producer01(Container01container) {
this.container=container;
}
@Override
public
void run() {
int i=1;
while(true){//不断的放数据
container.put(i++);
}
}
}
/**消费者线程*/
class Consumer01 extends Thread{
private Container01 container;
public Consumer01(Container01container) {
this.container=container;
}
@Override
public
void run() {
while(true){//不断的取数据
Object obj=container.take();
System.out.println("consumer.data="+obj);
try{Thread.sleep(2000);}catch(Exception e){}
}
}
}
public
class ThreadDemo03 {
public
static void main(String[] args) {
//1构建容器
Container01container=new Container01(5);
//2创建生产者对象
Producer01pro=new Producer01(container);
//3创建消费者对象
Consumer01con=new Consumer01(container);
//4.启动线程
pro.start();
con.start();
}
}
回顾:
Collection(List,Set,Queue)中的Queue接口在Android
中的应用非常广泛,尤其是BlockingQueue,BlockingDeque
这两个接口及相关实现类的应用。
---------------------------------------------------
Android 线程消息模型?
1.Android 中多线程应用机制?
1)Android 中所有的UI操作操作(UI更新,事件)都在主线程执行。
2)Android 中所有的耗时操作(例如下载)都应在工作线程执行
Android 系统这样做的目的是提高用户体验,让用户感觉使用
系统时是非常流畅的。
FAQ?
1)工作线程中的数据如何交给主线程?
2)主线程中的数据如何交给工作线程?
2.Android 中的消息模型相关概述?
Android 中的消息模型是实现Android中线程通讯的一种方式,
这种方式的实现依托于如下几个对象:
1)Message (消息对象:负责承载线程间需要传递数据)
2)MessageQueue(消息队列:负责存储多个消息对象)
3)Looper(迭代器:负责迭代消息队列)
4)Handler(处理器:发送和处理消息)
这些对象的伪代码简单实现:
class Message{
Object obj;
int what;
....
}
class MessageQueue{
Message []msg;
}
class Looper{
MessageQueuemsgQ;
public voidloop(){负责执行迭代操作
while(true){....}
}
}
class Handler{
public voidsendMessage(Message msg){}
public voidhandleMessage(Message msg){}
}
3.Android 中的消息模型案例应用?
1)工作线程发消息给主线程,主线程更新UI?
a)确定有工作线程
a1)工作线程要构建消息对象(Message)
a2)工作线程要获得一个handler对象,
此handler必须关联主线程的looper
a3)工作线程要将消息对象发送给主线程
b)确定有主线程
b.1)主线程获得消息对象
b.2)主线程要处理消息对象
lsv=(ListView)findViewById(R.id.lsv);
pBar=new ProgressBar(this);
lsv.addFooterView(pBar);//添加进度条
//lsv.setEmptyView(emptyView);
adapter=new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,data);
lsv.setAdapter(adapter);
loadDataFromNet();//模拟从网络加载数据
}
private
void loadDataFromNet(){
new Thread(){public
void run(){
//模拟正在加载数据
try{sleep(5000);}catch(Exception e){}
//从网络获得的数据(一般为xml或者json)
String dataStr="A/B/C/D";
//解析数据
String array[]=dataStr.split("/");
//将数据更新到页面
data.addAll(Arrays.asList(array));
//runOnUiThread是在主线程执行Runnable对象的run方法
//本质上底层也是借助handler在发送消息
runOnUiThread(new Runnable() {
@Override
public
void run() {//此方法运行在主线程
adapter.notifyDataSetChanged();
lsv.removeFooterView(pBar);
}
});
}}.start();
}
记住:
1)给谁发消息就要获得与谁的looper相关联的handler.
2)主线程默认有一个Looper,此Looper在创建时已经创建
了一个消息队列,用于存储多个消息对象。
3)每个线程最多只有一个Looper,自己构建的工作线程
默认都没有Looper.
Android 线程消息模型应用?
1.工作线程发消息给主线程?
2.主线程发消息给主线程?
1)实现回退操作(几秒内连续点击两次则退出系统)
2)欢迎页面(此页面为进入系统第一个页面,默认停留3秒)
3)系统banner条(广告条)自动滚动(发送延迟消息)
Handler h=new Handler();
h.postDelay(new Runnable(){
public voidrun(){
更新页面
h.postDelay(this,3000);
}
},3000)
3.主线程发送消息给工作线程?
1)工作线程默认没有Looper,需要自己创建looper;
2)主线程需要获得与工作线程Looper关联的handler.
扩展:HandlerThread对象的应用(此对象为一个线程对象
,它封装了Looper的创建及销毁过程,可以简化在工作线程
中对looper的操作);
-------------------------------------------------
Android 消息模型相关API及方法
1.Message(承载数据,数据载体)
1)属性:obj,what,arg1,arg2,...
2)方法:
a)obtainXXX();从消息池获得消息,消息池没有则创建消息对象
b)sendToTarget();底层借助handler发送消息
c)....
2.MessageQueue
3.Looper(迭代器,迭代消息队列)
1)prepare()
2)getMainLooper()
3)myLooper()
4)loop()
5)quit()
6).....
4.Handler(发送,处理消息)
1)sendMessage,sendEmptyMessage,......
2)handleMessage
3)post(...)
4)postDelay(....)
5)........
5.Activity
1)runOnUIThread();运行在主线程
--------------------------------------------------
Android 消息模型相关问题(FAQ)?
1.一个线程对象中可以有多个消息对象吗,此消息对象何时创建?
可以,何时需要何时创建。消息对象的创建方式一般建议
调用Message对象的obtain方法。
2.一个线程有几个消息队列,此消息队列何时创建?
一个线程一个消息队列,此消息队列在Looper创建时创建,
用于存储多个消息对象。
3.一个线程允许有几个Looper,此looper对象何时创建,此
Looper的作用是什么?
一个线程只能有一个Looper.
主线程默认有一个Looper.
其它线程默认没有Looper,需要时可以自己创建。
Looper主要用于在线程内部不断的迭代消息队列,执行任务。
4.一个线程允许有多个handler对象,此handler对象何时创建,
handler的作用是什么?
一个线程允许有多个handler.
handler对象何时需要何时创建。
handler对象的作用是发送消息,处理消息实现线程之间的通讯。
5.HandlerThread是一个什么样的对象,作用是什么?
HandlerThread一个线程对象,主要作用是封装了Looper
对象的操作,并可以在此线程中不断的处理一些耗时操作。
我觉得主线程的设计本质上就是一个HandlerThread.
6.给哪个线程发消息就获得与哪个线程的looper关联的
handler对象,正确吗?正确
----------------------------------------------------
Android中AsyncTask 对象
AsyncTask是Android中的一个工具类,此类实现了对异步
任务处理逻辑的封装,是对消息模型应用技巧的一种巧妙
实现。我们在使用AsyncTask对象时,需要构建此类类型
的子类对象,然后重写相关方法,这些方法有些运行在工
作线程,有些运行在主线程。
AsyncTask 相关泛型(决定类中属性类型,方法参数类型,方法返回值类型)
abstract classAsyncTask<Params,Progress,Result>{}
1)Params
2)Progress
3)Result
AsyncTask 对象相关方法:
1)execute (调用此方法执行任务,这些任务需要排队执行)
2)executeOnExecutor(调用此方法执行任务,这些任务可以并发执行)
3)onPreExecute(主线程,在doInBackground之前执行)
4)doInBackground(工作线程,用于执行耗时操作)
5)onPostExecute(主线程,在doInBackground之后执行)
6)publishProgress(发布进度,一般在工作线程调用)
7)onProgressUpdate(主线程,更新进度)
当调用异步任务的executeXXX方法,启动任务执行时,exexuteXXX
方法中的实际参数值会传递给doInBackground的形式参数。
-----------------------------------------------------
线程池?
1.何为线程池?
1)内存中的一块区域.
2)允许存储多个线程对象。
类似:整数池,字符串池,消息池,。。。
2.线程池应用的目的?
允许线程池中的线程可以重复使用,减少线程对象的
创建及销毁次数,以提高系统的执行效率。
3.线程池的应用场合?
需要反复创建线程,并发执行任务的场合。
例如:
1)同时下载多个文件。
2)同时处理多个用户请求。
4.Java 中线程池相关API?
1.Executor(线程池顶层接口):代表一个线程池对象
1)ExecutorService (接口)
2)ScheduledExecutorService(接口)
3)ThreadPoolExecutor(实现类)
4).....
我们通常可以调用ExecutorService,ScheduledExecutorService
的实现类的类型创建线程对象。
2.Executors(工具类:创建一些简单的线程池对象)
1)创建一个只有一个线程的线程池(newSingleThreadExecutor)
2)创建一个有固定上限的线程池(newFixedThreadPool)
3)创建一个没有固定上限的线程池(newCachedThreadPool)
说明:也可以直接构建ThreadPoolExecutor的对象。
线程池对象创建以后我们可以调用线程池的execute,submit等相关
方法执行任务。
相关文章推荐
- 白话空间统计番外二:空间统计与空间分析的区别(ArcGIS中)
- 关于Androidstudio的安装以及配置时候的注意事项
- scikit-learn : 优化岭回归参数alpha优化
- Unable to load native-hadoop library for your platform... using builtin-
- 逻辑回归
- 字符串按照单词为单位逆序排列
- Andrew NG 《machine learning》week 3,class5 —Solving the Problem of Overfitting
- 20150418多线程、指针与数组、结构体
- 用NSZombieEnabled解决恼人的EXC_BAD_ACCESS错误
- 剑指offer——滑动窗口的最大值
- 关于多线程GCD,小白必须知道的常用函数
- 大话设计模式-Chapter2策略模式
- Linux C 指针练习
- Collections类
- Storm架构分析
- iOS 美丽说瀑布流界面纯AutoLayout光速布局
- pom.xml常用元素介绍
- Ldap介绍
- Java - PAT - 1011. A+B和C (15)
- Android 自定义View 跳动的水果和文字