用来与用户交互,一个应用可以包含多个或零个Activity。
这部分只要跟书上的操作就好了,这边对书上的部分代码进行解释(按书解释)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button" //定义一个id
android:layout_width="match_parent" //让当前元素与父类一样宽
android:layout_height="wrap_content" //表示当前元素的高度只要能刚好包含里面的内容就行
android:text="Button"/>
</LinearLayout>
class FirstActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.first_layout) //这一行对应的代码
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest">
<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/AppTheme">
<activity android:name=".FirstActivity"
android:label="This is FirstActivity"> //指定Activity中标题的内容
<intent-filter> // 为了声明配置主Activity
<action android:name="android.intent.action.MAIN" /> // 为了声明配置主Activity
<category android:name="android.intent.category.LAUNCHER"/> // 为了声明配置主Activity
</intent-filter> // 为了声明配置主Activity
</activity>
</application>
</manifest>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.first_layout)
val button1: Button = findViewById(R.id.button) //实例化
button1.setOnClickListener{ //为按钮注册监听器
Toast.makeText(this ,"you clicked Button 1",Toast.LENGTH_LONG).show() //点击按钮时,执行监听器中的onClick()方法。
//Toast方法使用:通过静态方法makeText(),传入第一个参数(Content),第二个参数(本文内容),第三个参数(显示时长,Toast.LENGRH_SHORT或者Toast.LENGRH_LONG) }
}
findViewById()的使用:
作用:获取布局文件中控件的实例。
使用:一个控件要调用一次
简化:使用代码补全功能
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="Add" />
<item
android:id="@+id/remove_item"
android:title="Remove"/>
</menu>
//创建了两个菜单项 add_item(菜单选项名:Add) remove_item(菜单选项名:Remove)
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.main ,menu)
//menuInflater使用了语法糖,调用了父类的getMenuInflater()然后得到一个MenuInflater对象,再调用inflate()方法
return true
}
//通过inflate()将R.menu.main文件传入menu(Menu)对象中
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when(item.itemId){
R.id.add_item -> Toast.makeText(this,"you clicked Add",Toast.LENGTH_SHORT).show()
R.id.remove_item -> Toast.makeText(this,"you clicked Remove",Toast.LENGTH_LONG).show()
}
return true
}
//利用item调用背后的getItemId()方法 然后调用item.itemId 来判断点击的哪个菜单项,最后用when对应到指定的路径+Toast
button1.setOnClickListener {
finish() //结束这个Activity
}
button1.setOnClickListener{
val intent = Intent(this,SecondActivity::class.java) //SecondActivity::class.java 相当于SecondActivity.class
startActivity(intent)
}
//AndroidManifest.Xml 中声明
android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" /> //该category为默认category
</intent-filter>
//FirstActivity中实现
button1.setOnClickListener{
val intent = Intent("com.example.activitytest.ACTION_START") //传入字符串,响应这个action的Activity
startActivity(intent) //调用startActivity()时自动传入category到intent中
}
intent只能指定一个action 但是能指定多个category 如下:
android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.activitytest.MY_CATEGORY"/> //必须声明新添加的category!!!
</intent-filter>
button1.setOnClickListener{
val intent = Intent("com.example.activitytest.ACTION_START")
intent.addCategory("com.example.activitytest.MY_CATEGORY") //使用addCategory()
startActivity(intent)
}
隐式intent不仅可以使用自己程序内的Activity还可以使用其他程序的Activity
button1.setOnClickListener{
val intent = Intent(Intent.ACTION_VIEW) //Intent.ACTION_VIEW是Android系统内置的动作
intent.data = Uri.parse("https://www.baidu.com") //Uri.parse()方法将网址字符串解析成Uri对象 setData()方法将Uri对象传递。
startActivity(intent)
}
创建一个Activity 让它响应intent
//主界面按钮点击事件的代码
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.first_layout)
button1.setOnClickListener{
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.baidu.com")
startActivity(intent)
}
}
//新建activity的布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button3"/>
</LinearLayout>
//在AndroidManifest.xml中注册信息
<activity android:name=".ThirdActivity">
<intent-filter tools:ignore="ApplinkUrlError">
<action android:name="com.example.intent.actoin.VIEW" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
</intent-filter>
</activity>
除了https协议外还有 geo tel 协议
用法: Uri.prase("xxx: ")
传入字符串:
//firstActivity向SecondActivity传数据
button1.setOnClickListener{
val data = "hello SecondActivity"
val intent = Intent(this,SecondActivity::class.java)
intent.putExtra("extra_data",data)
//putExtra()方法 第一个参数是键(Intenth中取值) 第二个参数才是真正要的数据
startActivity(intent)
}
// SecondActivity中将传入的数据打印出来
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.second_layout)
val extraData = intent.getStringExtra("extra_data")
//getStringExtra()用于传入相应的键值 获取传递的数据
Log.d("SecondActivity","extra data is &extraData")
}
}
//改变按钮事件
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.first_layout)
button1.setOnClickListener{
val intent = Intent(this,SecondActivity::class.java)
//Intent() 第一个参数要求提供一个启动Activity的上下文
//第二个参数指定想要启动的目标Activity
startActivityForResult(intent,1)
//第一个参数启动目标Activity 第二个参数是请求码 用于判断回调数据的来源
}
}
//SecondActivity中注册点击事件
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.second_layout)
val intent = Intent()
intent.putExtra("data_return","Hello FirstActivity") //存放传递数据
setResult(Activity.RESULT_OK)
// setResult 接受两个参数 第一个用于向上一个activity返回处理结果 一般使用RESULT_OK 或RESULT_CANCELED 这两个值
//第二个参数是把带有数据的intent传回去
finish() //结束这个activity
}
//startActivityForResult()方法启动SecondActivity 当SecondActivity销毁后会回调上一个activity的startActivityForResult()方法
//
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
//onActivityResult() 有三个参数
/* 1启动Activity时传入的请求码 2返回数据时的处理结果 3携带返回数据的intent*/
when(requestCode){
1 -> if(requestCode == RESULT_OK) {
val returnedData = data?.getStringExtra("data_return")
//.? 判断不为空是进行
Log.d("FirstActivity","returned data is $returnedData")
}
}
}
后进先出的数据结构: 位于顶栈的原先的Activity先移除,然后新的Activity进顶栈, 系统只显示顶栈的给用户
<activity android:name=".DialogActivity"
android:theme="@style/Theme.AppCompat.Dialog">
</activity>
<activity android:name=".NormalActivity" />
//以上是NormalActivity和DialogActivity的声明 后者多了一个theme(对话框主题)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="This is a normal activity" />
</LinearLayout>
//以上是normalactivity的布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_parent"
android:text="This is a dialog activity"/>
</LinearLayout>
//以上是dialogactivity的布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent">
<Button
android:id="@+id/startNormalActivity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start NormalActivity" />
<Button
android:id="@+id/startDialogActivity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start DialogActivity"/>
</LinearLayout>
//以上是activity的布局文件
class MainActivity : AppCompatActivity() {
private val tag = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(tag,"onCreat")
setContentView(R.layout.activity_main)
startNormalActivity.setOnClickListener{
val intent = Intent(this,NormalActivity::class.java)
startActivity(intent)
}
startDialogActivity.setOnClickListener{
val intent = Intent(this,DialogActivity::class.java)
startActivity(intent)
}
}
override fun onStart() {
super.onStart()
Log.d(tag,"onStart")
}
override fun onResume() {
super.onResume()
Log.d(tag,"onResume")
}
override fun onPause() {
super.onPause()
Log.d(tag,"onPause")
}
override fun onStop() {
super.onStop()
Log.d(tag,"onStop")
}
override fun onDestroy() {
super.onDestroy()
Log.d(tag,"onDestroy")
}
override fun onRestart() {
super.onRestart()
Log.d(tag,"onRestart")
}
//以上方法什么执行就在日志中打印出来
}
使用onSaveInstanceState()回调方法
override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) {
super.onSaveInstanceState(outState, outPersistentState)
val temData = "something you just typed"
outState.putString("data_key",temData)
//第一个参数是键值 第二个参数是Bundle中取值
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(tag,"onCreat")
setContentView(R.layout.activity_main)
if (savedInstanceState != null){
val temData = savedInstanceState.getString("data_key")
Log.d(tag,temData)
}//如果有字符串 在日志中打印出来
}
Android的默认启动模式
在standar的模式下,每当启动一个新的Activity 它就会在返回栈并处于栈顶。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("FirstAcitivy",this.toString())
setContentView(R.layout.first_layout)
button1.setOnClickListener{
val intent = Intent(this,FirstActivity::class.java)
startActivity(intent) //每点击一次按钮就会创建一个实例 所以需要多次back 才能退出程序
}
}
<activity
android:name=".FirstActivity"
android:launchMode="singleTop" //启动singleTop模式
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("FirstAcitivy",this.toString())
setContentView(R.layout.first_layout)
button1.setOnClickListener{
val intent = Intent(this,FirstActivity::class.java)
startActivity(intent) 不会继续启动FirstActivity
}
//
让某个Activity在整个应用的上下文中只用一个实例
//修改FirstActivity的启动模式
<activity
android:name=".FirstActivity"
android:launchMode="singleTask"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
//在FIrstActivity中判断onRestart是否启动
override fun onRestart() {
super.onRestart()
Log.d("FirstActivity","onRestart")
}
//在SecondActivity中判断onDestroy是否使用
override fun onDestroy() {
super.onDestroy()
Log.d("SecondActivity","onDestroy")
}
解决Activity资源共享问题
//修改SecondActivity中启动模式
<activity android:name=".SecondActivity"
android:launchMode="singleInstance"> //就是本条代码
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.activitytest.MY_CATEGORY" />
</intent-filter>
</activity>
//使用 taskId(getTaskId)打印返回栈的id
//FirstActivity SecondActivity ThirdActivity的onCreat 分别如下
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("FirstAcitivy","Task id is $taskId")//调用父类的getTaskId
setContentView(R.layout.first_layout)
button1.setOnClickListener{
val intent = Intent(this,SecondActivity::class.java)
startActivity(intent)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("SecondActivity","Task id is $taskId")
setContentView(R.layout.second_layout)
button2.setOnClickListener {
val intent = Intent(this,ThirdActivity::class.java)
startActivity(intent)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("ThirdActivity","Task id is $taskId")
setContentView(R.layout.third_layout)
}
}
基本思路 在AppcompatActivity中加入一个子类 class 让原本继承AppcompatActivity的都继承这个class。
open class BaseActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("BaseActivity",javaClass.simpleName)//继承该class的Activity实现时都会打印出来(javaClass获取当前的class对象 simpleName 获取当前实例的类名)
}
}
思路: 用一个专门的集合对所有的Activity进行管理
//创建一个单例class
object ActivityCollector {
private val activities = ArrayList<Activity>()
//创建一个集合 储蓄所有使用的Acitivity
fun addActivity(activity: Activity){
activities.add(activity)
}
fun removeActivity(activity: Activity){
activities.remove(activity)
}
//创建 addActivity和removeActivity方法 用来添加和删除集合中的activity
fun finishAll(){ //利用循环结束所有activity
for (activity in activities){
if(!activity.isFinishing){
activity.finish()
}
}
activities.clear()
}
}
//在上次使用的 BaseActivity 实现打开或关闭Activity时就使用addActivity 或者 removeActivity 方法
open class BaseActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("BaseActivity",javaClass.simpleName)
ActivityCollector.addActivity(this)
}
override fun onDestroy() {
super.onDestroy()
ActivityCollector.removeActivity(this)
}
}
//在某个Activity实现退出程序
class ThirdActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("ThirdActivity","Task id is $taskId")
setContentView(R.layout.third_layout)
button3.setOnClickListener{
ActivityCollector.finishAll() //使用finishAll()
android.os.Process.killProcess(android.os.Process.myPid())
//使用killProcess杀掉一个进程 接受id参数 myPid()获取当前程序进程
}
}
}
解决可以更易看懂Activity之间的数据传输,让别人看懂
class SecondActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("SecondActivity","Task id is $taskId")
setContentView(R.layout.second_layout)
button2.setOnClickListener {
val intent = Intent(this,ThirdActivity::class.java)
startActivity(intent)
}
}
// 在companio object 中定义actionStart()方法
companion object {
fun actionStart(context: Context,data1: String,data2: String) {
val intent = Intent(context,SecondActivity::class.java)
intent.putExtra("param1",data1)
intent.putExtra("param2",data2)
context.startActivity(intent)
}
}
override fun onDestroy() {
super.onDestroy()
Log.d("SecondActivity","onDestroy")
}
}
//在某个地方实现启动该Activity的代码也简化了,如:
button1.setOnClickListener{
SecondActivity.actionStart(this,"data1","data2")
}
with: with函数接收两个参数:第一个参数可以是一个任意类型的对象,第二个参数是一个Lambda表达式。with函数会在Lambda表达式中提供第一个参数对象的上下文,并使用Lambda表达式中的最后一行代码作为返回值返回。
fun main() {
val list = listOf("apple","banana","orange","pear","grape")
/*化简前的代码
val builder = StringBuilder()
builder.append("Start eating fruits.\n")
for(fruit in list){
builder.append(fruit).append("\n") //将 fruit 循环移入builder中
}
builder.append("Ate all fruits.")
val result = builder.toString()
println(result) */
val result = with(StringBuilder()) {
// lambda表达式提供第一个参数对象的上下文
append("Start eating fruits. \n")
for (fruit in list){
append(fruit).append("\n")
// 附加上 fruit和“\n” 到对象中
append("Ate all fruits")
toString() //最后一行作为返回值
}
println(result)
}
有关StringBuilder()具体内容请看https://blog.csdn.net/csxypr/article/details/92378336
run: 与with十分相似
fun main() {
val list = listOf("apple","banana","orange","pear","grape")
val result = StringBuilder().run{ //与 with语法的区别
append("Start eating fruits. \n")
for (fruit in list){
append(fruit).append("\n")
}
append("Ate all fruits")
toString()
}
println(result)
}
==apply:==与run相似但是返回值不一样
/*语法如下
val result = obj.apply {
// 这里是obj的上下文
}
// result == obj*/
fun main() {
val list = listOf("apple","banana","orange","pear","grape")
val result = StringBuilder().apply{
append("Start eating fruits. \n")
for (fruit in list){
append(fruit).append("\n")
}
append("Ate all fruits")
}
println(result.toString())
}
// 最佳实践环节编写的启动Activity代码 多个参数可以简化
val intent = Intent(context,SecondActivity::class.java).apply{
putExtra("param1","data1")
putExtra("param2","data2")
}
context.startActivity(intent)
适用于编写工具类的功能
kotlin中弱化了静态方法,提供相似调用的单例类
class Util{
fun doAction(){
println("do1")
}
companion object{
//伴生类 kotlin中一个类只有一个伴生类 可直接调用 Util.doAction2()
fun doAction2(){
println("do2")
}
}
}
不过也是能使用静态方法的
class Util{
fun doAction(){
println("do1")
}
companion object{
@JvmStatic
//该注解只能加在单例类或者companion object 上 此时doAction2()便是真正的静态方法
fun doAction2(){
println("do2")
}
}
}
kotlin还会将顶层方法(那些没有定义在任何类中的方法)全部编译成静态方法
//创建一个后缀名为kt的文件(如 Helper.kt),在其中定义的任何方法都是顶层方法
fun doSomething(){
println("do something")
}
//这个方法可以直接调用(在kotlin中)
//Java中需要 HelperKt.doSomething()的写法调用 HelperKt是自动创建的一个Java类
本章总结:这一章大概学了两周左右 中途从学校回家,然后出去旅游了三天还有一些零零散散的事拖延了比较久好几天都没学 。这一章大概每天花4 5个小时 一周左右就能学的差不多(仅对我自己来说,大佬不需要) 然后其实里面还是有些对自己来说比较难的东西,当时其实有点觉得自己学不下去了
某乎上面说学编程一定需要有明确的目标 还要有一个时间规划,个人认为这个真的很重要!!!
以下是一些个人在学习过程中的经验或者说犯的错误
看好书上写的是什么!!!
(我在创建Layout resourse file的时候 把目录的文件名写成了first_layout,导致无法找到Layout resourse file 这里给出更直观的答案 https://jingyan.baidu.com/article/afd8f4deb9d5f034e286e9aa.html )
调用代码补全功能的时候注意选好正确得补全
错:override fun onPrepareOptionsMenu(menu: Menu?):
对:override fun onCreateOptionsMenu(menu: Menu?):
容易出现多写标点等等错误,如
//这边多写了一个>
android:theme="@style/Theme.AppCompat.Dialog">
注意看懂代码颜色 异常颜色可能需要注意
注意关键词的大小写 j 和 J 不好区分
问题:
button1.setOnClickListener{
val intent = Intent(this,SecondActivity::class.java)
startActivity(intent)
Toast.makeText(this ,"you clicked Button 1",Toast.LENGTH_LONG).show()
}
//上面和下面的写法有上面有上面不同,为什么?
button1.setOnClickListener{
Toast.makeText(this ,"you clicked Button 1",Toast.LENGTH_LONG).show()
}
button1.setOnClickListener{
val intent = Intent(this,SecondActivity::class.java)
startActivity(intent)
}
大佬懂得话,讨论区回答我一下 感谢!