Activity 跳转详解

Activity 跳转详解Activity跳转详解你好!我是Graydalf,有可能也叫Gdalf~今天被朋友问到如何设置一个广播来启动一个应用并显示数据,于是将自己了解到的记录下来,有什么较为DEMO的地方希望你能留言告诉我,因为我们都是GitHub嘛~~本节说明:Activity跳转的方式;跳转传值问题(包括非Activity的跳转到Activity);跳转传递值时生命周期回调函数调用情况

大家好,又见面了,我是你们的朋友全栈君。

Activity 跳转详解

你好! 我是 Graydalf ,有可能也叫 Gdalf ~
今天被朋友问到如何设置一个广播来启动一个应用并显示数据,于是将自己了解到的记录下来,有什么较为 DEMO 的地方希望你能留言告诉我,谢谢。


  • 本节说明
  • Activity 跳转的方式
  • 跳转传值问题(包括非 Activity 的跳转到 Activity)
  • 跳转传递值时生命周期回调函数调用情况

1. 显示跳转

通过字节码方式进行跳转,需要获取到字节码,所以多用于工程内跳转。

逻辑步骤

  • 通过Activity的实现类对象调用 startActivity(Intent intent) 方法跳转
  • 然后需要创建一个Intent对象 Intent i = new Intent(getApplicationContext(), MyActivity.class) ,参数1 可以使用通用的Context对象,参数2 则是需要跳转到的Activity字节码对象
  • 可以在Intent对象中存放数据 i.putExtra(key, value)
  • 然后再调转到的Activity中使用 getIntent().getStringExtra(key) 等方法来获取数据

2. 隐式跳转

通过意图拦截器 <intent-filter /> 来实现跳转

逻辑步骤

  • 配置意图拦截器
<intent-filter>
    <action android:name="android.intent.action.MyActivity"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:scheme="call"/>
    <data android:mimeType="data/url"/>
</intent-filter>
<!-- action android:name 配置用于启动此Activity的请求字串 -->
<!-- category android:name 只能使用系统定义好的类型,这里类型为默认 -->
<!-- data android:scheme 数据前缀,请求的URI必须以此前缀+`:`开头 -->
<!-- data android:mimeType 数据类型限制 -->
  • 通过Activity的实现类对象调用 startActivity(Intent intent) 方法跳转
  • 然后需要创建一个Intent对象 Intent i = new Intent()
  • 设置请求字串 i.setAction("android.intent.action.MyActivity")
  • 设置请求类型 i.addCategory("android.intent.category.DEFAULT")
  • 设置Data和Type i.setDataAndType(Uri.parse("src:"+"values"), "data/url") ,注意不能分别调用 setData(uri)setType(str) 方法,方法内部互相置空,列出其中一个的源码解释:
public Intent setType(String type) { 
   
    mData = null;//这里置空了对方
    mType = type;
    return this;
}
  • 然后再调转到的Activity中使用 getIntent().getStringExtra(key) 等方法来获取数据

非Activity跳转到Activity

我们用一个实例来讲解这种情况下遇到的问题

广播监视短信,启动Activity并且显示短信,流程图如下:

Created with Raphaël 2.1.0 Received sms Receiver onReceive Start Activity Show Message

1. Create BroadCastReceiver

public class SmsReceiver extends BroadcastReceiver { 
   

    @Override
    public void onReceive(Context context, Intent intent) {
        Object[] objects = (Object[])intent.getExtras().get("pdus");
        for(Object obj:objects) {
            SmsMessage message = SmsMessage.createFromPdu((byte[])obj);
            //获取发送人号码
            message.getOriginatingAddress();
            //获取内容
            String messageBody = message.getMessageBody();

            Intent i = new Intent(context, MainActivity.class);
            i.putExtra("sms", messageBody);
            //此处有BUG,我们在后面说明
            context.startActivity(i);

            Toast.makeText(context, "接收短信完毕:"+messageBody, Toast.LENGTH_SHORT).show();

            //这里演示,要是短信长度超过一条我就只取第一条
            break;
        }
    }
}

2. Register BroadCastReceiver

<receiver android:name="com.example.receiver.SmsReceiver" >
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
    </intent-filter>
</receiver>

3. 创建MyActivity

故事情节可能会很波折,这是因为涉及到:

  • getIntent() 获取Intent异常
  • 非Activity对象调用 startActivity()
  • Activity重复启动周期

在onCreate()方法中处理显示

public class MainActivity extends Activity { 
   

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

        Intent i = getIntent();
        if (i != null) {
            TextView tv = (TextView) findViewById(R.id.tv);
            tv.setText(i.getStringExtra("sms"));
        }
    }

这时候我们让程序跑起来,系统向我们我们报错

erro: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

上面的意思是说我们在非Activity context中调用 startActivity(),必须申明 FLAG_ACTIVITY_NEW_TASK 标记

这是什么意思呢,我们 Ctrl + 左键 进入 context.startActivity(i) 内部查看下源码

/** * ... * <p>Note that if this method is being called from outside of an * {@link android.app.Activity} Context, then the Intent must include * the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag. This is because, * without being started from an existing Activity, there is no existing * task in which to place the new activity and thus it needs to be placed * in its own separate task. * ... */
    public abstract void startActivity(Intent intent, Bundle options);
/* 若使用Activity之外的上下文对象启动一个Activity,则必须让Intent拥有 FLAG_ACTIVITY_NEW_TASK 启动标识,这是为了: 1.若已经有此Activity对象存在(也就是存在一个放置此Activity的任务栈),则在其任务栈中放置新的Activity对象 2.若没有现有的Activity对象存在(任务栈也不存在),因此需要将其放置在其自己独立的任务栈中。 */

所以我们在 SmsReceiveronReceive() 方法中调用 context.startActivity(i) 前加上 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ,然后再次运行程序,模拟发送短信,此时我们能够接收到短信并且显示出来。

在onResume()方法中处理显示

但是上面的写法对用户的体验非常不好,因为每条短信都会重新创建一个Activity对象压入任务栈,我们要是想不创建新的Activity只在当前Activity中显示又该如何做呢?

首先想到的是在将Activity的启动模式设置成 android:launchMode="singleTop" 这代表任务栈栈顶只能存在一个此Activity对象,这样我们在重复跳转的时候就不会重新创建了,设置如下:

<activity  android:launchMode="singleTop" android:name="com.example.receiver.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>

这时我们运行程序并且模拟发送短信,发现没有显示短信内容,这是因为我们的显示短信代码在onCreate()方法中,此方法只能在Activity被创建时调用,这里因为 singleTop 启动模式并没有重新创建Activity,我们将7个生命周期回调方法都打上Log,发现当不创建新Activity对象的前提下调用 startActivity() 方法,声明周期函数只会先执行 onPause() 再执行 onResume ,所有我们将 onCreate() 中的显示代码移动到 onResume() 中来,再次测试,新的问题又出现啦,打上Log明明 onResume() 执行了,死活不出结果!!(波折么?)

getIntent()方法的特点

我们将显示代码打上断点可以观测到,每次启动时, getIntent() 取得的方法总是 null (注:若你在模拟发送短信前,应用已经关闭,那么会回显示第一次的数据,再次发送短信取得的都是第一次的数据),我们继续 Ctrl + 左键 进入 getIntent() 方法内部查看源码:

/** Return the intent that started this activity. */
public Intent getIntent() {
    return mIntent;
}
/* 翻译:返回启动Activity时的intent */

光看这个你很难理解到什么叫返回启动时候的intent,本可以最简洁地口头描述给你看,但是这里还是准备用事实说话,我们继续查找名称中带有intent的方法,果然找到个文字叙述比较多且痛快的方法 onNewIntent() 的,如下:

/** * This is called for activities that set launchMode to "singleTop" in * their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP} * flag when calling {@link #startActivity}. In either case, when the * activity is re-launched while at the top of the activity stack instead * of a new instance of the activity being started, onNewIntent() will be * called on the existing instance with the Intent that was used to * re-launch it. * * <p>An activity will always be paused before receiving a new intent, so * you can count on {@link #onResume} being called after this method. * * <p>Note that {@link #getIntent} still returns the original Intent. You * can use {@link #setIntent} to update it to this new Intent. */
protected void onNewIntent(Intent intent) {
}

/* 第一句话就很给力,描述了此方法可能的使用场景,正好符合,翻译:当我们调用一个 singleTop 启动模式的 Activity,或者调用 startActivity(intent) 方法时参数为标识 FLAG_ACTIVITY_SINGLE_TOP 的 Intent 对象时。 然后是说:当已经有此 Activity 实例存在栈顶时,上面两种情况都会导致 onNewIntent() 方法被调用。 下面两个段落是说: 1. Activity 将总是被 paused 之后才去接收一个新的intent,所以你可以等此方法(onNewIntent)被调用完毕时,在 onResume() 方法中去写自己的代码。 2. getIntent 方法总是返回原来的值,你可以使用 setIntent() 方法去更新一个新的intent。 */

看完解释已经很明白了,我们现在修改重写 onNewIntent(intent) 方法如下:

@Override
protected void onNewIntent(Intent intent) {
    setIntent(intent);
}

现在再来运行程序,完美~


谢阅!
有什么好的建议和疑问可以在下面留言。

GitHub,才是男人的浪漫!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/143179.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • PHP和PHPINFO

    PHP和PHPINFOPHP开放源码和跨越平台,PHP可以运行在WINDOWS和多种版本的LINUX上。它不需要任何预先处理而快速反馈结果,它也不需要mod_perl的调整来使您的服务器的内存映象减小。PHP消耗的资源较少

  • css 自定义滚动条样式

    css 自定义滚动条样式我遇到的场景:对于iframe窗口,自带滚动条是整个窗口的大小。有时需要顶部或底部固定,则滚动条不应该触碰到顶部或底部。那么首先打开iframe时应该去掉滚动条scrolling="n

  • 简易旋转倒立摆_小车倒立摆受力分析讲解

    简易旋转倒立摆_小车倒立摆受力分析讲解旋转倒立摆调节经验前言程序框架关于直立关于自动起摆前言近期在做2013年电赛控制类题目–简易旋转倒立摆装置,自己并不是自动化专业的学生,没有学过自动控制原理,倒立摆其实是一个十分经典的自动控制模型,我们只能是边做边学习,逐渐去了解倒立摆。我认为倒立摆有两个难点,一个是自动起摆一个是机械结构,其中自动起摆涉及到PID算法与运动方程的求解,而机械结构主要是尽量减小转动阻尼同时避免旋转时线的缠绕。…

  • PHP面试题:HTTP中POST、GET、PUT、DELETE方式的区别

    PHP面试题:HTTP中POST、GET、PUT、DELETE方式的区别

    2021年10月12日
  • Java手机游戏开发专辑「建议收藏」

    Java手机游戏开发专辑「建议收藏」Java手机游戏开发专辑  关键字 KXML MMAPI HTTP XML CLDC   移动动作游戏开发中的一些问题  即使目前最新型号的手机仍然不是最理想的游戏平台,但它已经是个良好的开端。处理器、内存和色彩深度提供了游戏开发所需的因素。开发者正努力把其它游戏平台上的质量标准运用到这个平台上。当然了,一些问题仍然存在,然而这些问题终将被解决,就象PC平台游戏开发者使用不断改进的Di

  • 炒黄金入门必备基础知识学习「建议收藏」

    炒黄金入门必备基础知识学习「建议收藏」黄金投资在西方发达国家已经有百年历史了,其运作流程、交易体系都越来越完善,而且投资市场也越来越成熟。黄金市场是国际金融投资的热点。伦敦的现货黄金市场、美国的黄金期货市场、香港金银业贸易场等地的黄金市场组成了全球24小时不间断的黄金投资市场。一、交易介绍国际现货黄金以保证金的方式进行的一种现货交易业务,买卖双方以一定比例的保证金确立买卖合约,该合约可以不必实物交收,买卖双方可以根据市场的变化情…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号