越探越深-揭秘Activity的高级玩法


在上一篇中,我们已经探索了Activity的基础知识,包括它的本质构成、生命周期管理、启动模式等核心内容。但Activity的真正力量远不止于此,它还拥有许多高级特性,让我们能够打造出更加灵活、强大的Android应用体验。今天,就让我带大家深入挖掘Activity背后的那些独门绝学!


一、恢复重建:数据状态的长生不老药

当Activity发生重建时,例如设备旋转导致的配置变更,之前持有的临时数据将会遗失。Android系统为了解决这个问题,提供了两种主要的状态保存方案。


方案一:借助Bundle暂存关键数据

Activity中的onSaveInstanceState回调,就是为此而生。当系统准备销毁一个Activity实例时,会先调用该方法,并传入一个Bundle供我们暂存数据:

public class MyActivity extends AppCompatActivity {

    private static final String KEY_DATA = "key_data";
    private String data;

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

        if (savedInstanceState != null) {
            data = savedInstanceState.getString(KEY_DATA);
        }
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(KEY_DATA, data);
    }
}

当Activity重建时,系统会自动将之前的Bundle数据传回给onCreate方法,于是我们就可以从中恢复原有的状态信息了。通过这种方式,临时数据得以跨越重建的鸿沟得到保留。


方案二:ViewModel解决终极数据托管

使用Bundle的方式虽然直接有效,但有时会显得代码过于冗长。更好的选择是借助AndroidX库中内置的ViewModel组件,将状态数据的托管工作完全交给这个专门的管理者:

public class MyViewModel extends ViewModel {
    
    private Data currentData;
    
    public Data getCurrentData() {
        return currentData;
    }
    
    public void setData(Data data) {
        currentData = data;
    }
}
public class MyActivity extends AppCompatActivity {

    private MyViewModel viewModel;

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

        viewModel = new ViewModelProvider(this).get(MyViewModel.class);
        if (viewModel.getCurrentData() != null) {
            renderData(viewModel.getCurrentData());
        }
    }

    private void renderData(Data data) {
        viewModel.setData(data);
        // TODO: 更新UI
    }
}

ViewModel的生命周期是与当前Activity的归属关系绑定的,而不依赖于Activity的具体实例。这就意味着,无论Activity经历多少次重建,ViewModel都能够保持数据的连续性和一致性。

除了解决数据丢失的难题,ViewModel还拥有诸多其他优点,例如可感知页面导航状态、支持工作程协程等。所以在实际开发中,ViewModel无疑是状态恢复最佳实践的不二之选。


二、无所不通:Intent的多路精准控制

当我们想要启动一个新的Activity时,不可或缺的就是Intent这个Android世界中的"护航使者"了。它不仅功能强大,使用方式也相当灵活多变。

1、显式Intent

如果明确知道想要启动的目标Activity,我们就可以通过显式Intent直接指定它:

public class MainActivity extends AppCompatActivity {

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

        String data = "Hello";
        Intent intent = new Intent(this, TargetActivity.class);
        intent.putExtra("KEY_DATA", data); 
        startActivity(intent);
    }
}
public class TargetActivity extends AppCompatActivity {

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

        String data = getIntent().getStringExtra("KEY_DATA");
        // TODO: 处理data
    }
}

2、隐式Intent

隐式Intent通过在AndroidManifest.xml中声明Intent Filter,使自己对外暴露服务能力:

<!-- AndroidManifest.xml -->
<activity android:name=".ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>
public class SenderActivity extends AppCompatActivity {

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

        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_SEND);
        intent.putExtra(Intent.EXTRA_TEXT, "Hello");
        intent.setType("text/plain");

        startActivity(Intent.createChooser(intent, "分享文本"));
    }
}

这样,所有符合条件的Activity就都可以被系统视为"分享文本"行为的响应目标。用户还可以在多个备选项中自由选择。通过这种方式,隐式Intent赋予了Android生态更大的灵活性与可扩展性。


三、startActivityForResult:启动并得到返回

除了常规的启动方式,Intent还支持"启动-回调"模式。

startActivityForResult 是 Android 中的一个方法,它允许一个 Activity 启动另一个 Activity 并等待结果。

启动的 Activity 可以完成某项工作(如用户填写表单、选择图片等),然后通过 RESULT_OKRESULT_CANCELED 结果代码将结果传递回原始的 Activity

以下是 startActivityForResult 的一个典型使用案例,假设我们要从 MainActivity 中启动一个 SecondActivity 来获取用户输入的分数,并将结果返回:


1、第一步:在 MainActivity 中启动 SecondActivity 并接收结果


import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView scoreTextView;

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

        scoreTextView = findViewById(R.id.score_text_view);
        Button getScoreButton = findViewById(R.id.get_score_button);

        getScoreButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 使用 startActivityForResult 启动 SecondActivity
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivityForResult(intent, 1); // 1 是请求码(request code)
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // 检查请求码是否匹配
        if (requestCode == 1) {
            // 检查结果码
            if (resultCode == RESULT_OK) {
                // 获取返回的数据
                int score = data.getIntExtra("score", 0);
                scoreTextView.setText("Your score is: " + score);
            } else {
                // 结果码不是 RESULT_OK,表示用户取消了操作
                scoreTextView.setText("No score was entered.");
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }
}

第二步:在 SecondActivity 中获取用户输入并返回结果

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.content.Intent;

public class SecondActivity extends AppCompatActivity {

    private EditText scoreEditText;

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

        scoreEditText = findViewById(R.id.score_edit_text);
        Button submitButton = findViewById(R.id.submit_button);

        submitButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 获取用户输入的分数
                int score = Integer.parseInt(scoreEditText.getText().toString());
                // 创建一个新的 Intent 来传递结果
                Intent resultIntent = new Intent();
                resultIntent.putExtra("score", score);
                // 结束 SecondActivity 并传递结果
                setResult(RESULT_OK, resultIntent);
                finish();
            }
        });
    }
}

在这个例子中:

  1. MainActivity 有一个按钮,用户点击这个按钮时,会通过 startActivityForResult 启动 SecondActivity1 是我们定义的请求码(request code),用于区分 onActivityResult 中的不同请求。
  2. SecondActivity 提供了一个编辑框供用户输入分数,并有一个提交按钮。当用户点击提交按钮时,获取输入的分数,将其放入一个 Intent 中,并通过 setResult 方法将结果发送回启动它的 Activity,然后结束自己。
  3. SecondActivity 结束时,MainActivityonActivityResult 方法会被调用。通过检查请求码(requestCode)和结果码(resultCode),MainActivity 可以判断结果是否有效,并更新 UI 来显示用户输入的分数。

使用 startActivityForResult 可以很好地管理 Activity 之间的交互和结果传递,使得逻辑更加清晰和易于维护。


四、无界无垠:URI路由与Scheme协议接入


Intent所承载的不仅是Android内部的组件互联,它更将随着技术的发展而创造出新的无限可能性。通过支持URI路径,Intent实现了与手机浏览器的无缝连接,为我们的应用打开了一扇全新的大门。


1、精心构建:注册URI路径

首先,我们需要在AndroidManifest.xml中为想要对外暴露的Activity注册一个URI路径:

<activity
    android:name=".uri.UriActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:host="www.myapp.com"
            android:pathPrefix="/uri"
            android:scheme="https" />
    </intent-filter>
</activity>

在上面的示例中,我们声明了一个scheme为"https"、host为"www.myapp.com"、路径前缀为"/uri"的URI路由配置。这意味着,只要外部应用发出形如https://www.myapp.com/uri/*的Intent请求,就能够打开该Activity。


2、模式识别:解析传入的URI

接下来,Activity就需要提供解析URI的能力,从而获取隐含在其中的数据:

public class UriActivity extends AppCompatActivity {

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

        Intent intent = getIntent();
        Uri uri = intent.getData();
        if (uri != null) {
            String path = uri.getPath(); // 获取路径
            String param = uri.getQueryParameter("key"); // 获取参数
            // TODO: 处理获取到的数据
        }
    }
}

通过解析获取的Uri对象,我们就能轻松获取请求路径、参数等关键信息。这无疑为构建复杂的路由体系奠定了基础。


3、Scheme无边界:与外部通路互联接轨


除了与浏览器互联,我们的应用还可以借助Scheme与其他应用打通数据链路,构建出一张立体而广阔的通信网络。只要约定一个包名范围内唯一的Scheme协议,再搭配合适的Intent Filter,就能为外部应用提供丰富的服务接口:

<!-- 其他应用的 AndroidManifest.xml -->
<activity
    android:name=".SchemeActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:host="open"
            android:scheme="myapp" />
    </intent-filter>
</activity>
// 我们应用发出的请求
String uri = "myapp://open?data=hello";
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent);

上述代码将唤起目标应用的SchemeActivity,并将"data=hello"参数传递过去。通过这种方式,我们就能与各种应用进行互联互通、资源共享,打造出一个生动活泼、融合无限的智能化体验。


序幕未终:更多探索仍在继续

本文探讨了Activity作为Android四大组件核心的一些高级特性,包括保存和恢复状态数据、Intent的精细控制、回调机制的应用,以及面向未来的Uri路由与Scheme通信等内容。但Activity的魅力远不止于此,它还蕴含着更多精深的理念和机遇有待我们去挖掘。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/595301.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Go语言基本语法(三)指针

什么是指针 在Go语言中&#xff0c;"指针是一种存储变量内存地址的数据类型"&#xff0c;意味着指针本身是一个特殊的变量&#xff0c;它的值不是数据本身&#xff0c;而是另一个变量在计算机内存中的位置&#xff08;地址&#xff09;。形象地说&#xff0c;就像存…

multipass和multipassd命令的区别

multipassd通常是multipass服务的后台守护进程&#xff0c;它负责管理和控制虚拟机实例。 命令区别 例&#xff1a; multipass restart my-vm 这个命令用于重启Multipass中的虚拟机实例。例如有一个名为my-vm的虚拟机实例。 multipassd restart 这会重新启动Multipass后台…

一文学会最强大的 node.js 后端框架 nest.js

文章目录 nest cli项目基本结构IOC & DI基础注册值注册时 key 的管理动态注册类工厂函数方式注册设置别名导出 provider 模块功能模块模块的导入导出模块类中使用注入全局模块动态模块 中间件定义中间件注册中间件MiddlewareConsumer 类全局中间件 异常过滤器抛出异常自定义…

华三配置DHCP(基础)

华三交换机配置DHCP&#xff08;基础&#xff09; 1.组网拓扑图&#xff08;交换机-PC&#xff09; 2.通过交换机开启DHCP功能&#xff0c;使PC自动获取192.168.10.0&#xff08;vlan10&#xff09;网段地址 2.使用命令 <H3C>system-view [H3C]vlan 10&#xff08;建立…

Python_4-远程连接Linux

文章目录 使用Python通过SSH自动化Linux主机管理代码执行ls结果&#xff1a;文件传输&#xff1a; 使用Python通过SSH自动化Linux主机管理 在系统管理与自动化运维中&#xff0c;SSH&#xff08;Secure Shell&#xff09;是一个常用的协议&#xff0c;用于安全地访问远程计算机…

【0day】湖南建研工程质量检测系统InstrumentUsageRecordExport接口处存在任意文件读取漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

发那科Fanuc数控网络IP配置设定教程

1.在主面板如图按system键&#xff0c;进入系统界面 2.按右翻页切换键&#xff0c;切换到内嵌选项&#xff0c;按内嵌按钮跳转至设置IP界面&#xff0c;设置ip 3.按Focas2按钮&#xff0c;跳转至设置端口号和超时时间界面。设置端口号和时间之后&#xff0c;重启设备。注意&…

MES生产系统与数字孪生双重结合:智慧制造工厂的新引擎

随着数字化浪潮的推动&#xff0c;制造行业正在经历着前所未有的变革。在这个变革的浪潮中&#xff0c;MES生产制造系统与数字孪生技术的深度融合成为了制造工厂未来发展的核心驱动力。这种结合不仅提升了生产效率&#xff0c;优化了资源配置&#xff0c;降低了运营成本&#x…

2024年 Java 面试八股文——SpringCloud篇

目录 1.Spring Cloud Alibaba 中的 Nacos 是如何进行服务注册和发现的&#xff1f; 2.Spring Cloud Alibaba Sentinel 的流量控制规则有哪些&#xff1f; 3.Spring Cloud Alibaba 中如何实现分布式配置管理&#xff1f; 4.Spring Cloud Alibaba RocketMQ 的主要特点有哪些&…

HCIP的学习(12)

OSPF优化 ​ OSPF的优化主要目的是为了减少LSA的更新量。 路由汇总-----可以减少骨干区域的LSA数量特殊区域-----可以减少非骨干区域的LSA数量 OSPF路由汇总 域间路由汇总-----在ABR设备上进行操作 [GS-R2-ospf-1-area-0.0.0.1]abr-summary 192.168.0.0 255.255.224.0 [GS-…

什么是抖音橱窗?它和抖音小店有什么区别?普通人更适合做哪个?

大家好&#xff0c;我是电商糖果 相信有很多想在抖音卖货的朋友&#xff0c;都会搞不清抖音橱窗是什么&#xff1f; 甚至会把它和抖音小店当成一个项目&#xff0c;也不知道哪个更适合自己。 自己越了解发现越迷糊&#xff0c;有的说不需要直播&#xff0c;粉丝&#xff0c;…

汇智知了堂鸿蒙课程全新升级,权威师资引领AI新纪元

在人工智能飞速发展的今天&#xff0c;汇智知了堂紧跟时代步伐&#xff0c;全面升级鸿蒙课程&#xff0c;以权威师资、实战导向、互动教学、资源支持为核心&#xff0c;为广大学员带来前所未有的学习体验&#xff01; 首先&#xff0c;汇智知了堂鸿蒙课程汇聚了业内知名专家&…

软件设计师-应用技术-数据流图题1

基础知识及技巧&#xff1a; 0. 概念&#xff1a; 在结构化分析中&#xff0c;数据流图用来记录系统中的数据和数据在特定的过程中的流动&#xff0c;即数据如何被采集、处理、保存和使用的(围绕信息系统的功能)。 1. 元素实例&#xff1a; 补充知识&#xff1a;** 外部实体…

sqlx执行案例

SQLx简介 SQLx是Rust语言中的一个异步SQL数据库连接库&#xff0c;它支持多种数据库&#xff0c;如PostgreSQL、MySQL和SQLite。SQLx提供了简单的API和异步执行查询的能力&#xff0c;使得Rust程序员可以轻松地与数据库交互1。 本章节以PostgreSQL为例。 目录结构 cargo.tom…

区块链开发用的是哪种编程语言?

区块链技术作为近年来备受瞩目的新兴技术之一&#xff0c;其核心的特性之一就是去中心化、安全性高、透明度高和可扩展性强。而区块链的开发语言则是实现这一技术的关键因素之一。那么&#xff0c;区块链开发语言是哪一种编程语言呢&#xff1f; 一、区块链开发语言的特点和选…

五一热度最大,销量最高的十大随身WiFi!某东、某宝倾力推荐!2024随身wifi靠谱品牌推荐!随身wifi怎么选?

还在争论谁才是最强的随身WiFi&#xff1f;要我说别再争了&#xff01;直接用事实说话&#xff01;看看五一小长假期间&#xff0c;消费者购买最多、评价最好的十款随身WiFi&#xff01;数据综合了某宝、某东、某多多&#xff0c;绝对真实可靠&#xff01; 第一名&#xff1a;格…

今日详解,教你如何不直播在视频号卖货

大家好&#xff0c;我是电商笨笨熊 视频号作为背靠微信的平台&#xff0c;从不需要考虑自身的流量问题&#xff0c; 因此在视频号推出之后就有大批的主播从其他平台转入视频号&#xff1b; 而这时候很多普通人应该也发现了新的机会&#xff0c;不再去内卷抖音、快手直播&…

Java Jackson-jr 库使用介绍

介绍 Jackson-jr 是一个轻量级的Java JSON 处理库。这个库被设计用来替代 Jackson 的复杂性。对比 Jackson 的复杂 API&#xff0c;Jackson-jr 的启动速度更快&#xff0c;包大小更小。 虽然Jackson databind&#xff08;如ObjectMapper&#xff09;是通用数据绑定的良好选择…

[SaaS]建筑领域的sd应用

AirchiDesignhttp://www.aiarchi.art/#/建筑学长——千万建筑师的资源库和AI绘图创作平台建筑学长官网,为青年设计师建立的线上资源共享及AI绘图创作渲染平台,免费提供海量设计案例、CAD图纸、SU模型、PS素材、软件插件下载,提供丰富的设计软件教学与灵感参考素材图库。https:/…

贵州航天电科:“小程序+二维码”,消防器材巡检系统上线

近日&#xff0c;网信部完成轻量化的二维码巡检功能&#xff0c;消防器材巡检系统上线&#xff01;通过“小程序二维码”结合方式&#xff0c;实现灭火器、消火栓等消防器材全面巡检。 前期&#xff0c;网信部联合行政保卫部开展消防器材台账信息数据核查&#xff0c;确保台账信…
最新文章