您的位置:首页 > 其它

数据存储,线程的知识总结

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等相关

方法执行任务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: