2026-06-20 有关activity的一点记录
文章目录1. 开发中的一点理解2. 显式Intent与隐式Intent2.1 显式Intent2.2 隐式Intent2.3 隐式Intent的更多用法2.3.1 调用外部浏览器打开链接2.3.2 内部实现Activity打开链接3. Intent传递消息3.1 单向传递消息3.2 传递消息并接收返回消息4. 总结与下一步计划1. 开发中的一点理解类比网站应用activity就像是程序的后端负责逻辑处理在后台默默工作activity会为当前的这个页面服务其存在是无法被用户的视觉直接感知的。其本质是一个java文件或者kotlin文件。那么屏幕上我们看到的各种信息是哪来的其实是布局文件显示的也就是layout文件其本质是xml文件用来控制界面的显示类似于网站程序的前端页面可以直接被用户感知。网站应用中的前后端数据传输可以通过http/https传输但是安卓呢安卓使用的是id注册方式布局文件也就是xml文件中每一个部件文本框或者按钮之类的在生成时都要制定一个id值就像人的身份证号一样此后便可以在activity文件中通过调用findViewByid()函数找到它们了。可能有人会有疑惑网站应用需要网络数据传输才能建立起前后端连接为什么安卓不用那是因为安卓应用与网站应用架构不太一样网站应用大多是CS模式分为客户端和服务端后端在服务器上前端在客户机的浏览器上两者想要建立链接就要借助互联网建立在TCP/IP的基础上而安卓不是安卓的整个源码都在用户的手机上虽然有的会有混淆所以无需网络便可建立起“前端”布局文件和“后端”activity的链接。除了这些文件我们还可以定义一些其他的功能性类文件比如建立一个全局的单例类ToastUtil用于处理Toast显示问题这样可以保证主线程始终只有一个Toast避免因各种情况如用户误用连点器导致的大量Toast对象占用资源。//kotlinobjectToastUtil{privatevartoast:Toast?nullfunshow(context:Context,message:String){toast?.cancel()toastToast.makeText(context.applicationContext,message,Toast.LENGTH_LONG)toast?.show()}}当然安卓开发不止这些文件还有很多其他的文件但是因为数量庞大我不可能全部都记录下来只会记录一些对我自己有价值的我对博客读者没有冒犯的意思但我要说的是我的博客会以我自己为第一优先级所以有些地方我如果觉得对于我自己来说是常识就不会记录。有的东西就算记录了也可能会很混乱因为我要考虑效率与详细的平衡点。每一个Activity都要在AndroidManifest.xml中注册才可以使用一定要有一个主Activity并且也只能拥有一个告诉程序刚开启的页面是哪个页面相当于网站应用的index.php。?xml version1.0 encodingutf-8?manifestxmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsapplicationandroid:allowBackuptrueandroid:dataExtractionRulesxml/data_extraction_rulesandroid:fullBackupContentxml/backup_rulesandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/Theme.FirstCode_chapter03activityandroid:name.SecondActivityandroid:exportedfalse/activityandroid:name.FirstActivityandroid:exportedtrueandroid:labelthatapos;s first activityintent-filteractionandroid:nameandroid.intent.action.MAIN/categoryandroid:nameandroid.intent.category.LAUNCHER//intent-filter/activity/application/manifestandroid:exported这个属性控制当前activity是否允许被其他应用的组件调用。当activity有intent-filter属性时这个值要设置为true2. 显式Intent与隐式Intent2.1 显式IntentIntent在activity方面的作用简单来说就是充当两个activity之间沟通的桥梁。当想要从一个activity开启另一个activity时可以用以下这种显式Intent进行传递findViewByIdButton(R.id.button1).setOnClickListener{valintentIntent(this,SecondActivity::class.java)startActivity(intent)}外面那层findView不必在意主要看里面使用Intent的这个构造方法生成一个Intent对象。参数一是Context类型的要求一个启动指定Activity的上下文简言之就是说明被启动的activity是从哪启动的一般情况直接填当前activity即可也就是this对象参数二是class类型的要求指定开启哪一个activity一般来讲我们将目标activity放上去即可比如例子中所写的SecondActivity::class.java如果是java语言的话就是SecondActivity.class然后直接使用startActivity将intent启动就可以启动SecondActivity了。2.2 隐式Intent可以看见显式Intent启动activity是通过直接指定目标activity的方式实现的。与之相对应隐式Intent并不直接指定要启动的activity而是通过指定action和category等属性来匹配目标activity。action和category是activity的属性具体请看前面的AndroidManifest.xml文件。疑问点在于既然都是指定直接指定activity和指定属性有什么区别吗有的直接指定activity表示通过我这一步操作我要的就是这个activity这个activity能满足我这一步操作的接下来的行为而指定属性表示我不知道我的这个操作会跳转到哪个activity因为我并不知道哪个activity可以满足我的操作我只知道我要干这件事——action是xxx并且category是xxx具体哪个activity能满足我那就要看谁能帮我干这件事了。进一步类比的话就像我们寄信显式寄信相当于我指定了送信人我就要我指定的送信人帮我送隐式寄信相当于我这封信要寄出去我要求一名男性且留有长发的送信人具体是谁邮局自己分配吧满足我的要求就行。具体实现// kotlinfindViewByIdButton(R.id.button_1).setOnClickListener{valintent2Intent(com.example.firstcode_chapter03.ACTION_START)intent2.addCategory(com.example.firstcode_chapter03.MY_CATEGORY)startActivity(intent2)}// AndroidManifest.xml?xml version1.0 encodingutf-8?manifestxmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsapplicationandroid:allowBackuptrueandroid:dataExtractionRulesxml/data_extraction_rulesandroid:fullBackupContentxml/backup_rulesandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/Theme.FirstCode_chapter03activityandroid:name.SecondActivityandroid:exportedtrueintent-filteractionandroid:namecom.example.firstcode_chapter03.ACTION_START/categoryandroid:nameandroid.intent.category.DEFAULT/categoryandroid:namecom.example.firstcode_chapter03.MY_CATEGORY//intent-filter/activityactivityandroid:name.FirstActivityandroid:exportedtrueandroid:labelthatapos;s first activityintent-filteractionandroid:nameandroid.intent.action.MAIN/categoryandroid:nameandroid.intent.category.LAUNCHER//intent-filter/activity/application/manifest2.3 隐式Intent的更多用法2.3.1 调用外部浏览器打开链接使用隐式Intent不仅可以启动本应用的activity还可以启动其他程序的activity这使得多个应用之间的消息共享成了可能比如我们点击一个链接打开网页就没有必要自己实现一个浏览器了使用手机自带的即可。添加一个按钮//first_layout?xml version1.0 encodingutf-8?LinearLayoutxmlns:androidhttp://schemas.android.com/apk/res/androidandroid:orientationverticalandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentButtonandroid:idid/button1android:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text显式启动第二个Activity/Buttonandroid:idid/button_1android:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text隐式启动第二个Activity/Buttonandroid:idid/start_browserandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text打开预定义的链接/Buttonandroid:idid/back_buttonandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text销毁当前Activity//LinearLayout//FirstActivity.ktpackagecom.example.firstcode_chapter03importandroid.annotation.SuppressLintimportandroid.content.Intentimportandroid.os.Bundleimportandroid.view.Menuimportandroid.view.MenuItemimportandroid.widget.Buttonimportandroidx.appcompat.app.AppCompatActivityimportandroidx.core.net.toUriclassFirstActivity:AppCompatActivity(){SuppressLint(MissingInflatedId)overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContentView(R.layout.first_layout)findViewByIdButton(R.id.button1).setOnClickListener{valintentIntent(this,SecondActivity::class.java)startActivity(intent)}findViewByIdButton(R.id.button_1).setOnClickListener{valintent2Intent(com.example.firstcode_chapter03.ACTION_START)intent2.addCategory(com.example.firstcode_chapter03.MY_CATEGORY)startActivity(intent2)}// 重点看这里这是添加的隐式Intent打开网站操作findViewByIdButton(R.id.start_browser).setOnClickListener{valintent3Intent(Intent.ACTION_VIEW)intent3.datahttps://www.baidu.com.toUri()startActivity(intent3)}findViewByIdButton(R.id.back_button).setOnClickListener{finish()}}overridefunonCreateOptionsMenu(menu:Menu?):Boolean{menuInflater.inflate(R.menu.main,menu)returntrue}overridefunonOptionsItemSelected(item:MenuItem):Boolean{when(item.itemId){R.id.add_item-ToastUtil.show(this,这是添加按钮)R.id.remove_item-ToastUtil.show(this,这是删除按钮)}returntrue}}2.3.2 内部实现Activity打开链接正如前面所说的我们同样可以自己创建一个activity来接收intent的命中首先我们观察intent的要求action为Intent.ACTION_VIEWdata是https://www.baidu.com创建Activity空的仅演示可以被命中packagecom.example.firstcode_chapter03importandroid.os.Bundleimportandroidx.appcompat.app.AppCompatActivityclassThirdActivity:AppCompatActivity(){overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContentView(R.layout.third_activity)}}!-- third_layout.xml --?xml version1.0 encodingutf-8?LinearLayoutxmlns:androidhttp://schemas.android.com/apk/res/androidandroid:orientationverticalandroid:layout_widthmatch_parentandroid:layout_heightmatch_parent/LinearLayout!-- AndroidManifest.xml --activityandroid:name.ThirdActivityandroid:exportedtrueintent-filtertools:ignoreAppLinkUrlErroractionandroid:nameandroid.intent.action.VIEW/categoryandroid:nameandroid.intent.category.DEFAULT/dataandroid:schemehttps//intent-filter/activity如下图出现让我们选择的选项因为我们写的activity和浏览都被命中了这里我们点击自己定义的activity。如下图跳转到了我们自己定义的activity因为是空的所以啥也没显示。此外还可以设置data为tel:10086action为Intent.ACTION_DIAL这样的形式来命中电话服务这里不做展开了。3. Intent传递消息3.1 单向传递消息使用putExtra()来向目标activity传递信息以键值对的形式来添加findViewByIdButton(R.id.button_sendMessage).setOnClickListener{valstrHello Secvalintent5Intent(this,SecondActivity::class.java)intent5.putExtra(招呼信息,str)startActivity(intent5)}目标使用getStringExtra()来获取消息valstrintent.getStringExtra(招呼信息)ToastUtil.show(this,Fir说${str})3.2 传递消息并接收返回消息不仅可以实现从activity1向activity2发送消息当activity2销毁时还可以携带信息返回给activity1//Activity1// 注册一个启动器privatevalstartForResultLauncherregisterForActivityResult(ActivityResultContracts.StartActivityForResult()){if(it.resultCodeActivity.RESULT_OK){valdatait.data?.getStringExtra(返回消息)ToastUtil.show(this,Sec说${data})}}//Activity1//绑定事件findViewByIdButton(R.id.button_sendAndReceive).setOnClickListener{valstrhello Secvalintent6Intent(this,SecondActivity::class.java)intent6.putExtra(招呼信息,str)startForResultLauncher.launch(intent6)}//Activity2//处理接收的数据并准备返回数据valstrintent.getStringExtra(招呼信息)ToastUtil.show(this,Fir说${str})findViewByIdButton(R.id.button_returnMessage).setOnClickListener{valintentIntent()intent.putExtra(返回消息,Hello Fir)setResult(RESULT_OK,intent)finish()}这样的话点击按钮跳转到activity2后屏幕下方就会打印activity1向activity2说的话。当点击activity2中的这个按钮后返回的消息就会记录在intent中并且随着finish()的执行activity2被销毁马上返回activity1并将返回消息打印出来。当然可以自己决定什么时候销毁activity2比如去掉代码销毁finish()以自己手动返回的形式销毁activity2返回activity1。那么当返回之后屏幕下方的消息就会出现也就是说此时activity1接收到了来自activity2的“圣遗物”。如果不点击按钮直接返回呢那么按照上面的方法是没有办法收到来自activity2的消息的如果想要得到消息就需要在activity2的onCreate中加上这个API方式onBackPressedDispatcher.addCallback(this,object:OnBackPressedCallback(true){overridefunhandleOnBackPressed(){valintentIntent().apply{putExtra(返回消息,Hello Fir(BackPress))}setResult(RESULT_OK,intent)finish()}})4. 总结与下一步计划安卓太难学了主要是一个版本的更新会启用很多东西并且加上很多新的东西这就让学习成本大大提升了我们不得不根据目标sdk的不同版本来进行语法和函数的切换唉难啊难。接下来搞懂Activity的声明周期。