一文看懂Android的四大组件,快速入门必备!!!

Activity

定义与背景

  • Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互以完成某项任务。它就像是一个舞台,在这个舞台上,用户可以看到各种界面元素,如按钮、文本框、列表等,并与它们进行交互。例如,在一个购物应用中,商品列表页、商品详情页、购物车页等都是Activity,用户可以在这些页面上查看商品信息、添加商品到购物车、进行结算等操作。

Activity 的启动模式

Activity的启动模式是指决定生成新的Activity实例时是否重用已存在的Activity实例,以及是否和其他Activity实例公用一个任务栈(task)的规则。

standard(标准模式)

想象你有一个任务栈就像一个放东西的盒子。在这种模式下,每次你想要打开(激活)一个Activity,就像往这个盒子里放一个新的东西(创建一个新的Activity实例)。不管这个东西(Activity)之前有没有在盒子里,每次都放一个新的进去。

例如,你打开一个新闻应用,每次点击一篇新闻进入新闻详情页,都会创建一个新的新闻详情Activity实例并放入任务栈。

singleTop(单一顶部模式)

还是把任务栈当作盒子。如果某个Activity(我们叫它A)在盒子的最上面(也就是任务栈的栈顶),然后又要再次打开这个A,那就不需要再创建一个新的A了,就像盒子最上面已经有这个东西了,就不用再放一个新的了。但是如果A不在盒子最上面,或者盒子里根本没有A,那就要创建一个新的A并放入盒子(任务栈)。

比如,在一个搜索结果页面,如果这个页面在栈顶,再次搜索进入这个页面就不用创建新的实例。

singleTask(单一任务模式)

把任务栈当作一个有顺序的架子。如果要打开的Activity(假设是B)已经在这个架子(任务栈)上了,那就不需要创建新的B了。而且要把B放到架子的最上面(任务栈的栈顶),同时把B上面的其他东西(Activity实例)都拿下来(出栈)。就好像你要找一个东西,这个东西在架子中间,你把它拿出来放到最上面,同时把它上面的东西都移走。

例如,在一个电商应用中,商品列表页、商品详情页、购物车页,如果商品详情页是singleTask模式,当从购物车页再进入商品详情页时,商品详情页会被移到栈顶,中间可能有的其他页面(如果有的话)会出栈。

那在singleTask(单一任务模式)模式下,出栈的activity重新被调用是不是要从头开始走生命周期?

singleTask模式下,当重新启用出栈后的Activity时,由于处于非栈顶的Activity都被完全覆盖了,所以生命周期不仅仅会运行onPause还会到onStop,在重新启用时,会先调用onRestart,再执行onStart - onResume的顺序,而不是从头开始走生命周期。

当在singleTask模式下,Activity B上面的其他Activity出栈后,这些Activity就从任务栈中移除了。

对于出栈Activity的生命周期是怎么样的?

  • 首先会执行onPause方法,因为即将失去焦点。

  • 接着执行onStop方法,因为已经不可见了。

  • 如果系统内存紧张等情况,这些出栈的Activity实例可能会被销毁,此时会执行onDestroy方法。如果没有被销毁,当再次需要显示这些Activity时(例如通过回退操作等),会从onRestart方法开始,接着执行onStartonResume方法来重新显示。

singleInstance(单一实例模式)

这就像给某个特殊的Activity(假设是C)单独建了一个小盒子(独立的任务栈),这个小盒子里只有C这一个东西(Activity实例),不允许有其他的Activity在这个小盒子里。当需要打开C的时候,就直接找到这个单独的小盒子里的C,而且整个应用里只有这一个C的实例。

比如,在一个音乐播放应用中,音乐播放的控制界面可能是singleInstance模式,它独立运行在自己的小任务栈中,和其他页面分开。

Activity的生命周期

img

Activity的生命周期就像是一个人的成长过程,有不同的阶段。

启动阶段(onCreate)
  • 这就像是一个人出生的时候。当Activity被创建时,会调用onCreate方法。在这个阶段,你可以做一些初始化的工作,比如设置布局(就像给人穿上衣服),初始化一些变量等。例如:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity_main);  
    // 这里可以初始化变量,比如定义一个计数器并初始化为0 
    int count = 0; 
} 
可见阶段(onStart)
  • 这相当于人已经出现在大家面前了,但还没有完全准备好互动。当Activity变得可见时,会调用onStart方法。此时,Activity已经在屏幕上显示了一部分,但可能还没有获取到焦点(就像人在舞台上,但还没有开始表演)。

可交互阶段(onResume)
  • 这就像人已经完全准备好,可以和外界互动了。当Activity获取到焦点,可以和用户进行交互时,会调用onResume方法。例如,用户可以在这个时候点击按钮、输入文字等。

暂停阶段(onPause)
  • 这有点像人突然被打断了一下。当有另一个Activity部分覆盖当前Activity时(比如弹出一个透明的对话框),当前Activity会进入onPause状态。在这个阶段,Activity仍然是可见的,但不能完全和用户交互了。例如,你正在玩一个游戏(Activity),突然来了一个电话通知(另一个Activity部分覆盖),游戏就暂停了。不过在这个阶段,你可以保存一些临时的数据,比如游戏的当前进度。

停止阶段(onStop)
  • 这就像人离开了舞台,看不到了。当Activity完全被另一个Activity覆盖时,会调用onStop方法。此时Activity虽然还在内存里(就像人虽然不在舞台上了,但还在后台准备着),但是不再与windowmanager联接了。如果系统内存不足,这个停止的Activity可能会被销毁。

重新启动阶段(onRestart)
  • 这就像人又重新回到舞台准备再次表演。当一个已经停止的Activity再次被启动时,会先调用onRestart方法,然后再走onStartonResume的流程。

销毁阶段(onDestroy)
  • 这就像人彻底消失了。当Activity被销毁时,会调用onDestroy方法。可能是因为用户按了返回键,或者系统为了释放内存而销毁了这个Activity。在这个阶段,你可以释放一些资源,比如关闭数据库连接、停止正在播放的音乐等。

Activity的跳转方式

根据搜索结果可知有两种跳转方式,并没有提及三种跳转方式,以下是这两种跳转方式的讲解:

无返回数据的跳转

startActivity无返回数据的跳转

就像是你从一个房间(Activity)走到另一个房间(另一个Activity),只是单纯地过去,不需要带任何东西回来。

例如,从主页面(FirstActivity)跳转到一个设置页面(SecondActivity),只是进入设置页面进行一些设置操作,不需要把设置页面的任何数据返回给主页面。

在代码中,就像这样:

public void onClick(View arg0) { 
    //跳转到SecondActivity并传值 
    Intent intent = new Intent(FirstActivity.this,  SecondActivity.class);  
    startActivity(intent); 
} 
有返回数据的跳转

startActivityForResult(intent, int requestCode)有返回数据的跳转

  • 这就好比你从一个房间(FirstActivity)去另一个房间(SecondActivity)拿东西,然后再回来。

  • 在SecondActivity中通过setResult(RESULT_CODE, intent);设置返回的数据。例如,从主页面跳转到一个选择联系人的页面,在选择联系人页面选择好联系人后,要把选择的联系人信息返回给主页面。

  • 在FirstActivity中重写onActivityResult()方法就可以拿到返回的数据。代码大概是这样的:

  • 在FirstActivity中跳转:

public void onClick(View arg0) { 
    //跳转到SecondActivity并传值 
    Intent intent = new Intent(FirstActivity.this,  SecondActivity.class);  
    startActivityForResult(intent, 1); //这里的1就是requestCode,用于标识请求 
} 
  • 在SecondActivity中设置返回数据:

Intent resultIntent = new Intent(); 
resultIntent.putExtra("selected_contact",  "张三"); 
setResult(RESULT_OK, resultIntent); 
finish(); 
  • 在FirstActivity中接收返回数据:

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode,  resultCode, data); 
    if (requestCode == 1 && resultCode == RESULT_OK) { 
        String selectedContact = data.getStringExtra("selected_contact");  
        // 这里就得到了从SecondActivity返回的联系人信息 
    } 
} 

Service

定义与背景

由于手机屏幕的限制,通常情况下在同一时刻仅有一个应用程序处于激活状态,并能够显示在手机屏幕上,因此,应用程序需要一种机制,在没有用户界面的情况下,能够长时间在后台运行,实现应用程序的特定功能,并能够处理事件或更新数据。Android 系统提供了 Service 服务组件,它不直接与用户进行交互,却能够长期在后台运行。有很多情况需要使用 Service,典型的例子就是:MP3 播放器。

Service 非常适用于无需用户干预,且需要长期运行的后台功能。Service 没有用户界面,有利于降低系统资源。而且 Service 比 Activity 具有更高的优先级,只有在系统资源极度匮乏的情况下,android 系统才可能清理掉一部分 service 来保证系统的运行,而这种情况却又轻易不会出现。即使 Service 被系统终止了,在系统资源恢复后 Service 也将自动恢复运行状态,因此可以认为 Service 是在系统中永久运行的组件。Service 除了实现后台服务功能,还可以用于进程间通信,解决两个不同 Activity 应用程序进程之间的调用和通信问题。

Service的使用

安卓的Service(服务)是一种可以在后台执行长时间运行操作而没有用户界面的应用组件。

  1. 功能示例

    • 它可以处理网络事务,比如在后台持续下载文件,即使你切换到其他应用,下载也能继续进行。

    • 能够播放音乐,当你在手机上打开音乐播放器开始播放音乐后,即使你退出音乐播放器界面去做其他事情,如查看邮件、浏览网页等,音乐依然可以通过Service在后台持续播放。

    • 执行文件I/O操作,例如在后台对手机存储中的文件进行读写操作。

    • 与内容提供程序交互,获取或更新手机中的联系人、短信等数据。

  2. 类型

    • 启动状态(startService启动)

      • 当应用组件(如Activity)通过调用startService()启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件(如Activity)已被销毁也不受影响,除非手动调用才能停止服务。已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,一个后台文件下载服务,启动后就持续下载文件,不需要给启动它的Activity反馈下载结果。

    • 绑定服务(bindService启动)

      • 提供了一个客户端 - 服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信(IPC)跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。比如,一个音乐播放服务,Activity可以绑定到这个服务上,向它发送播放、暂停、切换歌曲等请求,并且能获取当前播放歌曲的相关信息(如歌名、时长等)。

  3. 在清单文件中的声明

    • 无论Service是启动状态还是绑定状态,都是通过继承Service基类自定义而来,并且都需要在AndroidManifest.xml 中声明。这就像是给安卓系统一个通知,告诉它这个应用有这样一个服务组件。

  4. 使用场景

    • startService:适用于需要在后台长时间运行的任务,例如下载文件、播放音乐等。

    • bindService:适用于需要与服务频繁交互的任务,例如获取实时数据、控制服务行为等。

  5. 交互场景

    • startService:不提供直接与组件交互的接口,主要用于执行后台任务。

    • bindService:提供与组件交互的接口,组件可以调用服务中的方法进行通信。

Service的生命周期

  1. 启动状态(StartedService)的生命周期

    • onCreate()

      • 这个方法在服务第一次被创建时调用,就像服务的“出生”阶段。在这里可以进行一些一次性的初始化操作,例如初始化一些变量、加载资源等。例如,如果服务需要连接数据库,就可以在onCreate方法中建立数据库连接。

    • onStartCommand()

      • 在程序中调用context.startService() 时会触发这个方法(在2.0以前版本中,使用onStart()回调方法)。如果服务还没有运行,那么Android系统会先调用onCreate()然后调用onStartCommand();如果服务已经运行,则只调用onStartCommand()。所以一个服务的onStartCommand方法可能会重复调用多次。这个方法是服务开始运行的标志,在这个方法里可以处理服务的主要业务逻辑,比如开始一个耗时的操作,像在后台持续下载文件或者播放音乐等。

    • onDestroy()

      • 当在程序中调用context.stopService() 时会触发执行这个回调方法,这是服务的“死亡”阶段。在这个方法里可以进行一些清理操作,例如释放资源,如果之前在onCreate中建立了数据库连接,那么可以在onDestroy中关闭数据库连接。如果是调用者自己直接退出而没有调用stopService()的话,Service会一直在后台运行。

  2. 绑定服务(bindService)的生命周期

    • onCreate()

      • 同样是在服务第一次创建时调用,进行初始化操作。

    • onBind()

      • 当组件(如Activity)调用bindService()方法绑定到这个服务时,会调用onBind()方法。这个方法返回一个IBinder对象,它是服务与绑定组件之间通信的接口。例如,一个音乐播放服务,当Activity绑定到这个服务时,onBind()方法返回的IBinder对象可以让Activity向服务发送播放、暂停等指令。

    • onUnbind()

      • 当所有绑定到服务的组件都调用unbindService()方法解除绑定后,会调用onUnbind()方法。在这个方法里可以进行一些与解除绑定相关的操作,比如清理与绑定组件之间的通信相关的资源。

    • onDestroy()

      • 当没有任何组件绑定到服务,并且服务也没有被启动(startService)时,服务会被销毁,此时调用onDestroy()方法进行最后的清理工作。

  1. 总结

  • startService:服务由 startService 启动后会一直运行,直到调用 stopSelf() 或 stopService()。它不依赖于启动它的组件的生命周期。

  • bindService:服务由 bindService 启动后会在所有绑定的组件解除绑定时停止。它的生命周期依赖于绑定的组件。

ContentProvider

定义与背景

  • 安卓中的ContentProvider(内容提供者)就像是一个数据共享的“桥梁”或者“中介”。它是安卓中的四大组件之一。

  • 想象你有一个房子(一个安卓应用),房子里有很多东西(数据,比如联系人信息、短信内容、图片等)。ContentProvider的作用就是把房子里的这些东西(数据)拿出来,分享给其他房子(其他安卓应用)使用。

主要用途 - 数据共享

  • 例如,手机里有一个联系人管理应用,这个应用里存储了联系人的姓名、电话、邮箱等信息。如果有另一个应用,比如一个短信群发应用,它想要获取联系人的电话号码来发送短信,就可以通过ContentProvider来获取联系人应用中的电话号码数据。

  • 再比如,相册应用存储了很多图片,而一个图片编辑应用想要获取相册里的图片进行编辑,也是通过ContentProvider来实现数据的获取。

采用的是一种叫做 匿名共享内存的方式进行数据传递,在不同的进程中只需要传递一个文件描述符就可以。

通过下图对 content provider 有个比较直观的了解:

img

ContentProvider的类型

  • 系统的ContentProvider

    • 就像手机系统自带的一些数据,如联系人、短信、图片等都有对应的系统ContentProvider。这些系统级别的数据可以被其他应用访问(当然,需要相应的权限)。例如,当你安装一个新的社交应用时,它可能会请求读取你的联系人信息,这就是通过系统的联系人ContentProvider来实现的。

  • 自定义的ContentProvider

    • 除了系统提供的,开发者也可以创建自己的ContentProvider。假设你开发了一个笔记应用,这个应用里存储了用户的笔记内容。如果你想让其他应用也能使用这些笔记内容(比如一个统计笔记字数的小工具应用),就可以创建一个自定义的ContentProvider来共享笔记数据。

ContentProvider的使用

  • 其他应用要想使用ContentProvider共享的数据,需要通过ContentResolver这个对象。ContentResolver就像是一个“办事员”,它知道如何与ContentProvider打交道。

  • 例如,如果要查询联系人的电话号码,首先要获取ContentResolver对象(在安卓的Activity或者其他组件中可以很容易获取到),然后使用ContentResolver的query方法来查询ContentProvider中的数据。就像你要找联系人的电话号码,先找到办事员(ContentResolver),然后让办事员去联系人数据的“仓库”(ContentProvider)里查询电话号码。

  • 同样,如果要插入、更新或者删除ContentProvider中的数据,也可以通过ContentResolver的insertupdatedelete方法来操作。

ContentProvider共享原理

在Android中,ContentProvider使用URI(统一资源标识符)来标识要操作的数据资源。就像每个地方都有一个地址一样,URI就是ContentProvider中数据的“地址”。

在 Android 中 URI 的格式如下:

URI = <schema>://<authority>/<path>/<id>

例如:content://com.jeanboy.provider/User/1

  • 主题(schema)

ContentProvider 的 URI 前缀,表示是一个 Android 内容 URI,说明由 ContentProvider 控制数据,该部分是固定形式,不可更改。

  • 授权信息(authority)

URI 的授权部分,是唯一标识符,用来定位 ContentProvider。格式一般是自定义 ContentProvider 类的完全限定名称,注册时需要用到。如:com.jeanboy.provider.TestProvider。

比如,对于系统的联系人ContentProvider,它可能有一个特定的授权名称,像contacts之类的(实际情况可能更复杂)。不同的ContentProvider有不同的授权名称,就像不同的公司有不同的名字一样。当你想要访问某个ContentProvider的数据时,通过这个授权名称就能找到对应的ContentProvider。

  • 表名(path)

路径片段,一般用表的名字,指向数据库中的某个表名。

例如,在联系人ContentProvider中,<path>可能是contacts/phones表示要访问联系人的电话号码数据集合。这就像是在一个公司(ContentProvider)里,<path>指向了具体的部门(数据类型或集合)。

  • 记录(id)

指向特定的记录,如表中的某个记录(若无指定,则返回全部记录)。

比如在联系人的电话号码数据集合中,如果<id>123,可能表示联系人中某个特定联系人(其电话号码记录对应的id为123)的电话号码信息。这就像是在一个部门(由<path>指定)里,<id>指向了具体的一个员工(具体的数据项)。

BroadcastReciver

定义与背景

  • Broadcast Receiver(广播接收器)就像是一个收音机,它可以接收来自系统或者应用发出的广播消息。在安卓系统中,很多事件都会以广播的形式发送出去,例如电池电量变化、网络连接状态改变、系统启动完成等。Broadcast Receiver的任务就是监听这些广播,当接收到自己感兴趣的广播时,就可以做出相应的反应。

Broadcast Receiver的注册

  • 静态注册 ——在 AndroidManifest.xml 里通过 < receive 标签声明

    • 这种方式是在AndroidManifest.xml 文件中进行注册。就像在房子(安卓应用)的蓝图(清单文件)里提前设置好一个收音机(Broadcast Receiver),告诉系统这个收音机要接收哪些广播。例如,要接收电池电量变化的广播,可以在清单文件中这样注册:

    <receiver android:name=".MyBroadcastReceiver"> 
        <intent - filter> 
            <action android:name="android.intent.action.BATTERY_CHANGED"/>  
        </intent - filter> 
    </receiver> 
    • 这里定义了一个名为MyBroadcastReceiver的广播接收器,并且通过<intent - filter>指定它要接收电池电量变化(android.intent.action.BATTERY_CHANGED )这个广播。

  • 动态注册 ——在代码中调用 Context.registerReceiver() 方法

    • 动态注册是在代码中进行注册的。这就好比你在房子(应用)里临时放一个收音机(Broadcast Receiver)来接收广播。例如,在一个Activity中:

    Java复制public class MainActivity extends Activity { 
        private MyBroadcastReceiver myBroadcastReceiver; 
    ​
        @Override 
        protected void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_main);  
    ​
            myBroadcastReceiver = new MyBroadcastReceiver(); 
            IntentFilter intentFilter = new IntentFilter(); 
            intentFilter.addAction("android.intent.action.BATTERY_CHANGED");  
            registerReceiver(myBroadcastReceiver, intentFilter); 
        } 
    ​
        @Override 
        protected void onDestroy() { 
            super.onDestroy();  
            unregisterReceiver(myBroadcastReceiver); 
        } 
    } 
    • onCreate方法中创建了MyBroadcastReceiver并注册它来接收电池电量变化的广播,然后在onDestroy方法中要记得取消注册(unregisterReceiver),就像把收音机拿走一样。

Broadcast Receiver的类型

  • 普通广播(Normal Broadcast)

    • 普通广播是完全异步的广播。就像在一个大广场上喊一句话,听到的人(广播接收器)可以同时做出反应,没有先后顺序。发送普通广播的速度比较快,因为它不需要等待每个接收器都处理完。例如,一个应用可以发送一个普通广播来通知其他应用某个事件发生了,其他应用中的广播接收器如果注册了接收这个广播,就可以各自独立地处理这个事件。

  • 有序广播(Ordered Broadcast)

    • 有序广播是按照一定的优先级顺序传递的广播。这就好比在一个有等级的组织里传达一个消息,先传给级别高的人(优先级高的广播接收器),然后再依次往下传。优先级高的广播接收器可以对广播进行处理,甚至可以终止广播,不让后面的接收器接收到。例如,系统发送一个有序广播来处理网络连接状态改变的情况,高优先级的安全相关的应用可以先处理这个广播,可能会根据网络连接情况调整安全策略,然后再让其他应用的广播接收器处理。

Broadcast Receiver的示例

  • 当网络连接状态从断开变为连接时,系统会发送一个网络连接状态改变的广播。一个下载应用中的Broadcast Receiver接收到这个广播后,就可以自动开始之前暂停的下载任务。

  • 当电池电量低时,系统发送电池电量低的广播,手机中的一些电量管理应用中的Broadcast Receiver接收到这个广播后,可以采取一些节能措施,如关闭一些后台服务或者降低屏幕亮度等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值