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并且显示短信,流程图如下:
1. Create BroadCastReceiver
public class SmsReceiver extends BroadcastReceiver {@Overridepublic 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 {@Overrideprotected 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对象存在(任务栈也不存在),因此需要将其放置在其自己独立的任务栈中。
*/
所以我们在 SmsReceiver
的 onReceive()
方法中调用 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,才是男人的浪漫!
Activity 跳转详解相关推荐
- Android面试之Activity生命周期详解
Activity生命周期详解 一 Activity的四种状态: Activity的生命周期中存在四种基本的状态:活动状态(Active/Runing),暂停状态(Paused),停止状态(Stoppe ...
- Android系统(187)---最易懂的Activity启动模式详解
Android基础:最易懂的Activity启动模式详解 前言 Android基础中,Activity的启动模式非常重要 本文将全面介绍 Activity的启动模式 目录 目录 1. 定义 即Acti ...
- 二叉树,平衡二叉树,B-Tree,B+Tree,跳表详解
二叉树,平衡二叉树,B-Tree,B+Tree,跳表详解 1.二叉查找树(BST) 1.1 二叉查找树概念 1.2 二叉查找树特点 2. 平衡二叉树(AVL) 2.1 平衡二叉树概念 2.2 平衡二叉 ...
- Android Activity 生命周期详解及监听
前言 系列文章: Android Activity 与View 的互动思考 Android Activity 生命周期详解及监听 Android onSaveInstanceState/onResto ...
- Activity生命周期详解及最佳实践
前言 该文章来自一个开源项目,致力于翻译Google官方文档,很棒,已经有成果了.PDF版本可以去这里下载http://hukai.me/eBooks/AndroidTrainingCHS.pdf,以 ...
- 微信小程序02【配置详解、生命周期-app对象使用、页面跳转详解】
学习地址:https://www.bilibili.com/video/BV1sx411z77P 笔记01:https://blog.csdn.net/weixin_44949135/article/ ...
- vue ajax拦截器,Vue-resource拦截器判断token失效跳转详解
本文主要为大家带来一篇Vue-resource拦截器判断token失效跳转的实例.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧,希望能帮助到大家. 在拦截器中设置全局的 ...
- Activity生命周期详解
在我的Android四大组件详解一文中已经对Activity的生命周期进行过一个比较详细的介绍.这篇文章我们再来更加深入地介绍Activity的生命周期. 一.Activity的生命周期方法如下: o ...
- Android FrameWork——Activity启动过程详解
前面发了blog分析了ActivityManager框架的大体结构,主要就是一个进程通信机制,今天我通过深入Activity的启动过程再次深入到ActivityManager框架,对其进行一个更深入的 ...
最新文章
- elasticsearch解决控制台中文乱码问题
- 网络带宽和速度测试windows和linux iperf工具
- 关于游戏开发中时间性能统计工具本身overhead较高的问题
- verilog中timescale
- 清空Form表单所有内容
- 大型WEB架构概况(笔记整理)一
- SAP Cloud for Customer的Container应用设计原理
- Vue Bootstrap OSS 实现文件追加上传、断点续传、极速秒传
- dubbo通信协议之对比
- 7 ida pro 网盘_IDA分析iOS网络协议
- 定时任务管理系统 java_几种任务调度的 Java 实现方法与比较(定时任务)(转)...
- Gartner:智能SOC/情报驱动的SOC的五大特征
- 北京市植被指数(NDVI)数据
- 在命令行中使用vs编译器
- mysql求平方根_MySQL数据库中如何求一个数的二次平方根(SQRT函数)呢?
- ue4 源码编译 虚拟内存不足 堆限制
- MySQL插入数据错误Incorrect string value: ‘\xE8\x85\xBE\xE8\xAE\xAF‘ for column ‘custname‘ at row 1
- ios+手机壳+瞬间切换android,不只是双卡双待,这个手机壳能让你的 iPhone 运行 iOS + Android 双系统...
- 有信仰与无信仰家族200年对比,让世人震惊!!
- 净误差与遗漏为负值的含义_【双语】跳出“资本外逃”之争看净误差与遗漏
热门文章
- <动态规划>完全背包(最大价值,恰好装满最大价值)
- 从点点点到年薪30W的心理历程--测试君请进,绝对让你不虚此行!
- Linux基于单链表环形队列的多线程生产者消费者模型
- 把打包后的文件直接放到itues上进行安装的步骤
- 191. 位 1 的个数 ●
- 雷替曲塞-聚乙二醇-小麦胚凝集素 Raltitrexed-PEG-Wheat germ agglutinin
- 毕业设计 嵌入式 智能MP3音乐播放器设计与实现 - 物联网
- [C++]简单的十六进制转十进制
- 50个找文献资料的中外全球电子数据库【收藏】
- 商业银行经营全解析之FTP(内部资金转移定价)