ImageVerifierCode 换一换
格式:PPT , 页数:47 ,大小:1.98MB ,
资源ID:373666      下载积分:2000 积分
快捷下载
登录下载
邮箱/手机:
温馨提示:
如需开发票,请勿充值!快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝扫码支付 微信扫码支付   
注意:如需开发票,请勿充值!
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【http://www.mydoc123.com/d-373666.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(第5章Android服务(Service).ppt)为本站会员(feelhesitate105)主动上传,麦多课文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知麦多课文库(发送邮件至master@mydoc123.com或直接QQ联系客服),我们立即给予删除!

第5章Android服务(Service).ppt

1、第5章 Android服务(Service),网络资源:http:/ Service概述,文本,5.1.1 Service介绍,Service是android 系统中的一种组件,它跟Activity的级别差不多,它们都是从Context派生出来的,但是它不能自己运行,只能在后台运行,并且可以和其它组件进行交互。它需要通过某一个Activity或者其他Context对象来调用。,5.1.2 启动Service的两种方式,在Android系统中,常采用以下两种方式启动Service.(1)通过Context的startService()启动service后,访问者与service之间没有关联,该s

2、ervice将一直在后台执行,即使调用startservice的进程结束了,service仍然还存在,直到有进程调用stopService(),或者service自己停止(stopSelf)。这种情况下,service与访问者之间无法进行通信,数据交换,往往用于执行单一操作,并且没有返回结果。例如通过网络上传,下载文件,操作一旦完成,服务应该自动销毁。(2)通过Context的bindService()绑定Service,绑定后Service就和调用bindService的组件同生共死了。也就是说当调用bindService()的组件销毁了,那么它绑定的Service也要跟着被结束,当然期间也

3、可以调用unbindservice()让Service提前结束。注意:一个服务可以与多个组件绑定,只有当所有的组件都与之解绑后,该服务才会被销毁。,5.1.2 启动Service的两种方式,以上两种方法可以混合使用,即一个Service既可以启动也可以绑定,只需要同时实现onStartedCommand()(用于启动)和onBind()(用于绑定)方法,那么只有调用stopService(),并且调用unbindService()方法后,该Service才会被销毁。 注意:服务运行在它所在进程的主线程,服务并没有创建它自己的线程,也没有运行在一个独立的进程上(单独指定的除外),这意味着,如果你

4、的服务做一些消耗CPU或者阻塞的操作,你应该在服务中创建一个新的线程去处理。通过使用独立的线程,你就会降低程序出现ANR(Application No Response程序没有响应)的风险,程序的主线程仍然可以保持与用户的交互。,5.1.3 Service中常用方法,与开发其它Android组件类似,开发Service组件需要先开发一个Service子类,该类需继承系统提供的Service类,系统中Service类包含的方法主要有: abstract IBinder onBind(Intent intent):该方法是一个抽象方法,所有Service子类必须实现该方法。该方法将返回一个IBin

5、der对象,应用程序可通过该对象与Service组件通信; void onCreate():当Service第一次被创建时,将立即回调该方法; void onDestroy():当Service被关闭之前,将回调该方法; void onStartCommand(Intent intent,int flags,int startId):每次客户端调用startService(Intent intent)方法启动该Service时都会回调onStartCommand()方法; boolean onUnbind(Intent intent):当该Service上绑定的所有客户端都断开连接时将会回调该

6、方法。,开发Service组件需要先开发一个Service子类,然后在AndroidManifest.xml文件中配置该Service,配置时可通过元素指定它可被哪些Intent启动。,在AndroidManifest.xml文件中配置Service:,Action中的值一定要与程序中创建的Intent的Action的值一致,程序就是根据Action的值来查找相应的Service从而启动它。,5.1.3 Service中常用方法,通过Context的startService()启动Service后,访问者与Service之间没有关联,该Service将一直在后台执行,即使调用startServ

7、ice()的进程结束了,Service仍然还存在,直到有进程调用stopService(),或者Service自己自杀(stopSelf())。这种情况下,Service与访问者之间无法进行通信、数据交换。,通过Context的bindService()绑定Service后,Service就和 调用bindService()的组件同生共死了,也就是说当调用 bindService()的组件销毁了,那么它绑定的Service也要跟着被结束。,5.1.2 Service中常用方法简介,案例:FirstService,定义的Service子类必须实现onBind()方法,然后还需在AndroidMa

8、nifest.xml文件中对该Service子类进行配置,配置时可通过元素指定它可被哪些Intent启动。下面具体来创建一个Service子类并对它进行配置,代码如下。,程序清单:/FirstService/src/iet/jxufe/cn/android/MyService.java,public class MyService extends Service private static final String TAG = “MyService“;public IBinder onBind(Intent arg0) Log.i(TAG, “MyService onBind invoked

9、!“);return myBinder; public void onCreate() Log.i(TAG, “MyService onCreate invoked!“);super.onCreate(); public void onDestroy() Log.i(TAG, “MyService onDestroy invoked!“);super.onDestroy();quit=true; public int onStartCommand(Intent intent, int flags, int startId) Log.i(TAG, “MyService onStartComman

10、d invoked!“);return super.onStartCommand(intent, flags, startId); ,自定义服务类,重写OnBind方法,重写OnCreate方法,重写OnDestory方法,重写OnStartCommand方法,案例:FirstService,在上述代码中,创建了自定义的MyService类,该类继承了Android.app.Service类,并重写了onBind(),onCreate(),onStartCommand(),onDestory等方法,在每个方法中,通过LOG语句测试和查看该方法是否被调用。,定义完Service之后,还需在项目的

11、AndroidManifest.xml文件中配置该Service,增加配置片段如下。,虽然目前MyService已经创建并注册了,但系统仍然不会启动MyService,要想启动这个服务。必须显示地调用startService()方法。如果想停止服务,需要显示地调用stopService()方法,下面代码中,使用Activity作为Service的启动者,分别定义了启动Service和关闭Service两个按钮,并为它们添加了事件处理。,程序清单:/FirstService/src/iet/jxufe/cn/android/MainActivity.java,public class MainA

12、ctivity extends Activity public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);start=(Button)findViewById(R.id.start);stop=(Button)findViewById(R.id.stop);final Intent intent=new Intent();intent.setAction(“.android.MyService“);start

13、.setOnClickListener(new OnClickListener() public void onClick(View v) startService(intent); );stop.setOnClickListener(new OnClickListener() public void onClick(View v) stopService(intent); ); ,案例:FirstService,案例:FirstService,运行本节的例子后,第一次单击【启动Service】按钮后,在DDMS视图下的LogCat视图有如下图所示的输出。,然后单击【关闭Service】按钮,

14、LogCat视图有如下图所示的输出。,下面按如下的单击顺序,重新测试一下本例。【启动Service】【启动Service】【启动Service】【停止Service】测试完程序,查看LogCat控制台输出信息如下图所示。系统只在第一次单击【启动Service】按钮时调用onCreate()和onStartCommand()方法,再单击该按钮 时,系统只会调用onStartCommand()方法,而不会重复调用onCreate()方法。,5.1.4 绑定Service过程,Context的bindService()方法的完整方法签名为:bindService(Intent service,Ser

15、viceConnection conn, int flags),该方法的三个参数解释如下: service:该参数表示与服务类相关联的Intent对象,用于指定所绑定的Service应该符合哪些条件; conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况。当访问者与Service之间连接成功时,将回调该ServiceConnection对象的onServiceConnected(ComponentName name,IBinder service)方法;当访问者与Service之间断开连接时将回调该ServiceConnection对

16、象的onServiceDisconnected(ComponentName name)方法。 flags:指定绑定时是否自动创建Service(如果Service还未创建)。该参数可指定BIND_AUTO_CREATE(自动创建)。,当开发Service类时,该Service类必须提供一个onBind()方法,在绑定本地Service的情况下,onBind()方法所返回的IBinder对象将会传给ServiceConnection对象里onServiceConnected(ComponentName name,IBinder service)方法的service参数,这样访问者就可以通过IBi

17、nder对象与Service进行通信。实际开发时通常会采用继承Binder(IBinder的实现类)的方式实现自己的IBinder对象。,5.1.4 绑定Service过程,5.1.4 绑定Service案例,在上一个案例中,添加两个按钮,一个用于绑定服务,一个用于解绑,然后分别为其添加事件处理。在绑定服务时,需要传递一个ServiceConnection对象,所以先创建该对象,代码如下。,private ServiceConnection conn=new ServiceConnection() public void onServiceDisconnected(ComponentName

18、name) Log.i(TAG,“MainActivity onServiceDisconnected invoked!“); public void onServiceConnected(ComponentName name, IBinder service) Log.i(TAG,“MainActivity onServiceConnected invoked!“);myBinder=(MyBinder)service;,程序清单:/FirstService/src/iet/jxufe/cn/android/MainActivity.java,5.1.4 (绑定Service案例),然后在M

19、yService中添加两个与绑定Service相关的方法,onUnBind()和onRebind(),与其他方法类似,只是在方法体重打印出该方法被调用了信息,代码如下。,public boolean onUnbind(Intent intent) Log.i(TAG, “MyService onUnbind invoked!“);return super.onUnbind(intent);public void onRebind(Intent intent) Log.i(TAG, “MyService onRebind invoked!“);super.onRebind(intent);,程序

20、清单:/FirstService/src/iet/jxufe/cn/android/MyService.java,5.1.4 (绑定Service案例),最后在MainActivity中为绑定Service和解绑Service按钮添加事件处理,代码如下。,public class MainActivity extends Activity public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bind=(B

21、utton)findViewById(R.id.bind);unbind=(Button)findViewById(R.id.unbind);final Intent intent=new Intent();intent.setAction(“.android.MyService“);bind.setOnClickListener(new OnClickListener() public void onClick(View v) bindService(intent, conn,Service.BIND_AUTO_CREATE); ); unbind.setOnClickListener(ne

22、w OnClickListener() public void onClick(View v) unbindService(conn); );,程序清单:/FirstService/src/iet/jxufe/cn/android/MainActivity.java,5.1.4 (绑定Service案例),程序执行后,单击绑定Service按钮,LogCat控制台打印信息如下图所示,首先调用onCreate()方法,然后调用onBind()方法。,程序执行后,单击解绑Service按钮,LogCat控制台打印信息如下图所示,首先调用onUnbind()方法,然后调用onDestory()方法。

23、,程序运行后,单击绑定Service按钮,然后退出程序,LogCat控制台打印信息如下图。可以看出,程序退出后,Service会自动退出。,5.1.4 (绑定Service案例),当单击绑定Service按钮后,再重复多次单击绑定Service按钮,查看控制台打印信息,发现程序并不会多次调用onBind()方法。,采用绑定服务的另一个优势是组件可以与Service之间进行通信,传递数据。这主要是通过IBinder对象进行的,因此需在Service中创建一个IBinder对象,然后让其作为onBind()方法的返回值返回,对数据的操作是放在IBinder对象中的。修改我们的MyService类,

24、添加一个内部类MyBinder,同时在onCreate()方法中启动一个线程,模拟后台服务,该线程主要是做数据递增操作,在MyBinder类中,提供一个方法,可以获取当前递增的值(count的值),具体代码如下。,程序清单:/FirstService/src/iet/jxufe/cn/android/MyService.java,5.1.4 (绑定Service案例),public class MyService extends Service private static final String TAG = “MyService“;private int count=0;private b

25、oolean quit=false;private MyBinder myBinder=new MyBinder();public class MyBinder extends Binder public MyBinder() Log.i(TAG, “MyBinder Constructure invoked!“);public int getCount() return count; public IBinder onBind(Intent arg0) Log.i(TAG, “MyService onBind invoked!“);return myBinder; public void o

26、nCreate() Log.i(TAG, “MyService onCreate invoked!“);super.onCreate();,线程中循环是否停止的标志,创建自定义的MyBinder对象,MyBinder的构造方法,观察什么时候创建,MyBinder中提供的获取数据的方法,重写onBind()方法, 返回创建的对象,5.1.4 (绑定Service案例),new Thread()public void run()while(!quit)tryThread.sleep(500);count+;System.out.println();catch (Exception e) e.pri

27、ntStackTrace(); .start();public void onDestroy() Log.i(TAG, “MyService onDestroy invoked!“);super.onDestroy();quit=true;,判断是否继续执行循环,休眠0.5秒,数据递增,改变循环是否退出的标志,否则子线程一直在循环,5.1.4 (绑定Service案例),接着在MainActivity中添加一个获取数据的按钮,获取数据的前提是要绑定Service,所以先绑定Service,在ServiceConnection()对象的onServiceConnected()方法中,获取绑定Se

28、rvice时,返回的IBinder对象,然后将该对象强制类型转换成MyBinder对象,最后利用MyBinder对象获取服务中的数据信息。首先改写创建ServiceConnection对象的方法,关键代码如下。,private ServiceConnection conn=new ServiceConnection() public void onServiceDisconnected(ComponentName name) Log.i(TAG,“MainActivity onServiceDisconnected invoked!“); public void onServiceConnec

29、ted(ComponentName name, IBinder service) Log.i(TAG,“MainActivity onServiceConnected invoked!“);myBinder=(MyBinder)service;,程序清单:/FirstService/src/iet/jxufe/cn/android/MainActivity.java,将传递的参数强制类型装换成MyBinder对象,5.1.4 (绑定Service案例),然后,为获取数据按钮添加事件处理方法,关键代码如下。,getData.setOnClickListener(new OnClickListen

30、er() public void onClick(View v) Toast.makeText(MainActivity.this, “Count=“+myBinder.getCount(), Toast.LENGTH_LONG).show(); );,程序清单:/FirstService/src/iet/jxufe/cn/android/MainActivity.java,以消息的形式,显示获取的数据,此时,单击绑定服务后,LogCat控制台打印信息如下图,首先创建MyBinder对象,因为该对象是作为MyService的成员变量进行创建的,完成MyService的初始化工作,然后再调用on

31、Create()方法,再调用onBind()方法,该方法返回一个IBinder对象,因为IBinder对象不为空,表示有服务连接,所以会调用ServiceConnection借口的onServiceConnected()方法,并将调用IBinder对象它的第二个参数。,案例总结,1、通过Context的startService()方法启动和停止Service 2、通过Context的bindService()方法绑定和解除绑定 3、两种方式混合使用,案例总结,两种方式混合使用时,方法的执行顺序是怎么样的?,问题与讨论,1、先启动后绑定,2、先绑定后启动,案例总结,1)先启动Service,然后

32、绑定Service。测试步骤:【启动Service】【绑定Service】【启动Service】【停止Service】【绑定Service】【解绑Service】。,总结:调用顺序如下:onCreate()onStartCommand()1到N次 onBind() onServiceConnected()onUnbind() onServiceConnected()onRebind()0到N次onDestroy()。,控制台信息如下图所示。,案例总结,2)先绑定Service,后启动Service。测试步骤:【绑定Service】【启动Service】【绑定Service】【解绑Service

33、】【启动Service】【停止Service】。,总结:调用顺序如下:onCreate()onBind()onServiceConnected() onStartCommand() 1到N次onUnBindonServiceConnected() onRebind()0到N次onUnBindonDestroy()。,控制台信息如下图所示。,案例总结,注意: (1)未启动Service而直接停止Service不起作用,但未绑定Service而先解绑Service则程序出错,强制退出; (2)若该Service处于绑定状态下,该Service不会被停止即单击停止按钮不起作用,当单击解绑Servic

34、e按钮时,它会先解除绑定随后直接销毁; (3)若在解除之前,没有单击停止Service,则只解绑而不会销毁。,5.1.5 Service的生命周期,每当Service被创建时会回调onCreate()方法,每次Service被启动时都会回调onStartCommand()方法,多次启动一个已有的Service组件将不会再回调onCreate()方法,但每次启动时都会回调onStartCommand()方法。,绑定服务的执行过程:执行单击事件方法根据Intent找到相应的Service类,并初始化该类调用Service的onCreate()方法调用该类的onBind()方法调用onService

35、Connected()方法。多次单击绑定服务按钮,并不会重复执行绑定方法。一旦解绑,调用onunBind()方法,然后自动销毁。,5.2 跨进程调用Service,AIDL是一种接口定义语言,用于约束两个进程间通信规则,供编译器生成代码,实现Android设备上的两个进程间通信(IPC)。 进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应的对象。 由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员来说是透明的。,AIDL:Android Interfa

36、ce Definition Language,5.2.1 什么是AIDL服务,客户端访问Service时,Android并不是直接返回Service对象给客户端,Service只是将一个回调对象(IBinder对象)通过onBind()方法回调给客户端。与绑定本地Service不同的是,本地Service的onBind()方法会直接把IBinder对象本身传给客户端的ServiceConnection的onServiceConnected方法的第二个参数。但远程Service的onBind()方法只是将IBinder对象的代理传给客户端的ServiceConnection的onServiceC

37、onnected方法的第二个参数。当客户端获取了远程的Service的IBinder对象的代理之后,接下来可通过该IBinder对象去回调远程Service的属性或方法。,AIDL文件创建和java借口定义相类似,但在编写AIDL文件时,需注意:,5.2.2 建立AIDL文件,1.接口名和aidl文件名相同;2.接口和方法前不用加访问权限修饰符public,private等,也不能用final,static;3.Aidl默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence),使用这些类型时不需要import声明。对

38、于List和Map中的元素类型必须是Aidl支持的类型。如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口。4.自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中。5.在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,以指明参数是输入参数、输出参数还是输入输出参数。6.Java原始类型默认的标记为in,不能为其它标记。,定义好AIDL接口之后(如Song.aidl),ADT工具会自动在gen目录下生成相应的包,并生成一个song.java接口,在该接口里包含一个Stub内部

39、类,该内部类实现了IBender,Song两个接口,这个Stub类将会作为远Service的回调类。由于它实现了IBinder接口,因此可作为Service的onBind()方法的返回值。,package .android; interface SongString getName();String getAuthor(); ,程序清单:/AIDLServer/src/iet/jxufe/cn/android/Song.aidl,5.2.2 建立AIDL文件,AIDL定义接口的源代码必须以.aidl结尾; AIDL接口中用到数据类型,除了基本类型、String、List、Map、CharSeq

40、uence之外,其他类型全部都需要导包,即使它们在同一个包中也需要导包。定义好AIDL接口之后(如Song.aidl),ADT工具会自动在gen目录下生成相应的包,并生成一个Song.java接口,在该接口里包含一个Stub内部类,该内部类实现了IBinder、Song两个接口,这个Stub类将会作为远程Service的回调类。它内部能实现一些功能。开发客户端的第一步就是将Service端的AIDL接口文件复制到客户端应用中,复制到客户端后ADT工具会为AIDL接口生成相应的Java接口类。,AIDL使用时需注意:,5.2.2 建立AIDL文件,5.2.3 建立AIDL服务端,远程Servic

41、e的编写和本地Service很相似,只是远程Service中onBind()方法返回的IBinder对象不同,该Service代码如下。,程序清单:/AIDLServer/src/iet/jxufe/cn/android/AIDLServer.java,public class AIDLServer extends Service private String names=new String“老男孩“,“春天里“,“在路上“;private String authors=new String“筷子兄弟“,“汪峰“,“刘欢“;private String name,author;private

42、 SongBinder songBinder;private Timer timer=new Timer();public class SongBinder extends Stub public String getName() throws RemoteException return name;public String getAuthor() throws RemoteException return author; ,5.2.3 建立AIDL服务端,远程Service的编写和本地Service很相似,只是远程Service中onBind()方法返回的IBinder对象不同,该Serv

43、ice代码如下。,程序清单:/AIDLServer/src/iet/jxufe/cn/android/AIDLServer.java,public IBinder onBind(Intent intent) return songBinder; public void onCreate() songBinder=new SongBinder();timer.schedule(new TimerTask() public void run() int rand=(int)(Math.random()*3);name=namesrand;author=authorsrand;System.out.

44、println(rand);, 0,1000);public void onDestroy() super.onDestroy();timer.cancel(); ,5.2.3 建立AIDL服务端,通过上面的程序可以看出,在远程Service中定义了一个SongBinder类,且该类继承Stub类,而Stub类继承了Binder类,并实现了Song接口,Binder类实现了IBinder接口。因此,与本地Service相比,开发远程Service要多定义一个AIDL接口。另外,程序中onBind()方法返回SongBinder类的对象实例,以便客户端获得服务对象,SongBinder对象的创建

45、放在onCreate()方法中,因为onBind()方法在onCreate()方法之后被调用,因此onBind()方法的返回值不会为空。接下来在AndroidManifest.xml文件中配置该Service类,配置Service类的代码如下:,程序清单:/AIDLServer/AndroidManifest.xml,5.2.4 建立AIDL客户端,1、创建ServiceConnection对象;2、以ServiceConnection对象作为参数,调用Context的bindService()方法绑定远程Service。3、将返回的IBinder对象的代理类转换成IBinder对象,从而调用

46、Service中的相应方法。,客户端绑定远程Service与绑定本地Service的区别不大, 同样只需要三步:,5.2.4 建立AIDL客户端案例,通过一个按钮来获取远程Service的状态,并显示在两个文本框中。,5.2.4 建立AIDL客户端案例,程序清单:/AIDLClient/src/iet/jxufe/cn/android/client/MainActivity.java,public class MainActivity extends Activity private Button getData;private EditText name,author;private Son

47、g songBinder; public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getData=(Button)findViewById(R.id.getData);name=(EditText)findViewById(R.id.name);author=(EditText)findViewById(R.id.author);final Intent intent=new Intent();intent

48、.setAction(“.android.AIDLServer“);bindService(intent, conn, Service.BIND_AUTO_CREATE);getData.setOnClickListener(new OnClickListener() public void onClick(View v) tryname.setText(songBinder.getName();author.setText(songBinder.getAuthor(); ,用于获取其他进程数据的按钮,显示获取的数据的文本编辑框,用户交互的IBinder对象,根据ID找到相应控件,根据ID找到

49、相应控件,根据ID找到相应控件,创建一个Intent对象,设置Intent的特征,绑定Service,添加单击事件处理,显示获取的数据,5.2.4 建立AIDL客户端案例,catch(Exception ex)ex.printStackTrace(); );private ServiceConnection conn=new ServiceConnection() public void onServiceDisconnected(ComponentName name) songBinder=null; public void onServiceConnected(ComponentName name, IBinder service) songBinder=Song.Stub.asInterface(service);protected void onDestroy() super.onDestroy();unbindService(conn);,

copyright@ 2008-2019 麦多课文库(www.mydoc123.com)网站版权所有
备案/许可证编号:苏ICP备17064731号-1