怎样的SqlConnection管理的IsolationLevel

怎样的SqlConnection管理的IsolationLevel,第1张

这MSDN文章指出:

隔离级别具有连接性的

范围,一旦为连接设置

用SET TRANSACTION ISOLATION

LEVEL它仍然有效

直到连接被关闭或

另一个隔离级别设置。当

连接关闭,并返回到

池,从隔离级别

最后SET TRANSACTION ISOLATION LEVEL

被保留。随后

一个连接池

隔离级别

那是在生效的本

连接池。

SqlConnection类有一个可容纳隔离级别。那么,如何连接知道什么隔离级别中运行???

我问这个的原因是以下情形的:

我打开一

在TransactionScope的序列化

模式,说“T1”。

开为T1的连接。

T1结束/处置,连接

追溯到连接池。

呼吁其他查询

连接(从获得后

连接池)和该查询运行

在可序列化的模式!

问题:

如何汇集连接仍然

知道什么隔离级别是

关联呢???

如何将其恢复为其他

事务级???

分辨率:

为什么池连接正在返回的串行化隔离级别的原因是由于以下原因:

你有一个连接池(比方说CP1)

CP1可能有50个连接。

你从CP1选择一个连接C1和序列化执行它。这种连接有其隔离级别设置完毕。

不管你做什么 CodeGo.net,这不会被复位(除非该连接是

用于在不同的隔离级别执行代码)。

执行查询C1(序列化)后,可以追溯到CP1。

如果步骤1-4,再次执行,那么将可能会比其他的C1连接,比方说,C2或C3。所以,这也将

有其隔离级别设置为可序列化。

因此,慢慢地,Serialzable被设置为在CP1多个连接。

当您执行在没有明确的隔离级别设置正在做一个查询,从CP1挑连接将决定

隔离级别。对于如如果这样的查询请求的连接

和CP1用C1(序列化)来执行该查询,然后这个查询

在串行化模式,即使你没有明确地将执行

设置它。

希望清除的几个疑点。 :)

本文地址 :CodeGo.net/199351/

-------------------------------------------------------------------------------------------------------------------------

1. 隔离级别是基础DBMS,说SqlServer的。设置隔离级别最有可能设置里面设置的隔离级别连接。

数据库管理系统保持隔离级别,只要连接保持打开状态。连接被放入池中,它保持打开状态,并保持之前的设定。

带隔离左右的水平,您应该重新设定隔离级别在任何交易结束时,或者甚至更好 CodeGo.net,将其设置在请求一个新的连接。

2.

SqlConnection.BeginTransaction接受一个IsolationLevel这是如何控制的SqlClient连接的隔离级别。另一种选择是通用的System.Transactions并指定隔离级别TransactionOptions.IsolationLevel传

递给在TransactionScope的构造函数。无论是在的SqlClient和System.Transactions的编程模型的隔离级别,必须

显式地为每个事务中指定。如果没有指定,则默认会(读已提交的的SqlClient,序列化的System.Transactions的)。

池连接不盲目,他们已经隐藏轨迹像当前事务的当前状态,等待结果等,并在可以清理一个连接返回到池中。只是状态是不是在编程模型暴露,这不是“不存在(这

适用于任何库类,任何类的设计者可以下internal伞)。

最后从池中的任何方面,它调用sp_reset_connection这是清理在服务器端的会话状态的服务器。

3.

它不隔离级别返回到原来的值.a个实体需要一个空的事务重置水平(虽然它apparentently不需要(否定的。完成()需要的话)。

试图改变这个iso数据库服务器上的SP不起作用。输出:

前:提交读取

期间:序列化

后:序列化

复位由SP尝试后:序列化

复位时通过XACT:提交读取

复位由XACT后:提交读取

// using Dbg = System.Diagnostics.Debug

XactIso.iso isoEntity = new XactIso.iso()

using (isoEntity)

{

Dbg.WriteLine("Before: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault())

var xactOpts = new TransactionOptions()

xactOpts.IsolationLevel = System.Transactions.IsolationLevel.Serializable

using (TransactionScope xact = new TransactionScope(TransactionScopeOption.Required, xactOpts))

{

Dbg.WriteLine("During: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault())

xact.Complete()

}

Dbg.WriteLine("After: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault())

isoEntity.usp_SetXactIsoLevel("ReadCommitted")

Dbg.WriteLine("After Reset by SP Attempt: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault())

// failed

var xactOpts2 = new TransactionOptions()

xactOpts2.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted

using (TransactionScope xact2 = new TransactionScope(TransactionScopeOption.Required, xactOpts2))

Dbg.WriteLine("During Reset by XACT: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault())

// works w/o commit

Dbg.WriteLine("After Reset by XACT: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault())

}

其中来自链接

proc [Common].[usp_GetXactIsoLevel]

as

begin

select

case transaction_isolation_level

WHEN 0 THEN 'Unspecified'

WHEN 1 THEN 'ReadUncommitted'

WHEN 2 THEN 'ReadCommitted'

WHEN 3 THEN 'RepeatableRead'

WHEN 4 THEN 'Serializable'

WHEN 5 THEN 'Snapshot'

end as lvl

from sys.dm_exec_sessions

where session_id = @@SPID

end

及(没有工作):

proc [Common].[usp_SetXactIsoLevel]

@pNewLevel varchar(30)

as

begin

if @pNewLevel = 'ReadUncommitted'

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

else if @pNewLevel = 'ReadCommitted'

SET TRANSACTION ISOLATION LEVEL READ COMMITTED

else if @pNewLevel = 'RepeatableRead'

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

else if @pNewLevel = 'Serializable'

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

else if @pNewLevel = 'Snapshot'

SET TRANSACTION ISOLATION LEVEL SNAPSHOT

else

raiserror('Unrecognized Transaction Isolation Level', 16, 1)

end

1、 概述

在很多企业应用中有时需要在特定的时间运行一段代码,比如银行需要在晚上系统相对空闲的时间

内进行日结的对帐,那么到了规定时间系统需要触发对帐服务运行对帐程序,现在EJB定时器服务能解决这个问题,它是一个可靠的、事务性的、提供容器的服

务,允许Bean提供者注册定时反馈的企业Beans,它可以在特定时刻发生,或在某段时间之后发生,或以一定时间间隔重复发生。由于这个服务是可靠的,

容器破坏的时候定时依然有效,企业Beans的激活与失效、装载与保存周期都由定时器注册。定时器服务由EJB容器实现,定时器服务可以通过

EJBContext接口新增的getTimerService()方法来访问,它返回实现TimerService接口的对象:这个接口允许创建不同的

定时器来支持在不同时间、不同时间间隔、不同时间周期时发生的定时反馈。使用定时器服务的企业Beans的Bean类必须实现

javax.ejb.TimedObject接口。在EJB2.1中,只有无序的会话Beans和实体Beans可以注册为定时器服务。这个功能在以后的

规范中可能会扩展到其它类型的Bean。

定时器服务适合长时间的业务处理模型,但并不适合用于实时的事件模型。

在 WebSphere Application Server

6中,EJB 定时服务将 EJB

计时器作为新的调度程序服务任务实施。缺省情况下,内部调度程序实例用于管理那些任务,定时任务存放在与服务器进程关联的 Cloudscape

数据库中。在集群环境中,任务必须存放在企业关系型数据库中。下面我们以DB2为例讲述怎样在集群环境中配置定时服务。

回页首

2、 创建用于定时服务的数据库

个定时服务程序都需要一个数据库,以用于存储它的持久信息。数据库及其位置应当由应用程序开发者和服务器管理员决定。

定时服务程序使用这个数据库来存储任务,然后运行这些任务。定时服务程序性能极大地依赖于数据库的性能。如果需要每秒执行更多任务,您可以在更大型的系统

中运行定时服务程序守护程序,或通过使用多个定时服务程序对任务或分区使用的会话 bean

使用集群。但是,定时服务程序数据库最终会达到饱和状态,此时您就需要一个更大型或更优异的数据库系统。

当您在每个定时服务程序配置中指定唯一的表前缀值时,多个定时服务程序可以共享一个数据库。这一共享可以降低定时服务程序数据库的管理成本。

TIPS:Oracle

XA 数据库的限制,Oracle XA 不允许在全局事务环境中执行所需的模式 *** 作。本地事务是不受支持的。如果您的调度程序使用 Oracle

XA 数据源,您可以将调度程序配置临时更改为使用一个非 XA Oracle 数据源,或者使用提供的 DDL

文件手工创建表。如果使用管理控制台为配置为使用 Oracle XA 数据源的调度程序创建或删除调度程序表,您将接收到一条

SchedulerDataStoreException 错误消息并且 *** 作将失败。

下面我们将以DB2为例讲述定时服务:

在机器hostdb上安装DB2后,打开 DB2 命令行窗口。

保您拥有数据库系统的管理员权限,验证此数据库确实支持 Unicode(UTF-8)。 否则,此数据库无法存储 Java

代码中可以处理的所有字符,当客户机使用了不兼容的代码页时,这将导致代码页转换问题。要避免死锁,请确保将 DB2

隔离级别设置为"读稳定性"。如果需要,请输入命令 :

db2set DB2_RR_TO_RS=YES

然后重新启动 DB2 实例以激活这一更改。在 DB2 命令行处理程序中输入以下命令使用示例名 timerdb 创建数据库:

db2 CREATE DATABASE scheddb USING CODESET UTF-8 TERRITORY en-us

即可创建名为 timerdb 的 DB2 数据库。

现已为定时服务创建了 DB2 数据库。

回页首

3、 创建定时服务的表空间和表

在WAS6的安装目录下,有一个名为scheduler的目录。下面包含WAS容器用来管理定时服务的各种数据库SQL定义。

对应于DB2的SQL定义文件名为createSchemaDB2.ddl和createTablespaceDB2.ddl,修改这两个文件选择你所要新建的表空间名和你所要的模式名称。这两个文件大致内容如下:

createTablespaceDB2.ddl

CREATE TABLESPACE @SCHED_TABLESPACE@ MANAGED BY SYSTEM USING

( '@location@\@SCHED_TABLESPACE@' )

可以修改表空间名称,这个文件也可不做修改。然后修改createSchemaDB2.ddl

修改后的的结果可以去掉原来的模式名称,那么新建用户表的时候将使用缺省连接数据库的用户的模式名。

CREATE TABLE "TASK" ("TASKID" BIGINT NOT NULL ,

"VERSION" VARCHAR(5) NOT NULL ,

"ROW_VERSION" INTEGER NOT NULL ,

"TASKTYPE" INTEGER NOT NULL ,

"TASKSUSPENDED" SMALLINT NOT NULL ,

"CANCELLED" SMALLINT NOT NULL ,

"NEXTFIRETIME" BIGINT NOT NULL ,

"STARTBYINTERVAL" VARCHAR(254) ,

"STARTBYTIME" BIGINT ,

"VALIDFROMTIME" BIGINT ,

"VALIDTOTIME" BIGINT ,

"REPEATINTERVAL" VARCHAR(254) ,

"MAXREPEATS" INTEGER NOT NULL ,

"REPEATSLEFT" INTEGER NOT NULL ,

"TASKINFO" BLOB(102400) LOGGED NOT COMPACT ,

"NAME" VARCHAR(254) NOT NULL ,

"AUTOPURGE" INTEGER NOT NULL ,

"FAILUREACTION" INTEGER ,

"MAXATTEMPTS" INTEGER ,

"QOS" INTEGER ,

"PARTITIONID" INTEGER ,

"OWNERTOKEN" VARCHAR(200) NOT NULL ,

"CREATETIME" BIGINT NOT NULL ) IN "@SCHED_TABLESPACE@"

这两个文件修改完成后,在命令行运行db2cmd转到db2命令窗口。

然后运行db2batch -d timerdb -f createTablespaceDB2.ddl

和db2batch -d timerdb -f createSchemaDB2.ddl生成定时服务所需要的表空间和表。

运行完成后用下列命令验证:

Db2 connect to timerdb

Db2 list tables

你将会看到有以下四个表被创建:

Table/ViewSchema Type

------------ ------------- -----

LMGRADMINT

LMPRADMINT

TASK ADMIN T

TREG ADMIN T

其中主表task存放了定时程序的相关信息。

回页首

4、 创建新的集群

分别在hosta,hostb,hostc上完成WAS6安装后,我们需要创建3个节点来组成一个新的群集。

1)在hosta上创建一个Network DeployManagement节点,启动概要表创建向导:

选择创建Deployment Manager概要表:

点下一步直至完成

2)分别在hostc和hostb两个节点上选择创建应用服务器概要表。

3)创建完成后在DeployManager概要上运行startManager.sh启动Network Manager。

4)启动完成后打开概要下的日志文件SystemOut.log查看soap端口,缺省为8879。

5)在hostb和hostc两个应用服务器节点上运行addNode.sh hosta 8879

6)运行完成后,打开ND管理控制台:http://hosta:9060/ibm/console

7)在服务器下新建一个群集timertest,创建两个成员为clus01,clus02。启动群集。

回页首

5、 创建定时服务的数据源

进入ND管理控制台,展开资源,点击JDBC 提供者,选择要新建的资源所在的服务器

点新建。按提示输入所需资料。点数据源,进入数据源页面。

新建一个名为testtimer的数据源,指定jndi名为jdbc/testtimer

测试连接通过后。做下一步设置。

回页首

6、 修改服务器设置

打开管理控制台。

单击服务器 >应用程序服务器 >服务器名 >EJB 容器设置 >EJB 定时服务设置。 出现"定时服务设置"面板。

如果您要使用内部或预配置的调度程序实例,则单击使用内部 EJB 定时服务调度程序实例单选按钮。

如果您选择不更改缺省的设置,则此实例与 Cloudscape 数据库相关联。

更改数据源选择输入您所选的数据源别名。选择前面创建的jdbc/testtimer数据源。

输入表前缀为你创建表时的用户缺省模式名称,必须注意的是,在模式名称后面必须要带上一个小数点.。具体对应的每个值的意思可以点击帮助页面查看。

回页首

7、 开发基于J2EE标准的定时服务企业bean

下面的例子是在RAD环境下开发,要实现定时服务,EJB必须要实现javax.ejb.TimedObject接口。

EJB里面需要涉及到的接口或类分别是:

要实现的TimedObject和TimerService,Timer。

EJB中的ejbContext增加了一个方法.getTimerService()用于获得TimerService类。但这个方法不能在

setEntityContext()、setSessionContext()、setMessageContext()方法中调用。

下面列出了三个接口的定义:

public interface TimedObject{

public void ejbTimeout(Timer timer)

}

public interface TimerService{

public Timer createTimer(Date expiration,Serializable info)

public Timer createTimer(long duration,Serialzable info)

public Timer createTimer(Date initalExpiration,long intervalDuration,Serializable info)

public Timer createTimer(long initalDuration,long intevalDuration,Serializable info)

public java.util.Collection getTimers()

}

public interface Timer{

public void cancel()

public java.io.Serializable getInfo()

public Date getNextTimeout()

public long getTimeRemaining()

public TimerHandle getHandle()//这是一个local对象,不能传到remote client端使用

}

对于Stateless SessionBean来说,不要在ejbCreate()和ejbRemove()中设置Timer。主要是因为ejbCreate和ejbRemove调用的时间和次数都因Container Vendor而异。可能导致错误设置Timer。

对MessageDriven Bean 而言,和Stateless SessionBean的情况基本相似。但是设置Timer应该在onMessage()里面。通过一个JMS来进行触发。

ejbTimedout是一个回调方法,执行具体的商业逻辑,那么怎样设置什么时间触发这个方法呢,我们利用javax.ejb.TimerSevice。该对象我们可以从EJBContext中获得该对象实例。

定时器创建的特定时间到达后,容器就会触发ejbTimeout(),运行ejbTimeOut方法提,Bean在终止之前通过调用定时器Cancel方

法取消定时器,它是定时器接口的一部分,如果定时器被取消,ejbTimeout()方法就不会被调用了。定时器接口的getHandle()方法返回一

个序列化的handle对象。接下来,这个持续的Handle能够"非序列化",通过调用getTimer()方法得到定时器。由于定时器是本地对

象,TimerHandle不必通过Bean的远程接口或Web Services接口来传递。

具体步骤如下:

新建一个EJB项目otherTimer,在这个EJB项目里新建一个otherTimer的会话Bean。

在Bean实体里面需要实现两个方法:

startTimer()和ejbTimeOut。

startTimer()方法里面,我们通过EJBCONTEXT取得一个TimerService然后创建一个Timer。这个timer将在

2005,9月19日晚上8点过5分触发,触发后,EJB容器会调用ejbTimeOut()方法运行具体的商业逻辑,并且这个Timer会在80000

毫秒后再次触发。

javax.ejb.TimerService ts=this.getSessionContext().getTimerService()

System.out.println("启动一个时钟!")

Timer timer = ts.createTimer(new Date(105,9,19,20,5,0),80000,"other timer")

回页首

8、 WAS Scheduler实现

于WAS

Scheduler实现定时服务,需要配置一个scheduler,在WAS管理控制台展开资源,点scheduler,新建一个scheduler指定

名称、JNDI名、数据源JNDI名(这里可以用前面设置的jndi/testtimer)和表前缀,跟前面设置服务器EJB定时服务容器设置类似。

设置完成后就可以使用scheduler来实现定时服务了。

EJB模块中创建一个无状态会话bean,该 bean 实现了 com.ibm.websphere.scheduler.TaskHandler

远程接口中的 process() 方法。将您要创建的业务逻辑放入 process() 方法中。当运行任务时,将调用 process()

方法。Home 和 Remote 接口在部署描述符 bean 中必须设置如下:

com.ibm.websphere.scheduler.TaskHandlerHome

com.ibm.websphere.scheduler.TaskHandler

通过使用以下示例工厂方法创建 BeanTaskInfo 接口的一个实例。 使用 JSP 文件、servlet 或 EJB 组件创建实例,如以下代码示例所示。此代码必须与先前创建的 TaskHandler EJB 模块位于同一应用程序中:

Object schedulerObj = initialContext.lookup("java:comp/env/Scheduler")

BeanTaskInfo taskInfo = (BeanTaskInfo) schedulerObj.createTaskInfo(BeanTaskInfo.class)

注:

创建 BeanTaskInfo 对象并不会将任务添加到持久存储中。它将为必要的数据创建一个占位符。直到调用调度程序中的 create()

方法,才会将任务添加到持久存储中。设置 BeanTaskInfo 对象中的参数。 这些参数定义了调用哪些会话 bean

以及何时调用它们。TaskInfo 接口包含可用于控制任务执行的各种 set() 方法,其中包括运行任务的时间以及运行任务时它执行的 *** 作。

BeanTaskInfo

接口要求使用 setTaskHandler 方法设置 TaskHandler JNDI 名称或 TaskHandlerHome。如果使用

WASScheduler MBean API 来设置任务处理程序,则 JNDI 名称必须是标准的全局 JNDI 名称。

使用 TaskInfo 接口 API 方法设置参数,如以下代码示例所示:

java.util.Date startDate = new java.util.Date(System.currentTimeMillis()+30000)

Object reportGenHomeObj = initialContext.lookup("java:comp/env/ejb/ReportGenerator")

TaskHandlerHome reportGenHome = (TaskHandlerHome)PortableRemoteObject.narrow

(reportGenHomeObj,TaskHandlerHome.class)taskInfo.setTaskHandler(home)

taskInfo.setStartTime(startDate)

scheduler.create(taskInfo)

那么EJB容器将在当前时间的30000毫秒后触发process方法,在taskinfo里面可以设置一些其他schduler的属性,比如运行次数,运行间隔等。

IPC是指两个进程之间进行数据交互的过程,即:跨进程通信。

进程是一个执行单,在移动设备上指一个程序或者一个应用。一个进程可以有多个线程,也可以只有一个线程,即主线程。在Android里边,主线程也叫作UI线程,要是在主线程执行大量耗时任务,就会造成界面无法响应,ANR问题,解决这类问题,把耗时 *** 作放在子线程就好。

在Android中,最有特色的进程间通信就是Binder,Binder轻松的实现了进程间的通信。

给四大组件 Activity、Service、Receiver、ContentProvider 在AndroidMenifeist中指定 android:process 属性,可以指定其运行的进程。

: 开头的线程是当前应用的私有进程,其它应用不可以和它跑在同一个进程中,而不以 : 开头的属于全局进程,其他应用通过ShareUID方式可以和它跑在一个进程中。

Android为了每一个应用(进程)都分配了独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间。

多进程会造成如下几个反面方面的问题:

为了解决这些问题,系统提供了跨进程通信方法,虽然不能直接共享内存,但是可以实现数据共享。Intent来传递数据,共享文件,基于Binder的Messenger,ContentProvider,AIDL和Socket。

当我们需要通过Intent和Binder传输数据,或者我们需要把对象持久化到存储设备上,再或者通过网络传输给其它客户端时,Serializable和Parcelable接口可以完成对象的序列化过程。

Serialzable是java提供的序列化接口,是一个空接口,为对象同序列化和反序列化 *** 作。

想让一个类对象实现序列化,只需要这个类实现Serialzable接口,并声明一个serialVersionUID即可,serialVersionUID可以声明成1L或者IDE根据当前类接口自动生成它的hash值。

没有serialVersionUID不影响序列化,但是可能会影响反序列化。序列化时,系统当前类的serialVersionUID写入序列化文件中,当反序列化时,回去检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致,如果不一致,无法完成反序列化。

Seriallizable用起来简单但是开销大,序列化和反序列过程需要大量的I/O *** 作,而Parcelable是Android序列化方式,更适合Android平台,效率更高。Parcelable主要用于内存序列化上,而Seriallizable更适用于序列化到本地存储设备,或者将对象序列化后通过网络传输到别的客户端。

Activity、Service、Receiver都支持在 Intent中传递Bundle数据,Bundle实现了Pareclable接口,所以它可以方便地在不同进程间传输。

Android基于Linux,使得其并发读写文件可以没有限制的进行,两个进程可以通过读写一个文件来交换数据。共享数据对文件格式没有要求,双反约定就行。使用文件共享很有可能出问题。

SharedPreferences是个特例,虽然也是属于文件的一种,但是由于系统对它的读写有一定的缓存策略,即在内存中会有一份SharedPreferences文件的缓存,因此在多进程模式下,系统对他的读写变得不可靠,高并发的时候,很大可能会丢失数据。

Messenger可以在不同的进程中传递Message对象,在Message中存入我们需要传递的数据,就可以实现数据的跨进程传递。它是一种轻量级的IPC方案,底层实现是AIDL。

Messenger对AIDL做了封装,使得我们可以更便捷的实现跨进程通信,它一次只处理一个请求,在服务端不用考虑线程同步问题,在服务端不存在并发执行的情形。实现一个Messenger有如下几个步骤:

在服务端创建一个Service,同时创建一个Handler,并通过它来创建一个Messenger对象,然后再Service的onBind中返回这个Messenger对象底层Binder即可。

绑定服务端Service,绑定成功后用服务端返回的IBinder对象创建一个Messenger。通过这个对象就可以向服务端发消息了。如果需要服务端回应客户端,就需要和服务端一样,创建一个Handler,并通过它来创建一个Messenger对象,然后把这个Messenger对象通过Message的replyTo参数传给服务端,服务端可以通过这个replyTo参数回应客户端。

首先要创建一个Service用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现AIDL接口即可。

绑定服务端的Service,将服务端返回的Binder对象转成AIDL接口所属的类型,接着就可可以范文AIDL里边的方法了。

在AIDL文件中,并不是所有的额数据类型都是可以使用的。

以上6种数据就是AIDL所支持的所有类型,其中自定义的Parecelable对象和AIDL对象必须显示的import,不管是否和当前的AIDL文件位于同一个包。

AIDL文件中用到了自定义的Parcelable对象,必须新建一个同名的AIDL文件,在其中声明它为parcelable类型。

AIDL中除了基础数据类型,其它类型参数都需要标上方向:in、out、inout,in是输入型参数,out是输出型参数,inout是输入输出型参数。

上面是远程服务端示例,AIDL方法在服务端的Binder线程池中执行,因此各个客户端同时连接的时候,会存在多个线程同时访问的情形,所以要在AIDL中处理线程同步,这个CopyOnWriteArrayList支持并发的读写。

AIDL所支持的是一个抽象的List,只是一个接口,因此虽然服务端返回的是CopyOnWriteArrayList,当时Binder会按照List规范去范文数据并最终形成一个ArrayList传递给客户端。

ServiceConnection 的回调方法在UI线程中运行,服务端的方法有可能很久才能执行完毕,需要考虑ANR的问题。

服务的方法本省就运行再Binder线程池中,本身可以执行大量耗时 *** 作,不要去服务端方法中开县城去进行异步任务。

客户端

服务端

RemoteCallbackList是系统提供专门用于删除跨进程listener的,它的内部有一个Map结构,用来保存所有的AIDL回调,这个Map的key就是Binder类型,value是CallBack类型。

客户端解注册的时候,我们只需要遍历服务端所有的listener,找出那个和接注册listener具有相同的Binder对象的服务端listener并把它删除即可。

RemoteCallbackList的beginBroadcast和finishBroadcast必须配对使用。

ContentProvider是Android专门提供不同应用间进行数据共享的方式。底层实现一样是Binder。

系统预置了许多ContentProvider,比如通讯录,日程信息表,只需要通过ContentResolver的query、update、insert、delete方法即可。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/6773443.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-28
下一篇 2023-03-28

发表评论

登录后才能评论

评论列表(0条)

保存