精华内容
下载资源
问答
  • Android 四大组件之Activity
    千次阅读
    2022-02-14 13:49:40

    Android 四大组件之Activity

    ​ Android有四大组件分别是:活动(activity),用于表现功能;服务(service),后台运行服务,不提供界面呈现;广播接受者(Broadcast Receive),勇于接收广播;内容提供者(Content Provider),支持多个应用中存储和读取数据,相当于数据库。

    活动(Activity)

    ​ 介绍:Activity是Android的四大组件之一,是用户操作可视化界面;它为用户提供了一个操作的页面。在我创建一个新的Activity之后,需要调用setContenView()方法来显示页面,以此来为用户提供交互。在Android APP中只要能看到的页面都是依附于Activity显示的,同样Activity是在开发中使用最多最频繁的一种组件。

    1、 Activity生命周期

    ​ 在一个Activity从页面开始到显示再到结束一共有7个生命周期方法

    img

    • onCreate()

      create表示创建,生命周期的第一个方法,也是在Android开发中接触最多的生命周期方法,表示Activity正在创建。一般会在这个方法中做一些初始化工作比如:setContentView加载布局,对一些控件和变量进行初始化等。此时Activity还在后台,不可见。

    • onStart()

      start标识Activity正在启动,这时Activity还没有显示在前台页面上,无法与Activity交互。其实将Activity的初始化工作放在这也没有什么问题,放在onCreate中是由于官方推荐的以及我们开发的习惯。

    • onResume()

      resume表示继续、重新开始,这名字和它的职责也相同。此时Activity经过前两个阶段的初始化已经蓄势待发。Activity在这个阶段已经出现在前台并且可见了。这个阶段可以打开独占设备

    • onPause()

      pause标识页面暂停,当Activity页面跳转到另一个Activity页面时或者应用正常退出时都会执行这个方法。此时Activity还处于前台可见状态,因此可以在此方法做一些轻量级的数据存储工作但是不能太耗时。因为在跳转Activity时只有当前Activity执行了onPause方法后另一个新的Activity方法才能启动,而且在Android中指定了onPause在500ms内没用完全执行完毕的话会强制关闭Activity。

    • onStop()

      stop标识停止,此时Activity已经处于不可见的状态,但是Activity还在内存中没有被完全的关闭销毁。这里主要做一些资源回收的工作。

    • onDestroy()

      destroy表示销毁,这个阶段说明页面已经完全被销毁了,不可见,我们可以将一些没有没有被释放的资源进行释放,以及进行一些回收工作

    • onRestart()

      restart表示重新开始,Activity这里是可见的,当Activity_A页面转到Activity_B页面,又从Activity_B页面返回到Activity_A页面或者当用户直接按Home键返回到桌面上后又切换到Activity页面就会触发这个方法。这里一般不进行操作

    当Activity_A页面切换到Activity_B页面的执行顺序是:

    ​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sq2euACh-1644817774816)(/Users/caokun/Library/Application Support/typora-user-images/image-20220210095135989.png)]

    其实Activity的生命周期除了onRestart方法其余六个是两两对应的,那么相邻的方法有什么区别呢?

    1.1、onCreate和onStart之间有什么区别?

    ​ 1、可见与不可见的区别,onCreate是正在创建为不可见,onStart处于正在启动状态处于可见的状态

    ​ 2、执行次数的区别,onCreate方法只有在Activity创建的时候执行一次,而onStart方法在重新进入或者切换到Activity页面的过程中都会被多次调用,因为Bndle数据恢复在onStart中进行比在onCreate进行要更加合适

    ​ 3、onCreate能做的事其实onStart都能做,但是onStart能做的事onCreate未必都能做到;比如setContentView和资源初始化在两者都能做。但是初始化动画onCreate就不能做,因为onCreate是处于不可见状态所以不会显示效果,所以在onStart做初始化动画比较合适。

    1.2、onStart和onResume之间有什么区别?

    ​ 1、两者因为都处于可见状态,但是不是都处于前台可操作的状态,比如:onStart是处于可见状态但是不在前台,不能进行交互,而onResume处于前台可见状态,因此可以行数据交互。

    ​ 2、职责不同,onStart方法还是主要进行一些初始化的工作,而onResume方法,根据官方的建议可以做一些开启动画和可与用户交互的工作

    1.3、onPause和onStop之间有什么区别?

    ​ 1、可见与不可见的区别;onPause是暂停状态但是还是可见的状态,而onStop处于已经停止了也不可见的状态但是Activity还在内存中。

    ​ 2、在系统存在内存不足时可能不会执行onStop方法,因为在做数据存储、状态保存以及程序状态保存时最好在onPause中进行,但是不要太耗时。

    1.4、onStop和onDestroy之间有什么区别

    ​ 1、onStop处于停止状态但是Activity还处于内存中,可以通过切换页面来唤醒Activity页面;但是onDestroy已经表示Activity已经被销毁了。

    1.5、为什么切换Activity时各方法的执行次序是

    (A)onPause→(B)onCreate→(B)onStart→(B)onResume→(A)onStop

    ​ 而不是

    (A)onPause→(A)onStop→(B)onCreate→(B)onStart→(B)onResume

    ​ 1、因为Activity或多或少都会占用一些内存在官方的建议,onPause方法将会释放掉很多系统资源,为切换Activity提供流畅性的保障,而不需要再等多两个阶段,这样做切换更快。

    2、 Activity启动方式

    ​ Activity有四种启动方式分别为:默认启动模式standard、栈顶复用模式singleTop、栈内复用模式singleTask、全局唯一模式singleInstance四种模式,这四种也有不同的特征和区别,下面就一一介绍。

    一个android应用程序功能通常会被拆分为多个Activity,而各个Activity之间通过Intent进行连接,android系统通过栈结构来保存整个程序的Activity,栈底的元素是整个栈任务的发起者。
    正常情况下,当一个Activity启动了另一个Activity的时候,新启动的Activity就会置于任务栈的顶端,而启动它的Activity虽然功成身退,但依然保留在任务栈中,处于停止状态(如果没有finish),当用户按下返回键或者调用finish()方法时,系统会移除顶部的Activity,让后面的Activity恢复活动状态。但是,可以给Activity设置一些“特权”,来打破这种“和谐”的模式。这种特权,就是通过在AndroidManifest.xml文件中的属性android:launchMode来设置或者通过Intent的flag来设置的。

      <activity android:name=".MainActivity"
                android:launchMode="standard">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
                  
                  
     
    

    1.1、默认启动模式standard

    ​ 如果开发时不在manifest设定,那么Activity的默认模式就是standard。在该模式下,启动的Activity会依照启动顺序被依次压入Task中:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1uLW4Et0-1644817774817)(/Users/caokun/Library/Application Support/typora-user-images/image-20220210102239166.png)]

    返回页面时也是依次销毁页面的,这是最简单的一个模式。

    1.2、栈顶复用模式singleTop

    ​ 在该模式下,如果栈顶Activity为我们要新建的Activity(目标Activity),那么就不会重复创建新的Activity而是直接切换到该Acitvity;如果栈顶Activity不是我们要新建的Activity才会去新建一个Activity。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-an0K2YUI-1644817774817)(/Users/caokun/Library/Application Support/typora-user-images/image-20220210103854059.png)]

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
     
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".Activity2"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="ONETEXT_TWOACTIVITY" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity android:name=".Activity3">
            <intent-filter>
                <action android:name="ONETEXT_THREEACTIVITY" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
    

    可以手动设置通过:android:launchMode="singleTop"对当前Activity进行设置启动模式

    通过这种设置可以避免已经创建过的Activity被重复创建

    1.3、栈内复用模式singleTask

    与singleTop模式相似,只不过singleTop模式是只是针对栈顶的元素,而singleTask模式下,如果task栈内存在目标Activity实例会将:将task内的对应Activity实例之上的所有Activity弹出栈。将对应Activity置于栈顶,获得焦点。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uQUHyNUn-1644817774818)(/Users/caokun/Library/Application Support/typora-user-images/image-20220210105422872.png)]

    1.4、全局唯一模式singleInstance

    这是第四种模式,也是相对于比较复杂的一种模式:在该模式下,我们会为目标Activity分配一个新的affinity,并创建一个新的Task栈,将目标Activity放入新的Task,并让目标Activity获得焦点。新的Task且只有这一个Activity实例。 如果已经创建过目标Activity实例,则不会创建新的Task,而是将以前创建过的Activity唤醒(对应Task设为Foreground状态)

    这种启动模式和singleTask几乎一样,它也只允许系统中存在一个目标Activity,包括上面我们所说的SingleTask的一些特性singleInstance都有。singleInstance翻译过来是单例的意思:TA有两层含义:1.告诉系统,我是独一无二的,2.告诉任务栈我是独一无二的,也就是说,任务栈中除了我不能再有其他Activity。

    所以,如果要启动singleInstance模式的Activity,那只能新创建一个任务栈用来放它,因为人家说了,“我是独一无二的!”。同样的,如果从这种启动模式的Activity中启动别的Activity,那不好意思,我不管你是不是和我处在同一个应用,我所在的任务栈只能拥有我一个人,您呐,另外让系统给你创建一个任务栈待着去吧。

    更多相关内容
  • Android四大核心组件 Activity Activity是Android应用程序核心组件中最基本的一种,是用户与应用程序交互的窗口。类似于一个网站中的网页,可以互相跳转,并且可以有返回值(相当于转发是添加参数或者返回值)。 当...

    Android四大核心组件

    Activity

    Activity是Android应用程序核心组件中最基本的一种,是用户与应用程序交互的窗口。类似于一个网站中的网页,可以互相跳转,并且可以有返回值(相当于转发是添加参数或者返回值)。
    当新打开一个视图时,之前的视图会被置为暂停状态,并被压入历史堆栈中。
    Activity是由Android系统进行维护的,拥有自己的生命周期,如:

    • onCreate() :创建
    • onStart() : 激活
    • onResume(): 恢复
    • onPause(): 暂停
    • onStop(): 停止
    • onDestroy(): 销毁
    • onRestart(): 重启
    Service

    Service是Android系统中类似于Activity但是没有视图的程序,可以在后台运行很长时间,相当于操作系统中的一个服务。
    Android定义了两种类型的Service,即本地和远程Service。本地Service是只能由承载该Service的应用程序访问的组件,而远程Service是供在设备上运行的其他应用程序远程访问的Service。
    通过Context.startService(Intent service)可以启动一个Service,通过Context.bindService()可以绑定一个Service。

    BroadcastReceiver

    顾名思义,广播接收者适用于接受来自系统和其他应用程序的广播,并作出回应。
    在Android系统中,当有特定时间发生时就会产生相应的广播,比如开机时系统会发送一条广播给应用,告知应用启动等。
    BroadcastReceiver不能生成UI,通过NotificationManager来通知用户有事件发生,对于用户来说是隐式的。
    BroadcastReceiver有两种注册方式:

    • 在AndroidManifest.xml中进行静态注册
    • 在运行的代码中使用Context.registerReceiver()来进行动态注册。
      只要注册了BroadcastReceiver,即使对应的广播事件来临时应用程序尚未启动,系统也会自动启动该应用程序对事件进行处理。同时,用户还可以通过Context.sendBroadcast()将自己的Intent对戏那个广播给其他应用程序
    ContentProvider

    文件,数据库等数据在Android系统内是私有的,仅允许被特定应用程序使用,在两个程序之间,数据的交换或者共享由ContentProvider实现。
    ContentProvider类实现了一组标准方法的借口,从而能够让其他应用保存或者读取ContentProvider提供的各种数据类型。

    Intent

    Intent并不是Android应用程序核心组件,但是Activity,Service,BroadcastReceiver之间互相通信使用的消息使用的就是Intent。

    Activity解读

    一个Android程序通常由多个Activity组成,但是其中只有一个MainActivity,相当于java中的main方法。

    Activity的生命周期

    本质上讲,activity在生命周期中一共存在三个状态

    • 运行态:指activity运行在屏幕最上层并获得了用户焦点
    • 暂停态:指当前activity依然存在,但是没有获得用户焦点。处于暂停态的activity保留了自己所使用的内存和用户信息,但是在系统极度缺乏资源的状态下,有kennel会被杀死释放资源。
    • 停止态: 指当前activity完全被处于运行态的activity遮挡住,用户完全不能看见该界面。处于停止态的activity依然存活,也保留了自己使用的内存和用户信息,但是一旦系统缺乏资源,停止态的activity会被杀死释放资源。
    方法调用说明
    onCreate(Bundle savedInstanceState)创建Activity时调用。在该方法中,还会以Bundle的形式提供对以前存储的任何状态的访问,其中参数savedInstanceState对象是用于保存Activity的对象状态
    onStart()activity在屏幕上变得用户可见是调用
    onResume()activity开始与用户交互时使用,无论是启动还是重启一个activity,该方法总是会被调用
    onPause()当Android喜用要激活其他activity时,该方法被调用,暂停或者收回CPU和其他资源时调用
    onStop()activity被停止并且转为不可见阶段时调用
    onRestart()重新启动已经停止的activity时调用
    onDestroy()activity被完全从系统内存中移除时使用。该方法被调用可能是因为有人直接调用finish方法或者系统决定停止该活动以释放资源

    activity生命周期解释

    上述七个生命周期方法分别在四个阶段按照一定的顺序进行调用:

    • 启动activity:依次执行onCreate(),onStart(),onResume()
    • activity失去焦点:依次执行onPause(),onStop()
    • activity重获焦点:依次执行onRestart(),onStart() ,onResume()
    • 关闭activity:依次执行onPause(),onStop(),onDestroy()
      请添加图片描述

    Activity组件

    每个android应用都有一个主Activity,相当于java中的main方法。多个Activity可以直接相互调用以完成不同的工作,当新的Activity被启动的时候,之前的Activity会停止,但是不会被销毁,而是被压入Back Stack的栈顶,当用户点击Back按钮时,当前的Activity会被销毁,原先的Activity会被从Back Stack的栈顶弹出并激活。当Activity状态发生改变的时候,都会通过状态回调函数同志Android系统。

    Activity的创建

    • 新建类
      创建一个新的Activity,必须创建Android.app.Activity的一个子类,并且重写onCreate()方法。
    • 关联布局XML文件
      在新建的Activity中设置其布局方式,需要在res/layout目录中新建一个XML布局文件。可以通过setContentView()方法来指定Activity的用户界面的布局文件,如setContentView(R.layout.activity_jarvis)
    • 注册
      AndroidManifes.xml文件中对建立的Activity进行注册,即在application标签下添加activity标签
    <manifest ...>
    	<application ...>
    		<activity Android:name=".ExampleActivity" />
    		对于主Activity,需要为其添加<intent-filter>标签
    		<activity Android:name=".ExampleActivity" >
    			<intent-filter>
    				表示该activity作为主Activity出现
    				<action Android.name="Android.intent.action.MAIN"/>
    				表示该Activity会被显示在最上层的启动列表中
    				<category Android.name="Android.intent.action.LAUNCHER" />
    			</intent-filter>
    		</activity>
    	</application>
    </manifest>
    
    

    Activity的启动

    在Android系统中,除了主Activity由系统启动以外,其他的Activity都需要由应用程序来启动。

    • 通常情况下,需要使用starActivity()方法来启动Activity,而要启动的Activity的信息由Intent对象来传递,如:
    //表示通过当前的Activity来启动AnotherActivity
    Intent intent = new Intet(this , AnotherActivity.class);
    startActivity(intent);
    
    • 有时,用户不需要知道需要启动的Activity的名称,而可以仅制定要完成的行为,由Android系统来为用户挑选合适的Activity:
    Intent intent = new Intent(Intent.ACTION_SEND);
    //Intent.EXTRA_EMAIL中放置的是recipientArray中存储的要发送的Email的目标地址,该Intent对象starActivity方法启动后,Android系统会启动相应的Email处理应用程序,并将Intent.EXTRA_EMAIL中的内容放到邮件的目标地址中
    intent.putExtra(Intent.EXTRA_EMAIL,recipientArray);
    startActivity(intent);
    
    • 当需要从启动的Activity获取返回值时,需要使用startActivityForResult(),并实现onActivityResult()方法来获取返回值。如:
    Intent intent = new Intent(Intent.ACTION_PICK,Contacts.CONTENT_URI);
    startActivityForResult(intent,PICK_CONTACT_REQUEST);
    

    关闭Activity

    关闭Activity使用finish()方法,关闭之前启动过的其他Activity可以使用finishActivity()方法。虽然Android SDK提供了这些方法,但是通常情况下不建议使用其去强制关闭某个Activity。因为Android系统在为用户维护Activity的生命周期,可以动态的回收和重建Activity,因此Activity应该交给Android系统来管理。

    Activity数据传递

    Activity数据传递共有三种形式

    • 通过Intent传递一些简单数据
    //Activity1中传递数据
    Intent intent = new Intent(Activity1.this , Activity2.class);
    intent.putExtra("author","jarvis");//在Intent中添加键值对
    Activity1.this.startActivity(intent);
    
    //在Activity2中获取传递过来的数据
    Intent intent = getIntent();//获取传递过来的Intent
    String value = intent.getStringExtra("author");
    
    • 通过Bundle传递相对复杂的数据或者对象
    //Activity1中传递数据
    Intent intent = new Intent(Activity1.this , Activity2.class);
    Bundle bundle = new Bundle();
    bundle.putString("author","jarvis");
    intent.putExtras(bundle);
    Activity1.this.startActivity(intent);
    
    //在Activity2中获取传递过来的数据
    Intent intent = getIntent();//获取传递过来的Intent
    Bundle bundle = intent.getExtras();
    String value = bundle.getString("author");
    
    • 通过startActivityForResult方法可以更方便的进行来回传递数据
    //Activity1中向Activity2传递数据
    final int REQUEST_CODE = 1;
    Intent intent = new Intent(Activity1.this , Activity2.class);
    Bundle bundle = new Bundle();
    bundle.putString("author","jarvis");
    intent.putExtras(bundle);
    starActivityForResult(intent,REQUEST_CODE);
    
    //同时Activity1还要重载onActivityResult方法,用于接受回调传回来的数据
    protected void onActivityResult(int requestCode , int resultCode , Intent intent){
    	if(requestCode == this.REQUEST_CODE){
    		if(resultCode == 1){
    			Bundle bundle = intent.getExtras();
    			String value = bundle.getString("res");
    		}
    	}
    }
    
    //在Activity2中接受数据并且处理后回传
    Intent intent = getIntent();
    Bundle bundle = intent.getExtras();
    String value = bundle.getString("author");
    
    Intent resIntent = new Intent();
    Bundle resBundle = new Bundle();
    resBundle.putString("res","jarvis");
    resIntent.putExtras(resBundle);
    Activity2.this.setResult(1 , resIntent);
    finish();//结束当前activity
    
    展开全文
  • Android四大核心组件——汇总

    千次阅读 2019-06-03 10:56:21
    onCreate:Activity创建时第一个调用的方法,通常我们在该方法中加载布局文件,初始化UI组件,事件注册等等 onStart:在onCreate方法之后调用,用于显示界面,但用户还不能进行交互 onRestart:当一个stoped状态的...

    一、Activity

    生命周期
    在这里插入图片描述
    七大方法详解
    onCreate:Activity创建时第一个调用的方法,通常我们在该方法中加载布局文件,初始化UI组件,事件注册等等
    onStart:在onCreate方法之后调用,用于显示界面,但用户还不能进行交互

    onRestart:当一个stoped状态的Activity被返回时调用,之后再调用onStart进入运行状态

    onResume:在onStart之后调用,该方法执行完成后,用户可以进行交互,当前Activity进入resumed状态。当一个paused状态的activity被重新返回时,会再次调用该方法,让Activity进入运行状态

    onPause:当其它Activity(透明或窗口模式)进入时,该方法会被调用,让当前Activity进入paused状态(暂停状态)。当前Activity还可见但不可交互,如果其它更高优先级的APP需要内存时,当前Activity可能会被销毁(kill)。当前Activity被返回时会调用onResume方法

    onStop:当其它Activity覆盖该Activity时,会被调用,当前Activity进入stoped状态(停止状态)。不可见,如果其它更高优先级的APP需要内存时,当前Activity可能会被销毁(kill)。 当前Activity被返回时会调用onRestart方法

    onDestroy:当前Activity被销毁时调用,通常在该方法中用来释放资源,当前Activity killed

    四个重要状态
    在这里插入图片描述
    横竖屏切换时Activity的生命周期

    此时的生命周期跟清单文件里的配置有关系。

    ①不设置 Activity 的 android:configChanges 时,横竖屏切换会重新调用各个生命周期,销毁当前 activity,然后重新加载,跟系统配置有关。

    ②onSaveInstanceState()方法会在当前页面销毁前被调用存储数据,onRestoreInstanceState()方法会被执行去取出保存的Bundle对象中的内容,进行一次横竖屏切换时Activity所执行的生命周期方法以及在onSaveInstanceState与onRestoreInstanceState打印相应日志

    Activity的启动模式

    standard模式:默认模式,以这种模式加载必定会构造一个新的Activity实例放到目标Task的activity栈顶,不管当前task的栈顶是什么情况。

    singleTop:这种模式与standard模式类似,区别在于加载activity会多个判断步骤。判断需要加载的新activity与当前task栈顶的activity是不是同一个,相同的话就不再构造新的activity,并调用这个activity的newInstance()方法,不相同就还是会构造新的activity放到栈顶。

    singleTask:这种模式下,会创建一个新的task来加载这个activity,并且这个task中只允许存在一个Activity的一个实例(以后可以加载其他Activity的实例)。

    singleInstance:这种模式下,会创建一个新的task并且这个task中只能存在一个需要加载的这个Activity实例,即除了这个activity之外,不允许其他activity。

    可以在清单文件中activity的launchMode中设置该activity的加载模式

    图解standard模式
    在这里插入图片描述
    在这里插入图片描述

    点击一次ActivityA按钮,会重新创建一个ActivityA进入栈,点击ActivityB按钮会创建一个ActivityB进入栈,所以是不断的重新创建Activity。
    图解singleTop模式
    在这里插入图片描述

    修改了Activity的launchMode为singleTop
    当此时的Activity为ActivityB时,即栈顶为ActivityB,点击按钮不会创建一个新的ActivityB出来,但是,如果是以下情况
    在这里插入图片描述

    点击ActivityB按钮,不会去调用下面的B,而是重新创建一个ActivityB放入栈顶,如图
    在这里插入图片描述

    图解singleTask模式
    在这里插入图片描述

    修改ActivityB的launchMode为singleTask,当这种情况下,点击ActivityB按钮,发现栈内已经有ActivityB时,会把ActivityB之上的Activity清除出栈。
    在这里插入图片描述

    图解singleInstance模式
    在这里插入图片描述
    修改ActivityB的launchMode为singleInstance,此时点击ActivityB按钮是,会新建一个Task,如图,
    在这里插入图片描述

    此时显示的是ActivityB,点击ActivityA按钮后,会返回之前的task并创建一个ActivityA,过程如下
    在这里插入图片描述

    点击返回,会先返回任务栈里的所以Activity,再切换到ActivityB,再返回就退出。

    二、Service
    定义与作用
    — Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。另外,一个组件能够绑定到一个service与之交互(IPC机制),例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行,以上是Google文档的解释,资料来源于大神博客
    — Service还有一个作用就是提升进程(每个应用都是一个进程)的优先级,进程的优先级指的是在Android系统中,会把正在运行的应用确定一个优先级,当内存空间不足时,系统会根据进程的优先级清理掉一部分进程占用的内存空间,以获得足够的内存空间以供新启用的应用运行。详细的进程优先级划分如下,
    1)前台进程:应用程序存在Activity正位于前台,可见并可控
    2)可见进程:应用程序存在Activity处于局部可见状态,即局部可见却不可控
    3)服务进程:应用程序存在正在运行的Service
    4)后台进程:应用程序的所有Activity均被置于后台,没有任何Activity可见
    5) 空进程:已经退出的应用程序

    生命周期
    在这里插入图片描述
    状态
    1)启动
    【启动service】
    用Context类定义的startService(Intent)即可启动Service组件,其中intent定义方法与跳转Activity类似,只需把Actvity类换成Service类即可。其生命周期为启动时onCreate()–>onStartCommand()–>销毁时onDestroy(), 反复调用startService()只会导致Service反复执行onStartCommand()
    【停止service】
    调用Context类定义的stopService(Intent)即可停止Service组件,反复调用并没有任何效果,亦不会报告错误,即:即使停止没有启动的Service也不会出错。也可以在Service类的内部,调用Service定义的stopSelf()方法,停止当前Service。

    2)绑定
    主要作用是实现组件间的通信,实质的表现是Activity可以调用Service中的方法,使Service执行特定的业务,并且这些方法可以是带返回值的方法,进而Activity可以通过获取这些返回值,这样就实现与Service的通信。
    【生命周期】
    – onCreate() -> 当第1次绑定时执行
    – onBind() -> 当第1次绑定时执行
    – onDestroy() -> 当解除绑定时执行

    启动一个服务

    public void startClick(View v){
            Intent intent=new Intent(this,MyService.class);
            startService(intent);
    
        }
    

    停止一个服务

    public void stopClick(View v){
            Intent intent=new Intent(this,MyService.class);
            stopService(intent);
        }
    

    service特性
    (1)Service的粘性:
    当Service被意外终止(非正常停止,即不是通过stopService()或stopSelf()停止)后,会在未来的某一刻自动重启。
    Service的粘性是通过onStartCommand()方法的返回值确定的,可用的值有:
    —–Service.START_REDELIVER_INTENT -> 粘性的,且在自动重启时,会重新给Service发送Intent对象。
    —–Service.START_STICKY -> 粘性的
    —–Service.START_NOT_STICKY -> 非粘性的
    —–Service.START_STICKY_COMPATIBILITY -> 粘性的,并且兼容的
    当需要Service是非粘性的,取值Service.START_NOT_STICKY;当需要Service是粘性的,并且还需要获取Intent对象时,取值Service.START_REDELIVER_INTENT;否则,只是需要粘性的,不需要Intent时,取值super.onStartCommand()默认值。
    (2)Service是单例的,在程序中一个Service类只会存在一个对象
    (3)Service是没有界面的,适合于在后台进行耗时操作,但要注意Service仍然是运行在主线程中的,故耗时的操作还是需要开启子线程来进行。

    三、ContentProvider
    .作用
    中文意思是内容提供者,ContentProvider可以将应用程序自身的数据对外(对其它应用程序)共享,使得其它应用可以对自身的数据进行增、删、改、查操作。
    Android系统使用了许多ContentProvider,将系统中的绝大部分常规数据进行对外共享,例如:联系人资料、通话记录、短信、相册、歌曲、视频、日历等等,一般这些数据都存放于一个个的数据库中。
    应用程序可以在Content Provider中执行如下操作:

    查询数据

    修改数据

    添加数据

    删除数据

    查询记录:
    在Content Provider中使用的查询字符串有别于标准的SQL查询。很多诸如select, add, delete, modify等操作我们都使用一种特殊的URI来进行,这种URI由3个部分组成, “content://”, 代表数据的路径,和一个可选的标识数据的ID。以下是一些示例URI:

    	content://media/internal/images  这个URI将返回设备上存储的所有图片
         content://contacts/people/  这个URI将返回设备上的所有联系人信息
         content://contacts/people/45 这个URI返回单个结果(联系人信息中ID为45的联系人记录)
    

    尽管这种查询字符串格式很常见,但是它看起来还是有点令人迷惑。为此,Android提供一系列的帮助类(在android.provider包下),里面包含了很多以类变量形式给出的查询字符串,这种方式更容易让我们理解一点,参见下例:

    MediaStore.Images.Media.INTERNAL_CONTENT_URI
    Contacts.People.CONTENT_URI
    

    因此,如上面content://contacts/people/45这个URI就可以写成如下形式:

    Uri person = ContentUris.withAppendedId(People.CONTENT_URI,  45);
    

    然后执行数据查询:

    Cursor cur = managedQuery(person, null, null, null);
    

    修改记录:
    我们可以使用ContentResolver.update()方法来修改数据,我们来写一个修改数据的方法:

    private void updateRecord(int recNo, String name) {
        Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, recNo);
        ContentValues values = new ContentValues();
        values.put(People.NAME, name);
        getContentResolver().update(uri, values, null, null);
    }
    

    添加记录:
    要增加记录,我们可以调用ContentResolver.insert()方法,该方法接受一个要增加的记录的目标URI,以及一个包含了新记录值的Map对象,调用后的返回值是新记录的URI,包含记录号。
    上面的例子中我们都是基于联系人信息簿这个标准的Content Provider,现在我们继续来创建一个insertRecord() 方法以对联系人信息簿中进行数据的添加:

    private void insertRecords(String name, String phoneNo) {
        ContentValues values = new ContentValues();
        values.put(People.NAME, name);
        Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
        Log.d(”ANDROID”, uri.toString());
        Uri numberUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
        values.clear();
        values.put(Contacts.Phones.TYPE, People.Phones.TYPE_MOBILE);
        values.put(People.NUMBER, phoneNo);
        getContentResolver().insert(numberUri, values);
    }
    

    删除记录:
    Content Provider中的getContextResolver.delete()方法可以用来删除记录,下面的记录用来删除设备上所有的联系人信息:

    private void deleteRecords() {
        Uri uri = People.CONTENT_URI;
        getContentResolver().delete(uri, null, null);
    }
    

    创建Content Provider
    要创建我们自己的Content Provider的话,我们需要遵循以下几步:

    1. 创建一个继承了ContentProvider父类的类

    2. 定义一个名为CONTENT_URI,并且是public static final的Uri类型的类变量,你必须为其指定一个唯一的字符串值,最好的方案是以类的全名称, 如:
      public static final Uri CONTENT_URI = Uri.parse( “content://com.google.android.MyContentProvider”);

    3. 创建你的数据存储系统。大多数Content Provider使用Android文件系统或SQLite数据库来保持数据,但是你也可以以任何你想要的方式来存储。

    4. 定义你要返回给客户端的数据列名。如果你正在使用Android数据库,则数据列的使用方式就和你以往所熟悉的其他数据库一样。但是,你必须为其定义一个叫_id的列,它用来表示每条记录的唯一性。

    5. 如果你要存储字节型数据,比如位图文件等,那保存该数据的数据列其实是一个表示实际保存文件的URI字符串,客户端通过它来读取对应的文件数据,处理这种数据类型的Content Provider需要实现一个名为_data的字段,_data字段列出了该文件在Android文件系统上的精确路径。这个字段不仅是供客户端使用,而且也可以供ContentResolver使用。客户端可以调用ContentResolver.openOutputStream()方法来处理该URI指向的文件资源,如果是ContentResolver本身的话,由于其持有的权限比客户端要高,所以它能直接访问该数据文件。

    6. 声明public static String型的变量,用于指定要从游标处返回的数据列。

    7. 查询返回一个Cursor类型的对象。所有执行写操作的方法如insert(), update() 以及delete()都将被监听。我们可以通过使用ContentResover().notifyChange()方法来通知监听器关于数据更新的信息。

    8. 在AndroidMenifest.xml中使用标签来设置Content Provider。

    9. 如果你要处理的数据类型是一种比较新的类型,你就必须先定义一个新的MIME类型,以供ContentProvider.geType(url)来返回。MIME类型有两种形式:一种是为指定的单个记录的,还有一种是为多条记录的。这里给出一种常用的格式:

    vnd.android.cursor.item/vnd.yourcompanyname.contenttype (单个记录的MIME类型)
    比如, 一个请求列车信息的URI如content://com.example.transportationprovider/trains/122 可能就会返回typevnd.android.cursor.item/vnd.example.rail这样一个MIME类型。

    vnd.android.cursor.dir/vnd.yourcompanyname.contenttype (多个记录的MIME类型)
    比如, 一个请求所有列车信息的URI如content://com.example.transportationprovider/trains 可能就会返回vnd.android.cursor.dir/vnd.example.rail这样一个MIME 类型。

    四、BroadcastReceiver

    BroadcastReceive简介
    BroadcastReceive也就是“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播。

    广播接收器的类型
    (1)Normal broadcasts:默认广播
    发送一个默认广播使用Content.sendBroadcast()方法,普通广播对于接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,接收者无法终止广播,即无法阻止其他接收者的接收动作。
    (2)Ordered broadcasts:有序广播
    发送一个有序广播使用Content.sendOrderedBroadcast()方法,有序广播比较特殊,它每次只发送到优先级较高的接收者那里,然后由优先级高的接收者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播
    (3)Sticky Broadcast:粘性广播
    当处理完之后的Intent,依然存在,直到你把它去掉。
    广播接收器的创建步骤
    构建Intent,使用sendBroadcast方法发出广播。
    定义一个广播接收器,该广播接收器继承BroadcastReceive,并且覆盖onReceive()方法来响应事件
    注册该广播接收器,我们可以在代码中注册,也可以在清单文件中注册。

    自定义的广播接收器

    public class MyReceiver1 extends BroadcastReceiver {
        public MyReceiver1(){
    
        }
    
        //接收
        @Override
        public void onReceive(Context context, Intent intent) {
            String info=intent.getStringExtra("info");
            Toast.makeText(context,info,Toast.LENGTH_SHORT).show();
        }
    }
    
    

    发送一个普通的广播

    public void sendNormalClick(View v){
            Intent intent=new Intent("com.example.action.MY_BROADCAST");
            intent.putExtra("info","姑娘约否");
            this.sendBroadcast(intent);
        }
    
    

    注册文件中添加对应的action
    在这里插入图片描述
    册广播接收器的两种方式
    静态注册
    静态注册是在AndroidManifest.xml文件中配置。
    动态注册
    动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播

    MyReceiver receiver=new MyReceiver();
    IntentFilter filter=new IntentFilter();
    filter.addAction("android.intent.action.MY_BROADCAST");
    registerReceiver(receiver,filter);
    

    解除注册

    unregisterReceiver(receiver);
    

    有序广播的创建
    先创建两个接收器

    public class MyReceiver3 extends BroadcastReceiver {
        public MyReceiver3(){
    
        }
        @Override
        public void onReceive(Context context, Intent intent) {
           Bundle data= getResultExtras(false);
          String info= data.getString("info");
            Toast.makeText(context,"有序广播-1----"+info,Toast.LENGTH_SHORT).show();
        }
    }
    
    public class MyReceiver4 extends BroadcastReceiver {
            public MyReceiver4(){
    
            }
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"有序广播-2",Toast.LENGTH_SHORT).show();
    
            Bundle data=new Bundle();
            data.putString("info","广播-2");
            this.setResultExtras(data);
        }
    }
    

    发送一个有序广播

     public void sendOrderClick(View v){
            Intent intent=new Intent("com.example.action.MY_BROADCAST2");
            //参数:intent ,接收权限
            this.sendOrderedBroadcast(intent,null);
        }
    
    

    在这里插入图片描述
    其中priority表示优先级,属性范围(-1000,1000),数值越大,优先级越高。
    中断有序广播

    this.abortBroadcast();
    

    同级别接收先后是随机的,再到级别低的收到广播;如果先接收到的把广播截断了,同级别以外的接收者是无法收到该广播的。
    在这个方法发来的广播中(代码注册方式中),收到广播先后次序为:注明优先级的、代码注册的、没有优先级的;如果都没有优先级,代码注册收到为最先。

    粘性广播的创建
    创建一个广播接收器

    public class MyReceiver5 extends BroadcastReceiver {
    public MyReceiver5(){
    
    }
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"接收一个粘性的广播",Toast.LENGTH_SHORT).show();
        }
    }
    

    发送一个粘性广播

    public void sendStickyClick(View v){
                Intent intent=new Intent("com.example.action.MY_BROADCAST3");
            this.sendStickyBroadcast(intent);
        }
    

    粘性广播必须要权限
    在清单文件中加入

     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    

    至此告一段落,写这篇汇总主要是方便自己的查看,为之后的实习做准备,加油呀少年。

    展开全文
  • Android四大核心组件 Activity、BroadcastReceiver、Service、ContentProvider
  • 学习笔记之Android四大核心组件详解

    万次阅读 2016-09-21 18:46:35
    概述Android四大核心组件指的是Activity,Service,ContentProvider,BroadCastReceiver,核心组件都是由Android系统进行管理和维护的,一般都要在清单文件中进行注册或者动态注册。Activity 定义与作用: Activity的...

    概述

    Android四大核心组件指的是Activity,Service,ContentProvider,BroadCastReceiver,核心组件都是由Android系统进行管理和维护的,一般都要在清单文件中进行注册或者在代码中动态注册。

    Activity

    1. 定义与作用: Activity的中文意思是活动,代表手机屏幕的一屏,或是平板电脑中的一个窗口,提供了和用户交互的可视化界面。Activity是用于处理UI相关业务的,比如加载界面、监听用户操作事件。
    2. 生命周期: 生命周期指的是Activity从创建到销毁所执行的一系列方法,主要包括7个生命周期方法。详细流程如下图
      这里写图片描述

      里面涉及了Activity的四个重要状态,如下表
      这里写图片描述
      注:以上两个图表皆摘自《Android从入门到精通》。

    3. 创建与配置 创建一个Activity需继承自android.app.Activity这个类,然后重写onCreate(),在onCreate()里面调用setContentView(参数)来加载布局,参数就是布局文件。
      配置则需要在清单文件的Application节点下面注册Actvitiy,如果要首先启动该Activity则添加带有category节点且值为LAUNCHER的intent-filter节点,下面就是清单文件的配置。
      <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>

    4 . 启动模式
    Activity的启动模式决定了激活Activity时,是否创建新的对象,进而将影响到任务栈也叫回退栈。
    在AndroidManifest.xml文件中,可以为每个activity节点配置android:launchMode属性,以决定该Activity的启动模式,该属性的值有:
    —–standard:(默认值)标准模式:每次激活Activity时,都会创建新的Activity对象
    —–singleTop:栈顶时唯一,即当Activity处于栈顶位置时,每次激活并不会创建新的Activity对象。但不在栈顶时,每次激活时会创建新的对象。
    —–singleTask:任务栈中唯一,即当栈中没有该Activity时,将创建该Activity对象,当栈中已经有该Activity时,将不会创建新的对象,原本栈中位于该Activity之上的其它Activity将全部被强制出栈,且被激活的Activity将自动获得栈顶位置。
    —–singleInstance:实例(对象)唯一,确保该Activity的对象一定只有1个,被设置为singleInstance的Activity将被置于一个专门的任务栈中,且该任务栈中有且仅有一个Activity。
    什么是任务栈(回退栈):
    任务栈是用来存放所有激活了的Activity对象,激活的Acitvity将会按照后进先出的栈结构显示出来。因为屏幕只能显示一个Activity,当有新的Activity被激活时,原来正在显示的Activity就会进行压栈操作被压到新Activity对象下方的位置。当按下”Back”键时栈顶Activity会执行弹栈操作,而在第2位的Activity将获得栈顶位置,显示在前台。

    service

    1. 定义与作用
      — Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。另外,一个组件能够绑定到一个service与之交互(IPC机制),例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行,以上是Google文档的解释,资料来源于大神博客
      — Service还有一个作用就是提升进程(每个应用都是一个进程)的优先级,进程的优先级指的是在Android系统中,会把正在运行的应用确定一个优先级,当内存空间不足时,系统会根据进程的优先级清理掉一部分进程占用的内存空间,以获得足够的内存空间以供新启用的应用运行。详细的进程优先级划分如下,
      1)前台进程:应用程序存在Activity正位于前台,可见并可控
      2)可见进程:应用程序存在Activity处于局部可见状态,即局部可见却不可控
      3)服务进程:应用程序存在正在运行的Service
      4)后台进程:应用程序的所有Activity均被置于后台,没有任何Activity可见
      5) 空进程:已经退出的应用程序
      service的进程优先级详细介绍请参考这篇博文,点此进入

    2 . 状态
    1)启动
    【启动service】
    用Context类定义的startService(Intent)即可启动Service组件,其中intent定义方法与跳转Activity类似,只需把Actvity类换成Service类即可。其生命周期为启动时onCreate()–>onStartCommand()–>销毁时onDestroy(), 反复调用startService()只会导致Service反复执行onStartCommand()
    【停止service】
    调用Context类定义的stopService(Intent)即可停止Service组件,反复调用并没有任何效果,亦不会报告错误,即:即使停止没有启动的Service也不会出错。也可以在Service类的内部,调用Service定义的stopSelf()方法,停止当前Service。

    2)绑定
    主要作用是实现组件间的通信,实质的表现是Activity可以调用Service中的方法,使Service执行特定的业务,并且这些方法可以是带返回值的方法,进而Activity可以通过获取这些返回值,这样就实现与Service的通信。
    【生命周期】
    – onCreate() -> 当第1次绑定时执行
    – onBind() -> 当第1次绑定时执行
    – onDestroy() -> 当解除绑定时执行

    【绑定与解绑】
    调用bindService()方法可以实现Activity与Service的绑定,调用unbindService()可以解除绑定。在Activity被销毁之前,必须解除与Service的绑定。
    具体实现代码如下:

    //在Activity中调用bindService()来实现服务绑定
    Intent intent =new Intent(this,MyService.class);
    //用于连接的对象,相当于组件间的一个连接纽带
    ServiceConnection conn=new ServiceConnection(){
            @Override
            public void onServiceConnected(
                    ComponentName name, 
                    IBinder service) {
                // 当Service已经连接
                //参数IBinder service就是与service进行通信的对象,通过这个对象可以调用Service里的方法
    
            }
            @Override
            public void onServiceDisconnected(ComponentName name) {
                // 当Service断开连接
            }
    };
    //绑定标志
    int FLAGS=BIND_AUTO_CREATE;
    bindService(intent,conn,FLAGS);
    //然后在Activity销毁时解绑,这里需要一个连接对象,所以需要在上面把conn设为全局变量
    @Override
        protected void onDestroy() {
            unbindService(conn);
            super.onDestroy();
        }
    
    //MyService类需要继承自Service,还需要在清单文件中注册
    public class MyService extends Service {
    
        @Override
        public void onCreate() {
        }
    
    
        @Override
        public IBinder onBind(Intent intent) {
        //这里需要返回一个IBinder对象,我们可以创建一个内部类来获得这个对象
            MyBinder binder = new MyBinder();   
            return binder;
        }
    
        /**这个内部类就是我们返回的IBinder类
        Activity的conn里连接上后就是得到这个对象才实现了组件间的通信
        */
        public class MyBinder extends Binder {
            //这个内部类可以写很多方法,来让Activity调用,还可以是带有返回值的方法
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
        }
    
    
    }
    

    下图形象地说明了Service两种状态的生命周期
    两种状态区别

    3.service特性
    【1】Service的粘性:
    当Service被意外终止(非正常停止,即不是通过stopService()或stopSelf()停止)后,会在未来的某一刻自动重启。
    Service的粘性是通过onStartCommand()方法的返回值确定的,可用的值有:
    —–Service.START_REDELIVER_INTENT -> 粘性的,且在自动重启时,会重新给Service发送Intent对象。
    —–Service.START_STICKY -> 粘性的
    —–Service.START_NOT_STICKY -> 非粘性的
    —–Service.START_STICKY_COMPATIBILITY -> 粘性的,并且兼容的
    当需要Service是非粘性的,取值Service.START_NOT_STICKY;当需要Service是粘性的,并且还需要获取Intent对象时,取值Service.START_REDELIVER_INTENT;否则,只是需要粘性的,不需要Intent时,取值super.onStartCommand()默认值。
    【2】Service是单例的,在程序中一个Service类只会存在一个对象
    【3】Service是没有界面的,适合于在后台进行耗时操作,但要注意Service仍然是运行在主线程中的,故耗时的操作还是需要开启子线程来进行。

    ContentProvider

    1.作用 中文意思是内容提供者,ContentProvider可以将应用程序自身的数据对外(对其它应用程序)共享,使得其它应用可以对自身的数据进行增、删、改、查操作。
    Android系统使用了许多ContentProvider,将系统中的绝大部分常规数据进行对外共享,例如:联系人资料、通话记录、短信、相册、歌曲、视频、日历等等,一般这些数据都存放于一个个的数据库中。
    【实现】
    由于ContentProvider可提供增、删、改、查这些操作,通常结合SQLite使用。
    ContentResolver是读取由ContentProvider共享的数据的工具。通过Context类定义的getContentResolver()方法,可以获取ContentResolver对象。如果您不打算与其他应用共享数据,则无需开发自己的提供程序。

    2.访问Content Provider

    Content Provider以一个或多个表(与在关系型数据库中找到的表类似)的形式将数据呈现给外部应用。 行表示提供程序收集的某种数据类型的实例,行中的每个列表示为实例收集的每条数据。

    应用从具有 ContentResolver对象的Content Provider访问数据。 此对象具有调用提供程序对象(ContentProvider 的某个具体子类的实例)中同名方法的方法。 ContentResolver 方法可提供持续存储的基本“CRUD”(创建、检索、更新和删除)功能。

    客户端应用进程中的 ContentResolver 对象和拥有提供程序的应用中的 ContentProvider 对象可自动处理跨进程通信。 ContentProvider 还可充当其数据存储区和表格形式的数据外部显示之间的抽象层。

    注:要访问提供程序,您的应用通常需要在其清单文件中请求特定权限。 内容提供程序权限部分详细介绍了此内容。

    例如,要从用户字典提供程序中获取字词及其语言区域的列表,则需调用 ContentResolver.query()。 query() 方法会调用用户字典提供程序所定义的 ContentProvider.query() 方法。 以下代码行显示了 ContentResolver.query() 调用:

    // Queries the user dictionary and returns results
    mCursor = getContentResolver().query(
        UserDictionary.Words.CONTENT_URI,   // The content URI of the words table,URI映射的数据表名
        mProjection,                        // The columns to return for each row,我们所要我的选择查询的表的列名,字符串数组
        mSelectionClause                    // Selection criteria,查询条件相当于SQL中的where a =? and b = ?
        mSelectionArgs,                     // Selection criteria,字符串数组,替代上面条件中的?占位符
        mSortOrder);                        // The sort order for the returned rows,排列的顺序相当于SQL中的order(字段)

    3.URI 资源访问格式
    内容 URI 是用于在Content Provider中标识数据的 URI。内容 URI 包括整个提供程序的符号名称(其授权)和一个指向表的名称(路径)。 当您调用客户端方法来访问提供程序中的表时,该表的内容 URI 将是其参数之一。

    在前面的代码行中,常量 CONTENT_URI 包含用户字典的“字词”表的内容 URI。 ContentResolver 对象会分析出 URI 的授权,并通过将该授权与已知提供程序的系统表进行比较,来“解析”提供程序。 然后, ContentResolver 可以将查询参数分派给正确的提供程序。

    ContentProvider 使用内容 URI 的路径部分来选择要访问的表。 提供程序通常会为其公开的每个表显示一条路径。

    在前面的代码行中,“字词”表的完整 URI 是:

    content://user_dictionary/words

    其中,user_dictionary 是提供程序的授权,需要在清单文件中注册words 是表的路径; content://(架构)始终显示,并将此标识为内容 URI

    许多提供程序都允许您通过将 ID 值追加到 URI 末尾来访问表中的单个行。 例如,要从用户字典中检索 _ID 为 4 的行,则可使用此内容 URI:

    Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);

    在检索到一组行后想要更新或删除其中某一行时通常会用到 ID 值。

    注:Uri 和 Uri.Builder 类包含根据字符串构建格式规范的 URI 对象的便利方法。 ContentUris 包含一些可以将 ID 值轻松追加到 URI 后的方法。 前面的代码段就是使用 withAppendedId() 将 ID 追加到 UserDictionary 内容 URI 后。

    4.显示数据
    ContentResolver.query() 方法始终会返回符合以下条件的 Cursor:包含查询的表为匹配查询选择条件的行指定的列, Cursor 对象为其包含的行和列提供随机读取访问权限。 通过使用 Cursor 方法,您可以循环访问结果中的行、确定每个列的数据类型、从列中获取数据,并检查结果的其他属性。 某些 Cursor 实现会在提供程序的数据发生更改时自动更新对象或在 Cursor 更改时触发观察程序对象中的方法。

    注:提供程序可能会根据发出查询的对象的性质来限制对列的访问。 例如,联系人提供程序会限定只有同步适配器才能访问某些列,因此不会将它们返回至 Activity 或服务。

    如果没有与选择条件匹配的行,则提供程序会返回 Cursor.getCount() 为 0(空游标)的 Cursor 对象。

    如果出现内部错误,查询结果将取决于具体的提供程序。它可能会选择返回 null,或引发 Exception。

    由于 Cursor 是行“列表”,因此显示 Cursor 内容的较好方式是通过 SimpleCursorAdapter 将其与 ListView 关联。

    以下代码段会创建一个包含由查询检索到的 Cursor 的 SimpleCursorAdapter 对象,并将此对象设置为 ListView 的适配器:

    // Defines a list of columns to retrieve from the Cursor and load into an output row
    String[] mWordListColumns =
    {
        UserDictionary.Words.WORD,   // Contract class constant containing the word column name
        UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name
    };
    
    // Defines a list of View IDs that will receive the Cursor columns for each row
    int[] mWordListItems = { R.id.dictWord, R.id.locale};
    
    // Creates a new SimpleCursorAdapter
    mCursorAdapter = new SimpleCursorAdapter(
        getApplicationContext(),               // The application's Context object
        R.layout.wordlistrow,                  // A layout in XML for one row in the ListView
        mCursor,                               // The result from the query
        mWordListColumns,                      // A string array of column names in the cursor
        mWordListItems,                        // An integer array of view IDs in the row layout
        0);                                    // Flags (usually none are needed)
    
    // Sets the adapter for the ListView
    mWordList.setAdapter(mCursorAdapter);
    注:要通过 Cursor 支持 ListView,游标必需包含名为 _ID 的列。 正因如此,前文显示的查询会为“字词”表检索 _ID 列,即使 ListView 未显示该列。 此限制也解释了为什么大多数提供程序的每个表都具有 _ID 列。

    获取某个列的值

    // 得到words表中WORD的字段标签,也即是上面查询时列名的位置mWordListColumns的下标,这里应该是第一个
    int index =mCursor.getColumnIndex(UserDictionary.Words.WORD);
    if (mCursor != null) {
        while (mCursor.moveToNext()) {
            // 得到该下标列名的值.
            newWord = mCursor.getString(index); 
        }
    } else {
    
    }

    5.创建Content Provider
    实现 ContentProvider 类,实现它的抽象方法。

    query()
    从您的提供程序检索数据。使用参数选择要查询的表、要返回的行和列以及结果的排序顺序。 将数据作为 Cursor 对象返回。
    insert()
    在您的提供程序中插入一个新行。使用参数选择目标表并获取要使用的列值。 返回新插入行的内容 URI。
    update()
    更新您提供程序中的现有行。使用参数选择要更新的表和行,并获取更新后的列值。 返回已更新的行数。
    delete()
    从您的提供程序中删除行。使用参数选择要删除的表和行。 返回已删除的行数。
    getType()
    返回内容 URI 对应的 MIME 类型。实现内容提供程序 MIME 类型部分对此方法做了更详尽的描述。
    onCreate()
    初始化您的提供程序。Android 系统会在创建您的提供程序后立即调用此方法。 请注意,ContentResolver 对象尝试访问您的提供程序时,系统才会创建它。

    设计内容 URI

    内容 URI 是用于在提供程序中标识数据的 URI。内容 URI 包括整个提供程序的符号名称(其授权)和一个指向表或文件的名称(路径)。 可选 ID 部分指向表中的单个行。 ContentProvider 的每一个数据访问方法都将内容 URI 作为参数;您可以利用这一点确定要访问的表、行或文件。

    设计授权
    提供程序通常具有单一授权,该授权充当其 Android 内部名称。为避免与其他提供程序发生冲突,您应该使用互联网网域所有权(反向)作为提供程序授权的基础。 由于此建议也适用于 Android 软件包名称,因此您可以将提供程序授权定义为包含该提供程序的软件包名称的扩展名。 例如,如果您的 Android 软件包名称为

     com.example.<appname>

    就应使用com.example.<appname>.provider 授权。

    设计路径结构
    开发者通常通过追加指向单个表的路径来根据权限创建内容 URI。 例如,如果您有两个表:table1 和 table2,则可以通过合并上一示例中的权限来生成 内容 URI com.example..provider/table1 和 com.example..provider/table2。路径并不限定于单个段,也无需为每一级路径都创建一个表。

    处理内容 URI ID
    按照惯例,提供程序通过接受末尾具有行所对应 ID 值的内容 URI 来提供对表中单个行的访问。 同样按照惯例,提供程序会将该 ID 值与表的 _ID 列进行匹配,并对匹配的行执行请求的访问。

    这一惯例为访问提供程序的应用的常见设计模式提供了便利。应用会对提供程序执行查询,并使用 CursorAdapter 以 ListView 显示生成的 Cursor。 定义 CursorAdapter 的条件是, Cursor 中的其中一个列必须是 _ID

    用户随后从 UI 上显示的行中选取其中一行,以查看或修改数据。 应用会从支持 ListView 的 Cursor 中获取对应行,获取该行的 _ID 值,将其追加到内容 URI,然后向提供程序发送访问请求。 然后,提供程序便可对用户选取的特定行执行查询或修改。

    内容 URI 模式
    为帮助您选择对传入的内容 URI 执行的操作,提供程序 API 加入了实用类 UriMatcher,它会将内容 URI“模式”映射到整型值。 您可以在一个 switch 语句中使用这些整型值,为匹配特定模式的一个或多个内容 URI 选择所需操作。

    内容 URI 模式使用通配符匹配内容 URI:

    *:匹配由任意长度的任何有效字符组成的字符串
    #:匹配由任意长度的数字字符组成的字符串

    以设计和编码内容 URI 处理为例,假设一个具有授权
    com.example.app.provider 的提供程序能识别以下指向表的内容 URI:

    content://com.example.app.provider/table1:一个名为 table1 的表
    content://com.example.app.provider/table2/dataset1:一个名为 dataset1 的表
    content://com.example.app.provider/table2/dataset2:一个名为 dataset2 的表
    content://com.example.app.provider/table3:一个名为 table3 的表
    提供程序也能识别追加了行 ID 的内容 URI,例如,content://com.example.app.provider/table3/1 对应由 table3 中 1 标识的行的内容 URI。

    可以使用以下内容 URI 模式:

    content://com.example.app.provider/*
    匹配提供程序中的任何内容 URI。
    
    content://com.example.app.provider/table2/*:
    匹配表 dataset1 和表 dataset2 的内容 URI,但不匹配 table1 或 table3 的内容 URI。
    
    content://com.example.app.provider/table3/#:匹配 table3 中单个行的内容 URI,如 content://com.example.app.provider/table3/6 对应由 6 标识的行的内容 URI。

    在清单文件中注册实现content provider的类

    与 Activity 和 Service 组件类似,必须使用 provider 元素在清单文件中为其应用定义 ContentProvider 的子类。 Android 系统会从该元素获取以下信息:

    授权 (android:authorities)
    用于在系统内标识整个提供程序的符号名称,也即是上面所说的URI包含路径名表名的字符串。
    提供程序类名 ( android:name )
    实现 ContentProvider 的类。实现 ContentProvider 类中对此类做了更详尽的描述。

    BraodCast Receiver

    1.概述
    广播接收器,顾名思义这是用于接收应用发送的广播的系统组件。广播是一种1对多的通信方式,即存在1个发送方,若干个接收方。在Android系统,把具有这样的数据的传递方式的机制称之为“广播”。Android系统会在特定的情景下发出各种广播,例如开机、锁屏了、电量不足了、正在充电了、呼出电话了、被呼叫了……
    广播是一种跨进程的、“全设备之内”的通信方式。

    2.发送广播
    调用Context对象的sendBroadcast(Intent)即可发送广播,在参数Intent对象中,应该调用setAction()方法配置广播的“频道号”,即是相当于收音机要接收某个电台的频段,只有注册了相同的Action的广播接收者才可以接收到该广播。

    3.接收广播
    自定义类,继承自android.content.BroadcastReceiver后需要注册,注册时,使用IntentFilter配置与发送方相同的Action,重写onReceiver()方法实现对广播的处理。

    public class MyBroadcastReceiver extends BroadcastReceiver {
        private static final String TAG = "MyBroadcastReceiver";
        @Override
        public void onReceive(Context context, Intent intent) {
            StringBuilder sb = new StringBuilder();
            sb.append("Action: " + intent.getAction() + "\n");
            sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
            String log = sb.toString();
            Log.d(TAG, log);
            Toast.makeText(context, log, Toast.LENGTH_LONG).show();
        }
    }

    4.注册广播接收器
    广播接收者的注册可以区分为静态注册和动态注册:

    • 静态注册:在清单文件AndroidManifest.xml中,在application节点下使用receiver节点进行注册。这种方式注册的广播接收者必须是一个单独的只实现BroadcastReceiver的类,不能是内部类。且这样的广播接收者是常驻型的,即从APP安装到手机上的那一刻即开始处于接收广播状态,且直至该APP被从手机移除。
    <receiver android:name=".MyBroadcastReceiver"  android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
        </intent-filter>
    </receiver>
    • 动态注册:在程序中调用Context对象的registerReceiver(BroadcastReceiver, IntentFilter)方法进行注册。这种方式可以注册以内部类的形式存在的广播接收者,且这种方式的广播接收者仅当注册后才开始接收广播,并且在调用了Context对象的unregisterReceiver(BroadcastReceiver)方法后就会停止接收广播。
    BroadcastReceiver br = new MyBroadcastReceiver();
    IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
    intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    this.registerReceiver(br, filter);

    5.无序广播与有序广播
    1. 普通的广播即为无序广播,谁都可以接收,并不会相互打扰。
    2. 有序广播:调用sendOrderedBroadcast(Intent, String permission)方法发送的广播,各广播接收者在接收广播时,会存在一定的先后顺序,即某接收者会先收到广播,其他接收者后收到广播,广播会在各接收者之间按照一定的先后顺序进行传递。在广播的传递过程中,先接收到广播的接收者可以对广播进行拦截或篡改。

    6.有序广播的接收者们的优先级
    有序广播的接收者们的优先级用于确定接收的先后顺序,优先级越高的接收者,将更优先接收到广播,反之,则更靠后接收到广播。
    1. 注册广播时,在广播对应的IntentFilter中的priority属性直接决定优先级,该属性值为int类型的数值,取值越大,则优先级越高!
    2. 如果存在多个广播接收者配置的priority属性值相同,则动态注册的广播接收者的优先级高于静态注册的广播接收者。
    3. 如果根据以上2条规则都无法确定优先级,则根据注册的先后顺序确定各接收者们的优先级。

    7.有序广播的拦截或篡改
    1. 【拦截】在广播接收者中,使用abortBroadcast()方法,可以终止有序广播向后继续传递,即后续的接收者们将无法接收到该广播。注意:该方法只能在接收有序广播时调用!
    2. 【篡改】在广播接收者中,调用setResult()方法,可以向广播中添加数据,并在后续的接收者中,可以通过getResult()获取这些数据,同时,后续的接收者也可以再次调用setResult()方法重新向广播中写入数据,即覆盖原有的数据,以实现篡改。

    展开全文
  • 之前在用到ContentProvider时也是在网上找的教程,但是按照那些做法不怎么全面,我是没有实现出来,并且对于报错也没有给出解释原因与解决办法,也是通过借鉴与自己摸索,将自己 的一点想法分享出来。...
  • Activity 活动代表了一个具有用户界面的单一屏幕。   三个状态:运行、停止、暂停; 生命周期: 回调 描述 onCreate() 这是第一个回调,在活动第一次创建是调用 ... 被暂停的活动无法接受...
  • 安卓 四大组件

    万次阅读 多人点赞 2018-06-29 11:16:46
    Android四大组件分别为activity、service、content provider、broadcast receive 一、Activity Activity生命周期的方法是成对出现的 onCreate() &amp; onDestory() onStart() &amp; onStop() ...
  • Android 四大组件通信核心 我们知道Android 四大组件:Activity/Service/Broadcast/ContentProvider 能够进行跨进程通信,它们均是借助Binder实现跨进程通信的能力。四者之间又有千丝万缕的联系,本篇将从宏观角度...
  • Android四类核心组件类介绍Android划分了四类核心组件类: Activi11y、 Servlce、 Broadcast Receiver和 ContentProvider,相同组件和不同组件之间的导航通过1ntent来完成, Android还定义了view类来显示可视化界面...
  • 对于许多初学者来说,Android四大组件理解起来有一定难度,鉴于此,我写下了这篇文章,希望对大家有所帮助。  Activity 是Android系统API的一个类,主要用来进行用户和系统进行交互,换句话说就是一个程序的窗口...
  • Android四大组件之Service

    千次阅读 2021-11-11 10:22:55
    Android四大组件之一:Service是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件; 服务是Android中实现程序后台的解决方案,不依赖任何用户界面,即使程序被切换到后台,或者用户打开了另外一个应用...
  • 导语本章的意义在于加深对四大组件工作方式的认识,有助于加深对Android整体的体系结构的认识。很多情况下,只有对Android的体系结构有一定认识,在实际开发中才能写出优秀的代码。 读者对四大组件的工作过程有一个...
  • Android 开发的四大组件分别是:活动(activity),用于表现功能;服务(service),后台运行服务,不提供界面呈现;广播接受者(Broadcast Receive),勇于接收广播;内容提供者(Content Provider),支持多个应用...
  • Android四大核心组件(五大核心组件)分别是Activity,Service,Intent,Content Provider,BroadCast Receiver等,它们都具有良好的生命周期,在android开发中,经常会使用到这几大核心组件的,下面将用简短的语句来...
  • 关于Android四大核心组件,在这次文章中会介绍Activity
  • Android四大组件分别是: 1.activity 显示界面 2.service 服务 3.Broadcast Receiver 广播 4.Content Provider 数据通信 1. activity 显示页面: a.首先activity就是一个单独的窗口; 一个activity相当于我们...
  • 安卓四大核心组件要点汇总

    千次阅读 2019-06-03 11:16:56
    四大核心组件 活动(activity),用于表现功能; 服务(service),后台运行服务,不提供界面呈现; 广播接受者(Broadcast Receive),用于接收广播; 内容提供者(Content Provider),支持多个应用中存储和读取...
  • Android的一个核心特性就是一个应用程序可作为其他应用程序中的元素,可为其他应用程序提供数据。例如,如果程序需要用某些控件来加载一些图片,另一个程序已经开发出了此项功能,且可供其他程序使用,就可以直接...
  • BroadcastReceiver(广播接收器),属于Android四大组件之一 在Android开发中,BroadcastReceiver的应用场景非常多广播,是一个全局的监听器,属于Android四大组件之一 Android 广播分为两个角色:广播发送者、...
  • 安卓分为四个层,从高层到底层分别是应用程序层(Applications),应用程序框架层(Application Framework),系统运行库层(Libraries)和运行环境层(Android Runtime)、linux核心层(Linux Kernel)。 应用程序层...
  • ActivityActivity是Android系统的核心组件之一!由Android系统进行管理和维护!Activity表现为处理所有与UI相关的业务!Activity的生命周期在Android系统中,将Activity也划分出了不同的生命周期阶段,并且在不同的...
  • Android 安卓 四大组件

    2018-11-25 18:09:28
    Android四大组件分别为activity、service、content provider、broadcast receive  一、Activity    Activity生命周期的方法是成对出现的 onCreate() &amp; onDestory()  onStart() &amp; onStop()  ...
  • Android四大组件

    2021-03-29 15:42:15
    Android四大组件 Activity(活动) 是android程序与用户交互的窗口,可以显示一些空间用于监听并处理用户的事件 生命周期 有四个状态、七个方法、两个异常 四个状态 Running:处于栈的最顶端,此时处于不可见并可和...
  • Android主要有以下四大组件。 Activity Activity就是用户与应用程序互动的界面。Activity总共有6种状态,Created, Started, Resumed, Paused, Stopped, Destroyed。与此同时,有以下7个回调函数使得其状态发生转换。...
  • Android 四大核心组件

    2016-05-25 18:46:20
    Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器。 一:了解四大基本组件 Activity : 应用程序中,一个Activity通常就是一个单独的屏幕,它上面可以...
  • ContentProvider是Android四大组件之一,其本质上是一个标准化的数据管道,它屏蔽了底层的数据管理和服务等细节,以标准化的方式在Android 应用间共享数据、数据交互,跨进程通信。 原理 ContentProvider的底层是...
  • android 生命周期图  
  • Android四大组件生命周期

    千次阅读 2018-04-06 22:08:51
    核心方法insert,delete,update,query <3>ContentResolver类    统一管理不同BrodcastReceiver之间的操作,提供了与BrodcastReceiver同名&作用的4个方法。 <4>UriMatcher类  步骤1:UriMatcher matcher = new ...
  • Android四大核心组件:Activity,Service,BroadcastReceiver,ContentProvider,这四大组件Android开发过程是每天几乎都会用到,所以我觉得有必要对这四大组件详细说明一下,本文中我会介绍一下什么是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,009
精华内容 5,203
关键字:

安卓四大核心组件