Android四大组件

Activity

启动模式

  • Standard:标准模式:开启一个Activity就会产生一个新的实例。

    standard模式启动ActivityB,创建类ActivityB的实例压入栈中。

    ActivityB可存在多个实例并且可以重叠存在
    在这里插入图片描述

  • SingleTop:单一栈顶模式:如果任务栈的栈顶有这个实例,才不会再创建允许有多个实例。

    singleTop模式启动ActivityB,系统会检查栈的栈顶是否存在类ActivityB的实例,存在直接使用该对象并回调onNewIntent(Intent intent)方法。不存在类ActivityB的实例,则创建类ActivityB的对象压入栈顶。

    ActivityB可以存在多个实例但不能重叠存在
    在这里插入图片描述

  • SingleTask:单一任务栈模式:如果任务栈中已经有实例,就不会再创建,只能有一个实例。

    singleTask模式启动ActivityB, 栈中已经存在类ActivityB的实例,则系统会把栈中类ActivityB的实例之上所有Activity实例销毁,然后回调类ActivityB的实例onNewIntent(Intent intent)方法。栈中不存在类ActivityB的实例,则创建类ActivityB的实例压入栈顶。

    ActivityB不会存在相同的实例Activity
    在这里插入图片描述

  • SingleInstance:单一实例模式:每个Activity有自己的任务栈,栈中有且只有一个实例。

    singleInstance模式启动ActivityB,系统会为它创建新的任务栈,然后创建类ActivityB的实例并压如栈中,该栈只存一个实例对象。如下图说明在类ActivityB的实例中singleInstance模式启动ActivityC。

    如果此时在ActivityC按返回键,则会先在task1中找是否有Activity,回到的是ActivityA,再次按返回键task1无Activity,回到的才是ActivityB。

    ActivityB实例单独占一个Task并且只存在ActivityB一个实例
    在这里插入图片描述

生命周期

在这里插入图片描述

问题:设备横竖屏切换,Activity会发生什么?

  • 不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
  • 设置Activity的android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
  • 设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。Android 3.2之后,还是会重新执行所有生命周期,除非再设置Activity的android:configChanges=”orientation|keyboardHidden|screensize”。

onSaveInstanceState和onRestoreInstanceState触发的时机?

先看Application Fundamentals上的一段话:

Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key)

从这句话可以知道,当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。

注意上面的双引号,何为“容易”?言下之意就是该activity还没有被销毁,而仅仅是一种可能性。这种可能性有哪些?通过重写一个activity的所有生命周期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我们可以清楚地知道当某个activity(假定为activity A)显示在当前task的最上层时,其onSaveInstanceState方法会在什么时候被执行,有这么几种情况:

  • 当用户按下HOME键时。
    这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则

  • 长按HOME键,选择运行其他的程序时。

  • 按下电源按键(关闭屏幕显示)时。

  • 从activity A中启动一个新的activity时。

  • 屏幕方向切换时,例如从竖屏切换到横屏时。
    在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行

总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。

至于onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行

另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原

Service

问题:startService()与bindService()区别?

生命周期上的区别
startService():
1,Service会经历onCreate()------->onStartCommand()。
2,调用者执行stopService时,直接调用onDestroy方法;调用者如果没有stopService,就算调用者被销毁了,Service会一直在后台运行
3,多次调用startService,该Service只能被创建一次,即该Service的onCreate()只会被调用一次。但是每次调用startService,onStartCommand()都会被调用

bindService():
1,Service会经历onCreate()----->onBind()。
2,调用者调用unbindService方法或者调用者被销毁了,Service就会调用onUnbind()------>onDestroy()。
3,多次调用bindService,onCreate()和onBind()不会再执行。

优缺点:
startService在Activity所在进程被终结后,服务依然在运行。该服务是独立的进程,会占用一定资源—>缺点
bindService方便很多。缺点是主进程被终结后,服务便会终止

service中onStartCommand方法的返回值及意义

  • START_STICKY:service被kill后会保存service状态,但不保存intent对象,当service尝试重启后,如果没有重传intent,intent就为null。
  • START_NOT_STICKY:service被kill后不会重启。
  • START_REDELIVER_INTENT:service被kill后自动重启,重传intent对象。
  • START_STICKY_COMPATIBILITY:不保证重启。

BroadcastReceive

问题:广播有哪几种,它们之间的区别是什么?

  • 无序广播
    1,发送方式:context.sendBroadcast(intent)
    2,不可被拦截
  • 有序广播
    1,发送方式:context.sendOrderBroadcast(intent)
    2,可被拦截
  • 粘性广播
    1,发送方式:context.sendStickyBroadcast(intent),需要BROADCAST_STICKY权限
    2,intent会一直保留到广播事件结束
  • 本地广播
    1,发送方式:localBroadcastManager.sendBroadcast(intent)
    2,只在app内传播,比较安全

注册方式及区别

1.静态注册

在minifest文件中
<receiver android:name=".BroadcastReceiverDemo" >
            <intent-filter>
                <action android:name="com.demo.BroadcastReceiverDemo" >
                </action>
            </intent-filter>
</receiver>

发送广播:
Intent mIntent = new Intent("com.demo.BroadcastReceiverDemo");
mIntent.putExtra("message", "hahahahaha");
sendBroadcast(mIntent);

接收广播:
public class BroadcastReceiverDemo extends BroadcastReceiver { 
     @Override 
     public void onReceive(Context context, Intent intent) {
         String msg = intent.getStringExtra("message"); 
         Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
      } 
}

2.动态注册
在代码中注册和反注册

registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

unregisterReceiver(BroadcastReceiver receiver)

区别:

静态注册:在AndroidManifest中进行注册后,不管改应用程序是否处于活动状态,都会进行监听,比如某个程序时监听 内存的使用情况的,当在手机上安装好后,不管改应用程序是处于什么状态,都会执行改监听方法中的内容。

动态注册:在代码中进行注册后,当应用程序关闭后,就不再进行监听。我们读知道,应用程序是否省电,决定了该应用程序的受欢迎程度,所以,对于那些没必要在程序关闭后仍然进行监听的Receiver,在代码中进行注册,无疑是一个明智的选择。

ContentProvider

ContentProvider用于保存和获取数据,并使其对所有应用程序可见。这是不同应用程序间共享数据的唯一方式。因为android没有提供所有应用共同访问的公共存储区。

问题:Android为什么要设计ContentProvider这个组件?

  • 封装。对数据进行封装,提供统一的接口,使用者完全不必关心这些数据是在DB,XML、Preferences或者网络请求来的。当项目需求要改变数据来源时,使用我们的地方完全不需要修改。
  • 提供一种跨进程数据共享的方式。

问题:如何限制对方的使用?

1,android:exported属性

  • true
    该服务能够被其他应用程序组件调用或跟它交互
  • false
    只有同一个应用程序的组件或带有相同用户ID的应用程序才能启动或绑定该服务

问题:如何只需要对同一个签名的其它应用开放ContentProvider?

则可以设置signature级别的权限
android:protectionLevel=“signature”

<permission android:name="com.android.gallery3d.filtershow.permission.READ"
            android:protectionLevel="signature" />

<permission android:name="com.android.gallery3d.filtershow.permission.WRITE"
            android:protectionLevel="signature" />

<provider
    android:name="com.android.gallery3d.filtershow.provider.SharedImageProvider"
    android:authorities="com.android.gallery3d.filtershow.provider.SharedImageProvider"
    android:grantUriPermissions="true"
    android:readPermission="com.android.gallery3d.filtershow.permission.READ"
    android:writePermission="com.android.gallery3d.filtershow.permission.WRITE" />

问题:如何只需要开放部份的URI给其他的应用访问?

则可以设置path-permission的权限

<provider android:name="ContactsProvider2"
    android:authorities="contacts;com.android.contacts"
    android:label="@string/provider_label"
    android:multiprocess="false"
    android:exported="true"
    android:grantUriPermissions="true"
    android:readPermission="android.permission.READ_CONTACTS"
    android:writePermission="android.permission.WRITE_CONTACTS">
    <path-permission
            android:pathPrefix="/search_suggest_query"
            android:readPermission="android.permission.GLOBAL_SEARCH" />
    <path-permission
            android:pathPrefix="/search_suggest_shortcut"
            android:readPermission="android.permission.GLOBAL_SEARCH" />
    <path-permission
            android:pathPattern="/contacts/.*/photo"
            android:readPermission="android.permission.GLOBAL_SEARCH" />
    <grant-uri-permission android:pathPattern=".*" />
</provider>

ContentProvider和线程以及阻塞

关于ContentProvider一直有几个疑问:
1,ContentProvider是运行在哪个进程里面的?
2,别的主线程调用它的时候会被阻塞吗?
3,如果不同的其他应用,同时调用了这个ContentProvider的同一个方法,它们会相互阻塞吗?比如有三个应用同时都在调用这个provider的插入方法,它们会相互阻塞还是并发运行?

1,ContentProvider的onCreate方法,运行在ui线程。但是其他方法,运行在非ui线程,例如call、query、delete、insert、upate等方法。
2,别的主线程调ContentProvider里面方法的时候,虽然他的call、query、delete、insert、upate等方法运行在非ui线程,但是其他调用方法是会被阻塞的。比如你在activity的onCreate方法中调用ContentProvider的query等方法,onCreate方法会被阻塞。
3,他们不会相互阻塞。

问题:ContentProvider是如何在不同应用程序之间传输数据的?

ContentResolver虽然是通过Binder进程间通信机制打通了应用程序之间共享数据的通道,但ContentProvider组件在不同应用程序之间传输数据是基于匿名共享内存机制来实现的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值