Android四大组件(activity task stack) 启动模式 / Activity

82 篇文章 1 订阅

Activity

Activity的概念

Activity 类的目的是促进这种标准的达成,当一个应用调用另一个应用时,调用方应用会调用另一个应用中的 Activity,而不是整个应用。通过这种方式,Activity 充当了应用与用户互动的入口点。

配置清单

要使应用能够使用 Activity,您必须在清单中声明 Activity 及其特定属性。

声明 Activity

要声明 Activity,请打开清单文件,并添加 元素作为 元素的子元素。例如:

    <manifest ... >
      <application ... >
          <activity android:name=".ExampleActivity" />
          ...
      </application ... >
      ...
    </manifest >
    

此元素唯一的必要属性是 android:name,该属性用于指定 Activity 的类名称。详见

声明 intent 过滤器

Intent 过滤器是 Android 平台的一项非常强大的功能。借助这项功能,您不但可以根据显式请求启动 Activity,还可以根据隐式请求启动 Activity。例如,显式请求可能会告诉系统“在 Gmail 应用中启动‘发送电子邮件’Activity”,而隐式请求可能会告诉系统“在任何能够完成此工作的 Activity 中启动‘发送电子邮件’屏幕”。当系统界面询问用户使用哪个应用来执行任务时,这就是 intent 过滤器在起作用。
以下代码段展示了如何配置一个发送文本数据并接收其他 Activity 的文本数据发送请求的 Activity:

    <activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
        <intent-filter>
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity>
    

在此示例中, 元素指定该 Activity 会发送数据。将 元素声明为 DEFAULT 可使 Activity 能够接收启动请求。 元素指定此 Activity 可以发送的数据类型。以下代码段展示了如何调用上述 Activity:

    // Create the text message with a string
    Intent sendIntent = new Intent();
    sendIntent.setAction(Intent.ACTION_SEND);
    sendIntent.setType("text/plain");
    sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
    // Start the activity
    startActivity(sendIntent);
    

声明权限

您可以使用清单的 标记来控制哪些应用可以启动某个 Activity。父 Activity 和子 Activity 必须在其清单中具有相同的权限,前者才能启动后者。如果您为父 Activity 声明了 元素,则每个子 Activity 都必须具有匹配的 元素。
例如,假设您的应用想要使用一个名为 SocialApp 的应用在社交媒体上分享文章,则 SocialApp 本身必须定义调用它的应用所需具备的权限:

    <manifest>
    <activity android:name="...."
       android:permission=”com.google.socialapp.permission.SHARE_POST”

    />

然后,为了能够调用 SocialApp,您的应用必须匹配 SocialApp 清单中设置的权限:

    <manifest>
       <uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
    </manifest>
    

隐式启动实践

APP应用

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toast.makeText(this,"隐式意图打开",Toast.LENGTH_SHORT).show();
    }
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cn.jj.myapplication" >
    <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/Theme.MyApplication" >
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="cn.jj.myapplication.intent" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

跳转应用

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "JJWorld";
    private TextView textView;
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        button.setOnClickListener(this);
    }

    private void initView() {
        textView = (TextView) findViewById(R.id.textView);
        button = (Button) findViewById(R.id.button);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                Intent intent = new Intent();
                intent.setComponent(ComponentName.unflattenFromString("cn.jj.myapplication"));
                intent.setAction("cn.jj.myapplication.intent");

                // 查询是否存在与intent匹配的activity
                PackageManager pm = this.getPackageManager();
                List<ResolveInfo> ris = pm.queryIntentActivities(intent, 0);
                Log.i(TAG,"ris size:" + (ris!=null? String.valueOf(ris.size()) :"0"));
                if (ris != null && ris.size() > 0) {
                    for (ResolveInfo resolveInfo : ris) {
                        Log.e(TAG, "resolveInfo.activityInfo.name:" + resolveInfo.activityInfo.name + "\n\r" +
                               "resolveInfo.activityInfo.packageName:" + resolveInfo.activityInfo.packageName);
                    }
                    startActivity(intent);
                }
                break;
            default:
                break;
        }
    }
}

跳转应用的manifest中添加了queries标签

    <queries>
        <package android:name="cn.jj.myapplication" />
    </queries>

生命周期

在这里插入图片描述

  • onCreate:创建活动。此时会把页面布局加载进内存,进入了初始状态。
  • onStart:开启活动。此时会把活动页面显示在屏幕上,进入了就绪状态。
  • onResume:恢复活动。此时活动页面进入活跃状态,能够与用户正常交互,例如允许响应用户的点击动作、允许用户输入文字等。
  • onPause:暂停活动。此时活动页面进入暂停状态(也就是退回就绪状态),无法与用户正常交互。
  • onStop:停止活动。此时活动页面将不在屏幕上显示。 onDestroy:销毁活动。此时回收活动占用的系统资源,把页面从内存中清除掉。
  • onRestart:重启活动。处于停止状态的活动,若想重新开启的话,无须经历onCreate的重复创建过程,而是走onRestart的重启过程。

特殊的生命周期:

  • onNewIntent

在singleTask和singleTop启动模式下,启动一个已存在的Activity,该Activity的生命周期会如何回调
activity1(singleTask)

[activity1]---task1---foreground

再启动activity1

[activity1]---task1---foreground

生命周期如下:

2022-09-06 12:11:13.262 16389-16389/cn I/TK.LoginActivity: onPause
2022-09-06 12:11:13.264 16389-16389/cn I/TK.LoginActivity: onNewIntent
2022-09-06 12:11:13.299 16389-16389/cn I/TK.LoginActivity: onResume

Acvtivity启动模式

页面跳转

Intent intent = new Intent(this, TestActivityTo.class);
startActivity(intent);

activity之间传递信息

1.使用bundle打包消息后进行消息的传递

  • 消息发送类
public class ActSendActiviy extends AppCompatActivity implements View.OnClickListener {

    private TextView tvContent;
    private Button btSend;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_send_activiy);
        initView();

        btSend.setOnClickListener(this);
    }

    private void initView() {
        tvContent = (TextView) findViewById(R.id.tv_Content);
        btSend = (Button) findViewById(R.id.bt_send);
    }

    @Override
    public void onClick(View v) {
        String content = tvContent.getText().toString();
        Intent intent = new Intent(this, ActReviceActivity.class);
        Bundle bundle = new Bundle();
        bundle.putString("time", DateUtil.getNowTime());
        bundle.putString("content",content);
        intent.putExtras(bundle);
        startActivity(intent);
    }
}

消息接收类

public class ActReviceActivity extends AppCompatActivity {

    private TextView tvReceive;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_revice);
        Intent intent = getIntent();
        Bundle bundle = intent.getExtras();
        String showInf = String.format("传递消息时间 %s \n 传递内容 %s \n ",
                bundle.getString("time"), bundle.getString("content"));
        initView();
        tvReceive.setText(showInf);
    }

    private void initView() {
        tvReceive = (TextView) findViewById(R.id.tv_receive);
    }
}
  • 如果getString的key不存在,则会返回null。

在这里插入图片描述

2.使用intent进行消息的传递

  • 消息发送类
public class ActSendActiviy extends AppCompatActivity implements View.OnClickListener {

    private TextView tvContent;
    private Button btSend;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_send_activiy);
        initView();

        btSend.setOnClickListener(this);
    }

    private void initView() {
        tvContent = (TextView) findViewById(R.id.tv_Content);
        btSend = (Button) findViewById(R.id.bt_send);
    }

    @Override
    public void onClick(View v) {
        String content = tvContent.getText().toString();
        Intent intent = new Intent(this, ActReviceActivity.class);
//        Bundle bundle = new Bundle();
//        bundle.putString("time", DateUtil.getNowTime());
//        bundle.putString("content",content);
//        intent.putExtras(bundle);
        intent.putExtra("time",DateUtil.getNowTime());
        intent.putExtra("content",content);
        startActivity(intent);
    }
}
  • 消息接收类
public class ActReviceActivity extends AppCompatActivity {

    private TextView tvReceive;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_revice);
        Intent intent = getIntent();
//        Bundle bundle = intent.getExtras();
//        String showInf = String.format("传递消息时间 %s \n 传递内容 %s \n ",
//                bundle.getString("time"), bundle.getString("content"));
        String showInf = String.format("传递消息时间 %s \n 传递内容 %s \n ",
                intent.getStringExtra("time"), intent.getStringExtra("content"));
        initView();
        tvReceive.setText(showInf);
    }

    private void initView() {
        tvReceive = (TextView) findViewById(R.id.tv_receive);
    }
}

在这里插入图片描述

3.小结

intent在put数据时底层也是使用了bundle
在这里插入图片描述
使用bundle传输数据更多用于A界面传输到B界面再传输到C界面这样链条比较长的场景。这样的话,B界面取到数据后,不用再重新打包,可以直接将bundle发送过去。

广播

  1. BroadcastReceiver.onReceive默认是在主线程(UI线程)执行的,所以不能在广播接收器做耗时操作。

  2. 广播发送者可以指定接收广播的应用,只要将sendBroadcast(intent)的intent加上具体的包名就行了,intent.setPackage(“yourpackagename”)。

  3. 广播发送者和接收者都可以声明权限,这样只有在AndroidManifest声明对应权限,才能接收到相应的广播消息。

简介

广播接收者(BroadcastReceiver)是安卓的四大组件之一。
类似于日常生活中的广播,安卓系统中的广播也有发送者和接收者;
发送者通常是系统的应用程序,比如电池电量低,开关机,有电话或者短信到来,网络是否连接等都会向外发出广播。
接收者通常是用户创建的应用程序,注册对应的广播后,用来监听系统发出的广播,监听到后可针对广播事件做相应反馈。
广播发送者也可以是用户创建的应用程序,成为自定义广播。

接收广播

发送广播

1 发送有序广播
使用sendBroadcast()方法发送无序广播。无序广播发送时会在携带的intent对象中设置action属性值,所有注册广播时设置了相同action值的广播接收者都能够接收到该广播,没有绝对顺序。
2 发送无序广播
使用sendOrderedBroadcast()方法可以发送有序广播。广播发送者和接收者也会先匹配action属性值,再通过广播接收者设置的priority属性值决定广播的接收顺序,priority值越大越先接收到广播,如果值相同,先注册的先接收到广播。
3 指定广播接收者(一种特殊的有序广播)

4)Android四大组件将创建的类在配置文件中进行注册。

广播步骤

创建一个Receiver类。通过系统自定义的创建。
重写onReceive()方法。
在AndroidManifest中添加过滤器。
添加此广播对应的权限。

当前是否为静态广播接收不到,但是动态广播可以接收到。

对于静态注册的方法,在Android8.0之后就增加了限制。
从 Android 8.0(API 级别 26)开始,系统对清单声明的接收器施加了额外的限制。
如果您的应用面向 Android 8.0 或更高版本,则您不能使用清单为大多数隐式广播(不专门针对您的应用的广播)声明接收器。当用户积极使用您的应用程序时,您仍然可以使用上下文注册的接收器。
如果仍然想要使用静态注册的方式,在发送广播时需要做声明:componentName中分别为包和包中类的引用。
intent.setComponent(new ComponentName(“com.example.myreceiver”,“com.example.myreceiver.receiver”));

比如MainActivity中添加:

无序广播


## 无序广播

  @Override
  public void onClick(View v) {
      Intent intent = new Intent();
      // action为字符串形式的
      intent.setAction(MyBroadCastReceiver.myReceiver);
      sendBroadcast(intent);
  }

  @Override
  protected void onStart() {
      super.onStart();
      myBroadCastReceiver = new MyBroadCastReceiver();
      // 创建一个意图过滤器 只处理myReceiverBroadcastReceiver的广播
      IntentFilter intentFilter = new IntentFilter(MyBroadCastReceiver.myReceiver);
      // 注册接收器,注册之后才能正常接收广播
      registerReceiver(myBroadCastReceiver, intentFilter);
  }

  @Override
  protected void onStop() {
      super.onStop();
      // 注销接收器,注销之后不再接收广播
      unregisterReceiver(myBroadCastReceiver);
  }

public class MyBroadCastReceiver extends BroadcastReceiver {

    private static String TAG = "MyBroadCastReceiver";
    public static String myReceiver = "myReceiverBroadcastReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null && intent.getAction().equals(myReceiver)){
            Log.i(TAG, "onReceive: my receive");
        }
    }
}

有序广播

优先级最大可以声明为int型的最大值,也就是2147483647(为了最高优先级,拼了)。默认优先级应该为0;

// 源码

	private int mPriority;

    public IntentFilter(String action) {
        mPriority = 0;
        mActions = new ArrayList<String>();
        addAction(action);
    }

    public final void setPriority(int priority) {
        mPriority = priority;
    }

发送广播

// 发送广播
Intent intent2 = new Intent();
// action
intent2.setAction(orderBroadCastReceiver);
sendOrderedBroadcast(intent2,null);

IntentFilter中输入参数为action
在这里插入图片描述
// 注册

// todo 优先级 默认的优先级是多少
OrderAReceiver orderAReceiver = new OrderAReceiver();
IntentFilter intentFilterA = new IntentFilter(orderBroadCastReceiver);
intentFilterA.setPriority(10);
registerReceiver(orderAReceiver,intentFilterA);

// todo 优先级 默认的优先级是多少
OrderBReceiver orderBReceiver = new OrderBReceiver();
IntentFilter intentFilterB = new IntentFilter(orderBroadCastReceiver);
intentFilterB.setPriority(8);
registerReceiver(orderAReceiver,intentFilterB);


// 取消注册
unregisterReceiver(orderAReceiver);
unregisterReceiver(orderBReceiver);

// 接收
registerReceiver 输入参数分别为BroadcastReceiver receiver, IntentFilter filter
在这里插入图片描述

public class OrderAReceiver extends BroadcastReceiver {
    private String TAG = "HHH.OrderAReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null && intent.getAction().equals(MainActivity.orderBroadCastReceiver)){
            Log.i(TAG, "OrderAReceiver onReceive...");
        }
    }
}```

public class OrderBReceiver extends BroadcastReceiver {
    private String TAG = "HHH.OrderBReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null && intent.getAction().equals(MainActivity.orderBroadCastReceiver)){
            Log.i(TAG, "OrderBReceiver onReceive...");
        }

    }
}
// 结果

```java
2022-06-17 17:02:05.777 21164-21164/cn.jj.myapplication I/HHH.OrderAReceiver: OrderAReceiver onReceive...
2022-06-17 17:02:05.779 21164-21164/cn.jj.myapplication I/HHH.OrderBReceiver: OrderBReceiver onReceive...

静态广播

发送

// public static String shakeBroadcast = "MyShakeBroadcast";
intent3.setAction(shakeBroadcast);
ComponentName componentName = new ComponentName(this,"cn.jj.myapplication.receiver.BroadStaticReceiver");
intent3.setComponent(componentName);
sendBroadcast(intent3);

接收

public class BroadStaticReceiver extends BroadcastReceiver {
    private String TAG = "HHH.BroadStaticReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null && intent.getAction().equals(MainActivity.shakeBroadcast)){
            Log.i(TAG, "onReceive: BroadStaticReceiver");
            Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
            vibrator.vibrate(500);
        }
    }
}

清单文件

        <receiver
            android:name=".receiver.BroadStaticReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="MyShakeBroadcast"/>
            </intent-filter>
        </receiver>

服务

1)简介
服务也是Android的四大组件之一。被称为是没有界面的activity;它拥有自己的生命周期,可以不随着activity的销毁而销毁。
2)创建方式
需要创建继承自Service类的自定义类,并在配置文件中使用标签完成注册,该类回复写一个同名构造方法和一个onBind()的回调方法。
3)使用方法
a) 开启和停止服务
使用startService()方法开启服务,使用stopService()方法停止服务。
适用于例如开启和关闭游戏背景音乐的场景。
b) 绑定和解绑服务
使用bindService()方法绑定服务,使用unbindService()方法解绑服务。
适用于服务中私有方法,Activity通过绑定服务后,调用服务中的方法。例如:音乐播放器。
4)服务与Activity中间的通信
a) 服务的本地调用方法
调用服务的Activity与服务在同一个应用程序中,绑定服务后调用服务中的方法。
b) 服务的远程方法调用
调用服务的Activity与服务在同一个应用程序中,绑定服务后调用服务中的方法。

context:
它描述的是一个应用程序的环境,即上下文
它类是一个抽象的类,android提供了一个具体的通用实现类contextIml类。
它就像是一个大管家,是一个访问全局信息的接口。通过它我们可以获取应用程度 的资源的类,包括一些应用级的操作,如启动一个activity,发送广播,接受Intent信息。

Context的继承关系图如下图所示:
在这里插入图片描述

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学知识拯救世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值