安卓开发
1.Activity
1.销毁程序时先销毁进入当前页面的那个activity,再销毁当前activity 2.创建流程 onCreat -> onStart -> onResume -> onPause -> onStop -> onDestory onRestart被调用后跳转到onStart 3.四种模式:
2.Service
1.Service不是一个单独的进程,它和它的应用程序在同一个进程中 2.Service不是一个线程,这样就意味着我们应该避免在Service中进行耗时操作 3.当一个后台的任务,需要分成几个子任务,然后按先后顺序执行子任务 (简单的说就是异步操作),此时如果我们还是定义一个普通Service,然后在onStart方法中开辟线程,然后又要去控制线程,这样显得非常的繁琐; 此时应该自定义一个IntentService然后再onHandleIntent()方法中完成相关任务! 4.Activity与Service进行通信时,交流媒介便是Service中的onBind方法,返回我们自定义的Binder对象 流程: (1).自定义Service中,自定义一个Binder类,然后将需要暴露的方法都写到该类中! (2).Service类中,实例化这个自定义Binder类,然后重写onBind()方法,将这个Binder对象返回! (3).Activity类中实例化一个ServiceConnection对象,重写onServiceConnected()方法,然后 获取Binder对象,然后调用相关方法即可! 5.定时任务处理流程 Step 1:获得Service: AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE); Step 2:通过set方法设置定时任务 int anHour = 2 * 1000; long triggerAtTime = SystemClock.elapsedRealtime() + anHour; manager.set(AlarmManager.RTC_WAKEUP,triggerAtTime,pendingIntent); Step 3:定义一个Service 在onStartCommand中开辟一条事务线程,用于处理一些定时逻辑 Step 4:定义一个Broadcast(广播),用于启动Service 最后别忘了,在AndroidManifest.xml中对这Service与Boradcast进行注册! 6.IBinder是Android给我们提供的一个进程间通信的一个接口,而我们一般是不直接实现这个接口的, 而是通过继承Binder类来实现进程间通信!是Android中实现IPC(进程间通信)的一种方式!
Binder机制
流程解析: -> Client调用某个代理接口中的方法时,代理接口的方法会将Client传递的参数打包成Parcel对象; -> 然后代理接口把该Parcel对象发送给内核中的Binder driver;; -> 然后Server会读取Binder Driver中的请求数据,假如是发送给自己的,解包Parcel对象, 处理并将结果返回; PS:代理接口中的定义的方法和Server中定义的方法是一一对应的, 另外,整个调用过程是一个同步的,即Server在处理时,Client会被Block(锁)住! 而这里说的代理接口的定义就是等下要说的AIDL(Android接口描述语言)!
Service绑定方法
startService进行绑定 在创建后只创建一个Service,完成后调用onStartCommand,在其他需要创建Service时只用再次调用onStartCommand,这个方法生成的Service和调用者无关,等到onDestory执行时才会销毁 bindService进行绑定 当第一次绑定时,系统会实例化一个对象,调用其的onCreat和onBind方法,然后调用者就可以用IBinder和Service进行通信了,此后如果再次使用bindService绑定Service,不会创建新的Service实例,直接把IBinder对像传给其他,解除绑定时,只需要调用unbindService,再所有的客户端都解除绑定时,才会调用onUbind和onDestory,当所有的客户端都解除绑定时,Service立即终止 先startService进行创建,再通过bindService进行绑定 其生命周期:onCreate( )->onStartCommand( )->onBind( )->onUnbind( )->onRebind( ),因为Service是通过startService进行创建的,所以在所有的客户端接触绑定后并不会进行销毁
方法解析
bindService(Intent Service,ServiceConnection conn,int flags)
service:通过该intent指定要启动的Service conn:ServiceConnection对象,用户监听访问者与Service间的连接情况, 连接成功回调该对象中的onServiceConnected(ComponentName,IBinder)方法; 如果Service所在的宿主由于异常终止或者其他原因终止,导致Service与访问者间断开 连接时调用onServiceDisconnected(CompanentName)方法,主动通过unBindService() 方法断开并不会调用上述方法! flags:指定绑定时是否自动创建Service(如果Service还未创建), 参数:0(不自动创建)BIND_AUTO_CREAT(自动创建)
设置定时任务:set(int type,long startTime,PendingIntent pi)
①type: 有五个可选值: AlarmManager.ELAPSED_REALTIME: 闹钟在手机睡眠状态下不可用,该状态下闹钟使用相对时间(相对于系统启动开始),状态值为3; AlarmManager.ELAPSED_REALTIME_WAKEUP 闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟也使用相对时间,状态值为2; AlarmManager.RTC 闹钟在睡眠状态下不可用,该状态下闹钟使用绝对时间,即当前系统时间,状态值为1; AlarmManager.RTC_WAKEUP 表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟使用绝对时间,状态值为0; AlarmManager.POWER_OFF_WAKEUP 表示闹钟在手机关机状态下也能正常进行提示功能,所以是5个状态中用的最多的状态之一, 该状态下闹钟也是用绝对时间,状态值为4;不过本状态好像受SDK版本影响,某些版本并不支持; 第一个参数决定第二个参数的类型,如果是REALTIME的话就用: SystemClock.elapsedRealtime( )方法可以获得系统开机到现在经历的毫秒数 如果是RTC的就用:System.currentTimeMillis()可获得从1970.1.1 0点到 现在做经历的毫秒数 ②startTime: 闹钟的第一次执行时间,以毫秒为单位,可以自定义时间,不过一般使用当前时间。 需要注意的是,本属性与第一个属性(type)密切相关,如果第一个参数对应的闹钟 使用的是相对时间(ELAPSED_REALTIME和ELAPSED_REALTIME_WAKEUP),那么本属 性就得使用相对时间(相对于系统启动时间来说),比如当前时间就表示为: SystemClock.elapsedRealtime();如果第一个参数对应的闹钟使用的是绝对时间 (RTC、RTC_WAKEUP、POWER_OFF_WAKEUP),那么本属性就得使用绝对时间, 比如当前时间就表示为:System.currentTimeMillis()。 ③PendingIntent: 绑定了闹钟的执行动作,比如发送一个广播、给出提示等等。PendingIntent 是Intent的封装类。 需要注意的是,如果是通过启动服务来实现闹钟提示的话, PendingIntent对象的获取就应该采用Pending.getService (Context c,int i,Intent intent,int j)方法; 如果是通过广播来实现闹钟提示的话, PendingIntent对象的获取就应该采用 PendingIntent.getBroadcast (Context c,int i,Intent intent,int j)方法; 如果是采用Activity的方式来实现闹钟提示的话,PendingIntent对象的获取 就应该采用 PendingIntent.getActivity(Context c,int i,Intent intent,int j) 方法。 如果这三种方法错用了的话,虽然不会报错,但是看不到闹钟提示效果。
广播
动态注册
在java代码中指定IntentFilter,然后添加不同的Action即可,想监听什么广播就写什么action,动态注册的广播,一定要调用unregisterReceiver让广播取消注册,需要程序启动才能接受广播
静态注册
在AndroidManifest中制定<IntentReceiver>就可以让程序在未启动的情况下接受广播
注意
从Android 8.0(API级别26)开始,该系统对声明清单的接收者施加了额外的限制。 如果你的应用目标是Android 8.0或更高版本,你不能使用清单为大多数隐式广播(不是专门针对你的应用的广播)声明接收器。当用户正在使用你的应用程序时,你仍然可以使用上下文注册的接收器。 即定义的静态广播必须指定范围(应用),类似于生活中广播要在指定频道才能收到。
内容传播者ContentProvider
自定义ContentProvider流程
Intent
类别
显式:通过组件名指定启动的目标组件,比如startActivity(new Intent(A.this,B.class)),每次启动的组件只有一个 隐式:不指定组件名,而指定Intent的Action,Data,或Category,当我们启动组件时, 会去匹配AndroidManifest.xml相关组件的Intent-filter,逐一匹配出满足属性的组件,当不止一个满足时, 会弹出一个让我们选择启动哪个的对话框~
七个属性
ComponentName(组件名称) Action(动作) Category(类别) Data(数据),Type(MIME类型)
Extras(额外) Flags(标记)
传递数据
1.简单数据 发送方 先实例化一个intent对象,在实例化一个Bundle对象,通过Bundle对象的putString、putInt等方法将要传递的信息放入Bundle对象中,再通过intent的putExtras(Bundle对象)传入到接受对象中 接受方 通过getIntent获取Intent对象,完成后通过Intent的getExtras获取Bundle对象,通过bundle对象的getInt、getString等方法获取传递过来的值 2.数组 发送方 先实例化一个intent对象,在实例化一个Bundle对象,通过Bundle对象的putStringArrary()写入传入的键和数组值到Bundle对象中,再通过intent的putExtras(Bundle对象)传入到接受对象中 接收方 通过getIntent获取Intent对象,完成后通过Intent的getExtras获取Bundle对象,通过bundle对象的getStringArrary(”键“)获取传递过来的值 3.集合 List<基本数据类型或String> 发送方 intent.putStringArraryListExtra(键,值) intent.putIntegerArrayListExtra(键,值) 接受方 intent.getStringArraryListExtra(键,值) intent.getIntegerArrayListExtra(键,值) List<Object> 发送方 intent.putExtras(key,(Serializable)list) 读取方 (List<Object>) getIntent.getSerializable(key) Map<String,Object> 在Map外面套一个List 4.传递对象 将对象转换成Json字符串 发送方 intent.putExtra(,new Gson.toJson(要传递的对象)) 接受方 通过getStringExtra()进行获取,在使用Gson的formJson方法进行获取 使用Serializable,Parcelable序列化对象 (1)使用Serializable实现 ①业务Bean实现:Serializable接口,写上getter和setter方法 ②Intent通过调用putExtra(String name, Serializable value)传入对象实例 当然对象有多个的话多个的话,我们也可以先Bundle.putSerializable(x,x); ③将跳转的Activity调用getSerializableExtra()方法获得对象实例: eg:Product pd = (Product) getIntent().getSerializableExtra(“Product”); ④调用对象get方法获得相应参数 (2)使用Parcelable实现 ①业务Bean继承Parcelable接口,重写writeToParcel方法,将你的对象序列化为一个Parcel对象; ②重写describeContents方法,内容接口描述,默认返回0就可以 ③实例化静态内部对象CREATOR实现接口Parcelable.Creator ④同样式通过Intent的putExtra()方法传入对象实例,当然多个对象的话,我们可以先 放到Bundle里Bundle.putParcelable(x,x),再Intent.putExtras()即可 解释:通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射成你的对象。也可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面, 在通过createFromParcel从流里读取对象,只不过这个过程需要你来实现,因此写的 顺序和读的顺序必须一致。
Fragment
会收到宿主Activity的影响,宿主Activity被销毁时,它也将会销毁
Fragment的生命周期
注意:
1.Fragment需要嵌套在Activity中使用,当然也可以嵌套到另外一个Fragment中,但这个被嵌套 的Fragment也是需要嵌套在Activity中的,间接地说,Fragment还是需要嵌套在Activity中!! 受寄主Activity的生命周期影响,当然他也有自己的生命周期!另外不建议在Fragment里面嵌套Fragment因为嵌套在里面的Fragment生命周期不可控!!! 2.Fragment的生命周期和Activity有点类似:三种状态: Resumed:在允许中的Fragment可见 Paused:所在Activity可见,但是得不到焦点 Stoped: ①调用addToBackStack(),Fragment被添加到Bcak栈 ②该Activity转向后台,或者该Fragment被替换/删除 ps:停止状态的fragment仍然活着(所有状态和成员信息被系统保持着),然而,它对用户不再可见,并且如果activity被干掉,他也会被干掉 一些关于生命周期变化信息: ①Activity加载Fragment的时候,依次调用下面的方法: onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart ->onResume ②当我们弄出一个悬浮的对话框风格的Activity,或者其他,就是让Fragment所在的Activity可见,但不获得焦点 onPause ③当对话框关闭,Activity又获得了焦点: onResume ④当我们替换Fragment,并调用addToBackStack()将他添加到Back栈中 onPause -> onStop -> onDestoryView !!注意,此时的Fragment还没有被销毁哦!!! ⑤当我们按下键盘的回退键,Fragment会再次显示出来: onCreateView -> onActivityCreated -> onStart -> onResume ⑥如果我们替换后,在事务commit之前没有调用addToBackStack()方法将 Fragment添加到back栈中的话;又或者退出了Activity的话,那么Fragment将会被完全结束, Fragment会进入销毁状态 onPause -> onStop -> onDestoryView -> onDestory -> onDetach
创建一个Fragment
静态加载一个Fragment 实现流程 动态加载一个Fragment
管理与事务
Fragment与Activity的交互
1.组件获取
Fragment获取Activity中的组件:getActivity().findViewByid() Activity获得Fragment中的组件:getFragmentManager.findFragmentByid()
2.数据传递
(1).Activity传递数据给Fragment: 在Activity中创建Bundle数据包,调用Fragment实例的setArguments(bundle)从而将Bundle数据包传给Fragment,然后Fragment中调用getArguments获取Bundle对象,然后进行解析就行了 (2).Fragment传递数据给Activity 在Fragment中定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口,Fragment就可以通过接口传数据了
3.Fragment与Fragment之间的数据互传
其实这很简单,找到要接受数据的fragment对象,直接调用setArguments传数据进去就可以了 通常的话是replace时,即fragment跳转的时候传数据的,那么只需要在初始化要跳转的Fragment 后调用他的setArguments方法传入数据即可! 如果是两个Fragment需要即时传数据,而非跳转的话,就需要先在Activity获得f1传过来的数据, 再传到f2了,就是以Activity为媒介~
|