〇、前情提要
第一行代码Android第二章内容。
参考:
- 思维导图
https://www.zhihu.com/question/27596017/answer/37634740 - 【Android Studio】第一行代码-第2章 探究活动(下)
一、概要
目录
思维导图
二、活动是什么
活动( Activity )是最容易吸引用户的地方,它是一种可以包含用户界面的组件,主要用于和用户进行交互。
一个应用程序中可以包含零个或多个活动,但不包含任何活动的应用程序很少见,谁也不想让自己的应用永远无法被用户看到吧?
三、活动的基本用法
0.Add No Activity
关闭当前项目file-close project
No Activity
1.手动创建活动
☆改成project模式,每次都需要
创建活动
该目录为空
创建empty Activity
FirstActivity,后两个不勾选
- Generate Layout File
自动为FirstActivity创建一个 对应的布局文件 - Launcher Activity
自动将FirstActivity 设置为当前项目的主活动
任何活动都要重写onCreate方法
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
直接调用父类方法
2. 创建和加载布局
每个活动对应一个布局,布局显示界面内容
res new 一个叫layout的directory
layout下new一个叫first_layout的Layout resource file
布局编辑器
模式切换
- design
可视化布局编辑器 - code
xml文件编辑布局 - split
两者皆有
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
已有一个LinearLayout元素,在创建时的根元素。
添加button元素
<Button
android:id="@+id/button_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button_1" />
- android:id
标识符
xml中比引用资源多+ 因为是在创建 - android:layout_width
宽
match_parent和父元素一样宽 - android:layout_height
高
wrap_content刚好包括里面内容 - android:text
元素中的文字
在活动中加载布局
调用setContentView方法
R.layout.first_layout可得到first_layout.xml的布局id
setContentView(R.layout.first_layout);
3.在AndroidManifest文件中注册
自动注册
防止崩溃
<activity android:name=".FirstActivity">
android:name=".FirstActivity"
.FirstActivity是com.example.activitytest.FirstActivity缩写
package="com.example.activitytest"已声明编程序包名
配置主活动
<activity android:name=".FirstActivity"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
android:label 标题栏内容,启动器应用程序显示的名称
运行
可以看到button
4.在活动中使用Toast
Toast是Android系统提供的一种非常好的提醒方式,在程序中可以使用它将一些短小的信息通知给用户,这些信息会在一段时间后自动消失,并且不会占用任何屏幕空间,我们现在就尝试一下如何在活动中使用Toast。
定义一个触发点
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
Button button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(FirstActivity.this, "You clicked Button_1",
Toast.LENGTH_SHORT).show();
}
});
}
}
- findViewById
找到元素R.id.button_1,在android:id="@+id/button_1"
返回一个View对象 需要转换成Button - setOnClickListener
设置成一个监听器 点击执行onClick - makeText
创建Toast对象
1.contest 上下文
2.test 文本内容
3.显示时长 Toast.LENGTH_SHORT Toast.LENGTH_LONG
点击
5.在活动中使用Menu
让菜单都能得到展示的同时,还能不占用任何屏幕空间。
res下建文件夹menu,menu下建菜单文件main
main.xml
<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>
- <item>
创建具体一个标签 - android:id
指定唯一的标识符 - android:title
指定名称
重写onCreateOptionsMenu
mac:control+O
FirstActicity.java
public class FirstActivity extends AppCompatActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
- getMenuInflater
得到MenuInflater对象 - inflate
给当前活动创建菜单
传入R.menu.main添加到menu对象中 - onCreateOptionsMenu
true可显示
菜单响应事件
FirstActicity.java
重写onOptionsItemSelected
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.add_item:
Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
演示
菜单栏
6.销毁一个活动
按back键
代码
Activity类finish
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
运行点击按钮就销毁
四、使用Internet在活动间穿梭
0.创建一个新活动
创建新活动SecondActivity
Empty Activity | second_layout
自动生成如下文件
second_layout
second_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<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_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button_2"
/>
</LinearLayout>
SecondActivity.java内容保持不变
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
}
}
AndroidMainfest.xml中自动注册
<activity android:name=".SecondActivity">
非主活动,不用配置<intent-filter>
Intent
是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。
Intent 一般可被用于启动活动、启动服务以及发送广播等场景。
1.使用显式Intent
点击启动活动
FirstActivity.java
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}
});
- Intent (Context packageContext, Class<?>cls)
- Context
要求提供一个启动活动的上下文 - Class
指定想要启动的目标活动 - startActivity()
专门用于启动活动的 它接收一个Intent 参数
演示
点击button_1进入SecondActivity
销毁
2.使用隐式Intent
并不明确指出我们想要启动哪一个活 动,而是指定了一系列更为抽象的action 和category 等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动。
AndroidMainfest.xml
在下配置内容指定action和category
// SecondActivity
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
FirstActivity.java
public void onClick(View v) {
// 隐式
Intent intent = new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);
}
- com.example.activitytest.ACTION_START
传进action字符串 - android.intent.category.DEFAULT
默认category 调用startActivity自动添加到Intent
一个Intent只能指定一个action,能指定多个category
FirstActivity.java
Intent intent = new Intent("com.example.activitytest.ACTION_START");
// 4.添加多个category
intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);
AndroidMainfest.xml
<activity 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" />
</intent-filter>
</activity>
也能达到跳转到活动二的界面
3.更多隐式Intent的用法
不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如说你的应用程序中需要展示一个网页,这时你没有必要自己去实现一个浏览器( 事实上也不太可能),而是只需要调用系统的浏览器来打开这个网页就行了。
FirstActivity.java
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
}
实现
☆uri不是url
- Intent.ACTION_VIEW
Intent 的action
常量值为android.intent.action.VIEW - Uri.parse()
将一个网址字符串解析成一个Uri对象 - setData()
将这个Uri对象传递进去
用于指定当前Intent正在操作的数据 以字符串的形式传人
<intent-filter>标签中再配置一个<data>标签
更精确地指定当前活动能够响应什么类型的数据。
- android:scheme
用于指定数据的协议部分,如上例中的http部分。 - android:host
用于指定数据的主机名部分,如上例中的www.baidu.com部分。 - android:port
用于指定数据的端口部分,一般紧随在主机名之后。 - android:path
用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。 - android:mimeType
用于指定可以处理的数据类型,允许使用通配符的方式进行指定。
只有标签中指定的内容和Intent 中携带的Data完全一致时, 当前活动才能够响应该
Intent。
不过一般在标签中都不会指定过多的内容,如上面浏览器示例中,其实只需要指定android:scheme为http,就可以响应所有的http协议的Intent 了。
创建活动三 响应打开网页的Intent
third_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<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_3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button_3" />
</LinearLayout>
ThirdActivity.java不变
AndroidMainfest.xml
<activity android:name=".ThirdActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
</intent-filter>
</activity>
有报错可忽略
选第一项跳转到活动三界面
选第二项跳转到网页
☆在真正项目中尽量不要出现这种有可能误导用户的行为
调用系统拨号界面
- geo表示地理位置
- tel表示拨打电话
FirstActivity.java
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
AndroidMainfest.xml
<activity android:name=".ThirdActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
</activity>
4.向下一个活动传递数据
使用Intent 来启动一个活动,其实Intent还可以在启动活动的时候传递数据。
Intent 中提供了一系列putExtra()方法的重载, 可以把我们想要传递的数据暂存在Intent 中,启动了另一个活动后,只需要把这些数据再从Intent中取出就可以了。
字符串传递
ex:如果FirstActivity 中有一个字符串,现在想把这个字符串传递到SecondActivity中
FirstActivity.java
// 8.传递字符串
String data = "Hello SecondActivity";
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("extra_data",data);
startActivity(intent);
显式intent
- putExtra()
name 键
第二个参数为要传递的数据
SecondActivity.java
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d("SecondActivity",data);
}
}
- getIntent()
获取用到启动SecondActivity的Intent - getStringExtra()/getIntExtra/getBooleanExtra
传入相应键值 获取传递的数据
演示
运行后提示Hello SecondActivity
5.返回数据给上一个活动
返回上一个活动只需要按一下Back键就可以了,并没有一个用于启动活动Intent来传递数据。
startActivityForResult()方法
这个方法期望在活动销毁的时候能够返回一个结果给上一个活动。
第一个参数还是Intent
第二个参数是请求码,用于在之后的回调中判断数据的来源。
- 修改FirstActivity中按钮的点击事件
@Override
protected void onCreate(Bundle savedInstanceState) {
……
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivityForResult(intent, 1);
}
});
}
启动SecondActivity,请求码只要是一个唯一值就可以了,这里传入了1。
- 在SecondActivity 中给按钮注册点击事件,并在点击事件中添加返回数据的逻辑
public class SecondActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
Button button2 = (Button) findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RESULT_OK, intent);
finish();
}
});
}
}
构建了一个用于传递数据的Intent,把要传递的数据存放在Intent中。然后调用了setResult()方法,是专门用于向上一个活动返回数据的。
setResult()方法
第一个参数用于向上一个活动返回处理结果,一般只使用RESULT_0K 或RESULT__CANCELED这两个值
第二个参数则把带有数据的Intent传递回去,然后调用了finish()方法来销毁当前活
动。
由于我们是使用startActivityForResult()方法来启动SecondActivity的,在SecondActivity
被销毁之后会回调上一个活动的onActivityResult()方法。
在FirstActivity中重写这个方法来得到返回的数据
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String returnedData = data.getStringExtra("data_return");
Log.d("FirstActivity", returnedData);
}
break;
default:
}
}
onActivityResult()方法
第一个参数requestCode,即我们在启动活动时传人的请求码。
第二个参数resultCode, 即我们在返回数据时传人的处理结果。
第三个参数data,即携带着返回数据的Intent。
由于在一个活动中有可能调用startActivityForResult()方法去启动很多不同的活动,每一个活动返回的数据都会回调到onActivityResult()这个方法中,因此我们首先要做的就是通过检查requestCode的值来判断数据来源。
确定数据是从SecondActivity返回的之后,我们再通过resultCode的值来判断处理结果是否成功。最后从data中取值并打印出来,这样就完成了向上一个活动返回数据的工作。
运行
重新运行程序,在FirstActivity的界面点击按钮会打开SecondActivity ,然后在SecondActivity
界面点击Button 2按钮会回到FirstActivity,这时查看logcat 的打印信息。
可以看到,SecondActivity 已经成功返回数据给FirstActivity了。
onBackPressed()方法
如果用户在SecondActivity中并不是通过点击按钮,而是通过按下Back键回到FirstActivity,可以通过在SecondActivity中重写onBackPressed()方法来解决这个问题
@Override
public void onBackPressed() {
Intent intent = new Intent() ;
intent . putExtra("data_ return", "Hello FirstActivity");
setResult (RESULT_ _0K, intent) ;
finish();
}
这样的话,当用户按下Back键,就会去执行onBackPressed()方法中的代码,我们在这里
添加返回数据的逻辑就行了。