第三天

四大组件之
        Activity的生命周期,启动
        Intent和intentFilter
        Service的生命周期,两种编程方式
        BroadcastReceiver 广播接收者
        ContentProvider内容提供者
--------------------------------------------------------------------------------
什么是Activity 
        a,布满整个窗口或者悬浮于其他窗口上的交互界面
        b,一个应用程序中通常有一个或多个Activity构成
        b,每个Activity都必须在AndroidManifest.xml中进行申明
        c,多个Activity是通过栈进行管理,当前的活动的Activity在栈顶
        d,在程序中自定义的Activity必须继承基类Activity
        c,Activity有自己的生命周期,并且在不同的生命周期中会调用不同的函数
    创建方法:
        1.定义一个Activity的子类
        2.重写onCreate()
        3.定义一个布局视图    
        4.将布局视图关联给活动(界面)
        5.注册活动子类到清单文件
    四大组件之Activity的生命周期
        class 人类{
            出生方法(){}
            
            上幼儿方法(){}
            
            上小学(){}
            
            上中学(){}
            
            上大学(){}
            
            工作1(){}
            工作2(){}
            
            找对象(){}
            成家(){}
            
            去世(){}
            
        }


onCreate(): Activity开始被创建的时候被调用,
            主要完成的任务:创建ui视图,绑定数据到list中

onStart(): 当Activity变成可视化的时候被调用,可见了,但还不是可交互的从后台切换到前台也会调用
           此方法中可以去维护一些显示在Activity上的资源,比如可以注册一个BroadcastReceiver,
           用于监控对UI产生影响的状态变化
           比如ui上的内容发生变化,可以通过个BroadcastReceiver去广播
                       
onResume: 获取到与用户交互的焦点,也可以认为是apk正在running
          在这里可以做一些动画的播放,打开独占设备(比如相机)

onPause: 失去用户交互的焦点,但是视图还在,比如另外一个Activity切换到前台并获取到焦点时
          (一个对话框出现,或者是休眠)
          在这个方法中执行停止动画等比较耗CPU的操作,或者将需要永久化存储的数据进行保存,
          因为有可能不会回来了

onResume和onPause会经常切换,所以里面的内容尽量的是轻量级的,以避免导致用户等待

onStop:表示当前Activity完全被其他的视图给占用了

onDestrory: 整个Activity完全销毁的时候,该方法中应该完成释放资源的操作

        3个阶段和7个方法
            开始阶段:onCreate, onStart, onResume
            重新获取焦点: onRestart(); onStart();onResume;
            关闭Activity: onPause, onStop,onDestory

        Activity获得与失去焦点的循环:
            onPause->onResume->onPause
        Activity可见与不可见的循环
            onStart->onRestart->onResume->onPause->onStop

        整个生命周期:onCreate-->onDestory
            可视周期:
                onStart->onStop
            焦点周期:
                onResume->onPause
            在 activity 被停止后重新启动时(调用打开过的应用程序)调用该方法。
                其后续会调用 onStart 方法   
                onRestart()
        总共7个
        -------------------------------------------------
        activity创建(onCreate)->可视化(onStart)->获取焦点(onResume)
                |
                来了一个电话
        onPause(失去焦点)->onStop(失去视图)
                |
                接完电话,返回到app
        onRestart(重新开始,针对恢复activity)->onStart(可视化)->onResum(获取焦点)
                |
                退出activity
        onPause(失去焦点)->onStop(失去视图)->onDestroy(毁灭)
        
        按下返回按键:onPause()->onStop()->onDestory()
        长按Home键,弹出最近打开过的应用程序
        按Home键:onPause()->onStop()
        onRestart():启动一个另外一个Activity后,由另外一个Activity返回时
=============================================================================== 
    启动Activity的方式:
    1,startActivity();
        a,启动一个自定义的Activity(显示的启动)
            Intent intent = new Intent();                           //创建一个Intent对象   
            intent.setClass(activity1.this, activity2.class);   //描述起点和目标   
            startActivity(intent);                                     //开始跳转
        b,启动系统的Activity
            String telString = "tel:13800138000";
            final Uri telUri = Uri.parse(telString);
            String data = "http://www.google.com";
            final Uri webUri = Uri.parse(data);

            Intent intent = new Intent(Intent.ACTION_VIEW, webUri);
            startActivity(intent);
        
        
    2,启动另外一个Activity并返回结果--实质也是通过Bundle实现
        startActivityForResult(Intent, int requestCode);----------> 
            参数2:requestCode请求码,由程序员自行定义,用于标识请求来源
                    例如:一个Activity有两个按钮,点击这两个按钮会打开不同的Activity
                    不管哪个Activity关闭后,系统都会调用前面Activity的onActivityResult()
                    如果需要获取不同的Activity返回来的数据,那么可以通过该请求码进行识别
        onActivityResult(int requestCode, int resultCode, Intent)<-----------------
                     ----setResult(Int resultCode);
            requestCode:用于区分到底是哪个请求
            resultCode: 结果码
            Intent:包含Bundle,里面有跟多信息
        另外一个:
           Intent data=new Intent();  
            data.putExtra("bookname", str_bookname);  
            data.putExtra("booksale", str_booksale);  
                setResult(20, data); // 

    3,启动activity的时候传递数据: intent作为中介(也可以理解为容器)
        a,携带Bundle
            1,构建Bundle
            2,填入数据
                bundle.putInt("键", 值); //普通数据
                budle.putSerialize("键",对象);
            3,将Bundle加入到Intent
                putExtra(Bundle) 
                
        b,键值对
            putExtra("键", 值);
        c,获取数据
            Intent intent = getIntent();
    关闭Activity:
        a,关闭当前的activity
            finish();
        b,关闭以startActivityForResult()方法启动的Activity
            finishActivity(int requestCode);

========================================================================
intent的作用和使用
    什么是intent?
    a,为一个信息的载体,用于应用间的交互与通讯,对应用中一次操作的动作、动作涉及数据、附加数据进行
        描述,Android则根据此Intent的描述,负责找到对应的组件,将Intent传递给调用的组件,并完成
        组件的调用
    b,Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互
        比如启动另外一个Activity,另外一个Service,还可以发送广播给BoardcastReciver
        
    c,intent的属性--表示要做什么,带了一些什么信息
        Intent主要有以下四个重要属性,它们分别为:
        0,Component name:表示该intent是交给哪个具体的Component组件的(该对象是可选的,同时也可以不用intent-filter)
            在代码中需要如下操作:
                ComponentName comp = new ComponentName(xxx类.this, 另一个Activity的this);
                Intent  intent = new Intent();
                intent.setComponent(comp);
                StartActivity(Intent);
        
        Action 和Category,在启动的组件中需要有intent-filter
        1,Action:值为一个字符串,它代表了系统中已经定义了一系列常用的动作
            a,系统自带的常量:ACTION_CALL,ACTION_EDIT
            b,自定义的字符串,一般格式:"包名.类名.特定的字符"
        
        2,Category:组件的类别,用于描述哪一类的组件可以处理该Intent,也是一个字符串,为Action添加的附加信息,通常会和Action结合使用
            一个Intent只能指定一个Action,但可以指定多个Category
                    CATEGORY_DEFAULT :默认的category
                    CATEGORY_LAUNCHER:决定应用程序是否显示在程序列表里,表示在luncher中可否启动该组件
                    CATEGORY_BROWSABLE :在网页上点击图片或链接时,系统会考虑将此目标Activity列入可选列表,
                                    供用户选择以打开图片或链接。比如有个网页链接,你的系统装了很多浏览器,此时会列举出多个打开方式
                    
            
        3,Data:Android中采用指向数据的一个URI来表示,如在联系人应用中,
            对于不同的动作,其URI数据的类型是不同的(可以设置type属性指定特定类型数据),
            如ACTION_EDIT指定Data为文件URI,打电话为tel:URI,访问网络为http:URI,
            而由content provider提供的数据则为content: URIs。一个指向某联系人的URI可能为:content://contacts/1。 
        4,Extras:Extras属性主要用于传递目标组件所需要的额外的数据。通过putExtras()方法设置。常用于在多个Action之间进行数据交换
                public void invokeWebSearch(View view) {  
                        Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);  
                        intent.putExtra(SearchManager.QUERY, "android");    //关键字  
                        startActivity(intent);  
                }  
        以上一般比较重要的是:
            action 
            data (both URI and data type) 
            category

    Intent被解析的过程:显示intent和隐式intent
        显示intent:明确指定需要启动或者触发的组件的类名,常用于启动当前应用程序的不同组件
                类似与找人: 找章子怡
        隐式intent:指定需要启动或者触发的组件应满足怎样的条件,常用于启动其他应用程序中的组件
                也就是说系统会对intent进行解析,解析出它的条件
                然后再在系统中查找与之匹配的目标组件
                而被调用或目标组件需要通过intentfilter来声明自己满足条件
                类似与找人: 穿红衣服的女孩
    Intent-filter:组件的意图过滤器,
        a,其实是一个对象,但是一般不会直接去创建,都是在AndroidManifest.xml中存在
        b,一个组件中可以有多个Intent-filter,可以根据过滤不同的intent而采取不同的处理
        c,过滤的时候会过滤三个域:action,data,category,任何intent必须成功经过这三道过滤,缺一不可
        Action test:至少有一个
            
                
                
                
                
            
            必须添加一个android.intent.category.DEFAULT


        c,隐式的启动:
            在intent添加过滤器intentfilter
            
                android:name="com.example.android.tst.SecondActivity"
                android:label="@string/title_activity_main" > 
                 
                 
                 
                 
            

            启动方法:
                Intent intent=new Intent("com.example.android.tst.SecondActivity");
                //或者如下操作
                //intent.setAction( "com.example.android.tst.SecondActivity");
                //intent.addCategory(Intent.CATEGORY_DEFAULT);
                startActivity(intent);
                解释:
                发送了这个intent之后,android会去系统里保存的MainManifest.xml里查找符
                合这两个属性的activity,

                任何一个需要隐式启动的Activity都必须要有这项:
                    
==========================================================================
Service在Android中和Activity是属于同一级别上的组件
            Activity仪表不凡,迷倒万千少女
            Service身强力壮,但是在后台做一些搬运工的力气活

            后台运行
Service的特性:
            1, 拥有后台运行的特性,比如将屏幕关闭后,继续运行
            2,不是一个独立的进程,除非特别指定(存在于一个进程中)
            3,它不是一个线程
            4,服务是一种    应用程告诉系统它想在后台要做的某个事情    的工具,并将功能提供(暴露)给其它应用程序

Service的应用场合:
        从播放列表播放音乐,播放器有一些activities来叫用户选定歌曲并开始播放。但是,播放本身不需要activity处理,因为用户希望关闭activity
        后歌曲会继续播放。因此media player 的activity 会启动一个service
    

Service和Thread的区别:
        1,Thread 是程序执行的最小单元,它是分配CPU的基本单位,而Service是一个组件,你也可以认为是应用程序的一个插件
                这个插件能完成后台的操作
        2,Service其实是运行在主线程中的,如果需要执行复杂耗时的操作,必须在Service中再创建一个Thread来执行任务
        3,Service的优先级高于后台挂起的Activity,当然,也高于Activity所创建的Thread,因此,系统可能在内存不足的时候优先杀死后台
                的Activity或者Thread,而不会轻易杀死Service组件,即使被迫杀死Service,也会在资源可用时重启被杀死的Service
        4,Thread只是一个用来执行后台任务的工具类,它可以在Activity中被创建,也可以在Service中被创建。
            所以不需要去疑惑使用Service还是Thread,而是应该讨论在什么地方创建Thread。

Service的两种启动方式:
            context.startService()-- 对应于Local Service(本地服务,调用和实现在同一个进程)
                        依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC
                        主进程被Kill后,服务便会终止。
            context.bindService()-- 对应于Remote Service(远程服务,调用和实现不在同一个进程)
                        由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程
                        提供服务具有较高的灵活性。该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点
    
Service的生命周期:
        本地服务:
                启动一个Service的过程
                            context.startService() ->onCreate()->onStartCommand()->Servicerunning
                
                            startService()在Activity中启动服务,实际是并实例化了一个Service实例
                            onCreate()  进行一些服务的初始化工作,比如可以创建一个线程用于播放音乐
                            onStartCommand():服务正常运行时,能够处理Intent,如果多多次启动服务,该方法会被调用
                                                在以前的版本该方法为onStart();onStartCommand()内部会被调用,已经过时了
                
                停止一个Service的过程:
                            context.stopService() ->onDestroy() ->Service stop 
                            
                            Activity调用这即使结束了自己的生命周期,只要没有使用stopService方法停止这个服务,服务仍会运行
        远程服务: 远程服务其实就是给外部apk提供各种接口
                启动一个Service的过程
                        context.bindService()-->onCreate()-->onBind()-->Servicerunning

                                onBind():当绑定成功时,该方法被调用,并且需要返回一个binder接口的实例
                                        如果重复绑定,该方法只会执行一次
                停止一个Service的过程:
                        context.unbindService()-->onUnBinde()-->onDestroy()-->Service stop 
                        
                        bindService模式下服务是与调用者生死与共的,在绑定结束之后,一旦调用者被销毁,服务也就立即终止,
                        就像江湖上的一句话:不求同生,但愿同死,当然罗,如果要继续用服务,再bind就好了, 服务会跟着运行起来的


aidl: 实际是一个工具,帮我们自定生成一些代码,完成进程调度的细节代码
只需要定义好service段和调用端直接的接口就可以了

package com.hq.service;

interface IService{  //一定要文件的名字保持一致,文件名一定要是aidl的后缀
    int add(int a, int b);
    int sub(int a, int b);

}


1,在服务端里实现接口:
    public class MyService extends Service{
        
        public IBinder onBind(Intent arg0)
        {
            // TODO Auto-generated method stub
            Log.i(TAG, "------onBind--------");
            //如果需要绑定成功,就一定要返回一个binder的子类
            return new IServiceImpl();
        }

        // 实现用户提供的接口,定义一个内部类
        public class IServiceImpl  extends IService.Stub{
                public int add(int a, int b) throws RemoteException
                {
                    // TODO Auto-generated method stub
                    return a+b;
                }

                @Override
                public int sub(int a, int b) throws RemoteException
                {
                    // TODO Auto-generated method stub
                    return a-b;
                }
        }
    
    }

2,在client中进行调用:
    bindService(intent3, serviceConnection, Service.BIND_AUTO_CREATE); //启动服务
    //参数2: 当绑定成功之后,需要做的事情:
    private ServiceConnection serviceConnection = new ServiceConnection(){
        public void onServiceConnected(ComponentName name, IBinder iBinder){
                //通过IService中将ibider统一的接口转换成自己定义的接口对象
                serviceManager = IService.Stub.asInterface(iBinder);
                serviceManager.add(34, 56) //直接调用
        }
    }


MediaPlayer media;
media = MediaPlayer.create(MyService.this,R.raw.nobody);
media.start();
media.stop();
------------------------------------------------------------------------------------------------------------------------------------
BroadcastReceiver也就是“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播
    广播体现在方方面面,例如
            当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服务的功能;
            当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等操作;
            当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度,等等。

广播的发送:
    普通广播:
            对于多个接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,
            接收者无法终止广播,  即无法阻止其他接收者的接收动作。
            sendBroadcast(intent);
            abortBroadcast();
    有序广播:
        它每次只发送到优先级较高的接收者那里,然后由优先级高的接受者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播
        sendOrderedBroadcast(intent, "george.permission.MY_BROADCAST_PERMISSION");
                参数中有个权限,所以
                        在AndroidMainfest.xml中定义一个权限:
                            
                        
                        如果要发送广播,必须要获取到这个权限:
                            

过滤器的配置:
        1,静态:在AndroidManifest.xml文件中配置,这种方式的注册是常驻型的,也就是说当应用关闭后,
                        如果有广播信息传来,MyBroadCastReceiver也会被系统调用而自动运行

                
                    
                        

                        
                    
                
        2,动态:在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播
                    不是常驻型的,也就是说广播会跟随程序的生命周期

                private ThirdBroadCastReceiver receiver = null;
                //新建一个广播接收器
                receiver = new ThirdBroadCastReceiver();
                //新建一个过滤器
                IntentFilter filter = new IntentFilter();
                filter.addAction("broadcast.MyBroadCastReceiver");
                filter.setPriority(997);
                //为广播接受器注册一个过滤器
                registerReceiver(receiver, filter);


广播的接收:
        普通广播:
                intent.getExtras();
        有序广播:
                接受
                    String extraStr = getResultExtras(true).getString("passMsg");
                继续传播:
                    // 给下个广播接受者传递广播
                    Bundle bundle = new Bundle();
                    bundle.putString("passMsg", intentStr + "from @SecondBroadCastReceiver");
                    setResultExtras(bundle);
                停止传播:
                    abortBroadcast();

你可能感兴趣的:(第三天)