文章目录
参考章节
2.1 创建基本活动
- 你可能会对@+id/button_1这种语法感到陌生,但如果把加号去掉,变成@id/button_1,这样你就会觉得有些熟悉了吧,这不就是在XML中引用资源的语法吗?只不过是把string替换成了id。是的,如果你需要在XML中引用一个id,就使用@id/id_name这种语法,而如果你需要在XML中定义一个id,则要使用@+id/id_name这种语法。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest2">
<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/Theme.ActivityTest2">
<activity
android:name=".FirstActivity"
android:exported="true">
<!--配置主活动,其中xml语法 (<p/>) == (<p>...</p>) -->
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
- Toast的用法非常简单,通过静态方法makeText()创建出一个Toast对象,然后调用show()将Toast显示出来就可以了。这里需要注意的是,makeText()方法需要传入3个参数。第一个参数是Context,也就是Toast要求的上下文,由于活动本身就是一个Context对象,因此这里直接传入FirstActivity.this即可。第二个参数是Toast显示的文本内容,第三个参数是Toast显示的时长,有两个内置常量可以选择Toast.LENGTH_SHORT和Toast.LENGTH_LONG。
package com.example.activitytest2;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.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.buttom_1); // 通过id获取按钮,返回一个View对象,转换成Button对象
// button1.setOnClickListener(v -> Toast.makeText(FirstActivity.this, "You clicked Button_1",
// Toast.LENGTH_LONG).show());
button1.setOnClickListener(new View.OnClickListener(){ // 接口可以直接实现,也可以转化成lambda
@Override
public void onClick(View v) {
Toast.makeText(FirstActivity.this, "You clicked Button_1",
Toast.LENGTH_LONG).show();
// finish(); // 销毁
}
});
}
}
- inflate()方法接收两个参数,第一个参数用于指定我们通过哪一个资源文件来创建菜单,这里当然传入R.menu.main。第二个参数用于指定我们的菜单项将添加到哪一个Menu对象当中,这里直接使用onCreateOptionsMenu()方法中传入的menu参数。然后给这个方法返回true,表示允许创建的菜单显示出来,如果返回了false,创建的菜单将无法显示。
@Override
public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
getMenuInflater().inflate(R.menu.main, menu); // 创建一个MenuInflater对象,调用inflater方法给当前活动创建菜单
return super.onCreatePanelMenu(featureId, menu);
}
/**
* This hook is called whenever an item in your options menu is selected.
* The default implementation simply returns false to have the normal
* processing happen (calling the item's Runnable or sending a message to
* its Handler as appropriate). You can use this method for any items
* for which you would like to do processing without those other
* facilities.
*
* <p>Derived classes should call through to the base class for it to
* perform the default menu handling.</p>
*
* @param item The menu item that was selected.
* @return boolean Return false to allow normal menu processing to
* proceed, true to consume it here.
* @see #onCreateOptionsMenu
*/
@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;
}
2.2 使用Intent在活动之间跳转
2.2.1使用显示和隐式Intent
- 其中一个是Intent(Context packageContext, Class<? >cls)。这个构造函数接收两个参数,第一个参数Context要求提供一个启动活动的上下文,第二个参数Class则是指定想要启动的目标活动,通过这个构造函数就可以构建出Intent的“意图”。然后我们应该怎么使用这个Intent呢?Activity类中提供了一个startActivity()方法,这个方法是专门用于启动活动的,它接收一个Intent参数,这里我们将构建好的Intent传入startActivity()方法就可以启动目标活动了。
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.buttom_1); // 通过id获取按钮,返回一个View对象,转换成Button对象
// button1.setOnClickListener(v -> Toast.makeText(FirstActivity.this, "You clicked Button_1",
// Toast.LENGTH_LONG).show());
button1.setOnClickListener(new View.OnClickListener(){ // 接口可以直接实现,也可以转化成lambda
@Override
public void onClick(View v) {
// Toast.makeText(FirstActivity.this, "You clicked Button_1",
// Toast.LENGTH_LONG).show();
// finish(); // 销毁
// 构建一个Intent对象,传入上下文和目标活动
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
// 执行Intent
startActivity(intent);
}
});
}
- ,隐式Intent则含蓄了许多,它并不明确指出我们想要启动哪一个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动。
<activity
android:name=".SecondActivity"
android:exported="true" >
<intent-filter>
<!-- 指定响应的action-->
<action android:name="com.example.activitytest2.ACTION_START"/>
<!-- 指定响应的category-->
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="com.example.activitytest2.MY_CATEGORY"/>
</intent-filter>
</activity>
// 构建一个Intent对象,传入上下文和目标活动
Intent intent = new Intent("com.example.activitytest2.ACTION_START");
intent.addCategory("com.example.activitytest2.MY_CATEGORY");
// 执行Intent
startActivity(intent);
2.2.2隐式Intent的更多用法
- 使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如说你的应用程序中需要展示一个网页,这时你没有必要自己去实现一个浏览器(事实上也不太可能),而是只需要调用系统的浏览器来打开这个网页就行了。
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.buttom_1); // 通过id获取按钮,返回一个View对象,转换成Button对象
// button1.setOnClickListener(v -> Toast.makeText(FirstActivity.this, "You clicked Button_1",
// Toast.LENGTH_LONG).show());
button1.setOnClickListener(new View.OnClickListener(){ // 接口可以直接实现,也可以转化成lambda
@Override
public void onClick(View v) {
// Toast.makeText(FirstActivity.this, "You clicked Button_1",
// Toast.LENGTH_LONG).show();
// finish(); // 销毁
// 构建一个Intent对象,传入上下文和目标活动
// Intent intent = new Intent("com.example.activitytest2.ACTION_START");
// intent.addCategory("com.example.activitytest2.MY_CATEGORY");
// // 执行Intent
// startActivity(intent);
// 构建一个浏览器Intent,并设置url
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
// 执行Intent
startActivity(intent);
}
});
}
- 这里我们首先指定了Intent的action是Intent.ACTION_VIEW,这是一个Android系统内置的动作,其常量值为android.intent.action.VIEW。然后通过Uri.parse()方法,将一个网址字符串解析成一个Uri对象,再调用Intent的setData()方法将这个Uri对象传递进去。
2.2.3活动间传递数据
- 比较常用的就是Activity (Service)之间的数据传递。举个简单例子,在当前Activity1使用startActvity(intent)或者startActivityForResult(intent, code)方法跳转到另一个Activity2之前,如果要传递某些String类型数据给Activity2,则会执行intent.putExtra(String str, String Key),将String数据打包到Intent中,并给它一个Key标识。在Activity2当中,getIntent()方法获得这个intent,然后再getStringExtra(Key),就可以获得你之前打包的那个数据了。
// 传递字符串给SecondActivity
String data = "Hello SecondActivity";
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("extra data", data); //传入数据
startActivity(intent);
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = getIntent(); // 通过getIntent()方法获取到用于启动SecondActivity的Intent
//然后调用getStringExtra()方法,传入相应的键值,就可以得到传递的数据了
String data = intent.getStringExtra("extra data");
Log.d("SecondActivity", data);
}
}
2.3活动的生命周期及启动模式
2.3.1 四种生命周期
- 运行–>处于栈顶
- 暂停–>不处于栈顶–>任然可见
- 停止–>不处于栈顶–>完全不可见–>会保留状态和成员变量–>内存吃紧时会被回收
- 销毁–>从返回栈中删除–>系统最先回收这部分内存
2.3.2七个函数启动模式
- onCreate( )–>创建的时候执行
- onStart( )–>由不可见变为可见时执行
- onResume( )–>准备好和用户交互的时候执行–>位于返回栈栈顶,处于运行状态
- onPause( )–>系统准备启动或者恢复另一个活动时执行–>释放掉一些cpu资源
- onStop( )–>当活动完全不可见时执行–>到停止状态前执行
- onDestory( )–>销毁状态前执行
- onRestart( )–>由停止状态变成运行状态时执行–>重新启动
2.3.3 三种活动生存期
- 完整生存期。活动在onCreate()方法和onDestroy()方法之间所经历的,就是完整生存期
- 可见生存期。活动在onStart()方法和onStop()方法之间所经历的,就是可见生存期。
- 前台生存期。活动在onResume()方法和onPause()方法之间所经历的就是前台生存期。–>这段时间可以和用户交互
2.4活动实践开发技巧
2.4.1知晓当前是哪一个活动
- 创建一个BaseActivity
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity", getClass().getSimpleName());
}
}
- 需要让BaseActivity成为ActivityTest项目中所有活动的父类。修改First-Activity、SecondActivity和ThirdActivity的继承结构,让它们不再继承自AppCompatActivity,而是继承自BaseActivity。
2.4.2随时随地退出程序
- 在活动管理器中,我们通过一个List来暂存活动,然后提供了一个addActivity()方法用于向List中添加一个活动,提供了一个removeActivity()方法用于从List中移除活动,最后提供了一个finishAll()方法用于将List中存储的活动全部销毁掉。
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity", getClass().getSimpleName());
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
//killProcess()方法用于杀掉一个进程,它接收一个进程id参数,
// 我们可以通过myPid()方法来获得当前程序的进程id。需要注意的是,
// killProcess()方法只能用于杀掉当前程序的进程,我们不能使用这个方法去杀掉其他程序。
android.os.Process.killProcess(android.os.Process.myPid());
}
}
- 在BaseActivity的onCreate()方法中调用了ActivityCollector的addActivity()方法,表明将当前正在创建的活动添加到活动管理器里。然后在BaseActivity中重写onDestroy()方法,并调用了ActivityCollector的removeActivity()方法,表明将一个马上要销毁的活动从活动管理器里移除。从此以后,不管你想在什么地方退出程序,只需要调用ActivityCollector.finishAll()方法就可以了。例如在ThirdActivity界面想通过点击按钮直接退出程序,只需将代码改成如下所示
public class SecondActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Button button2 = (Button) findViewById(R.id.buttom_2); // 通过id获取按钮,返回一个View对象,转换成Button对象
button2.setOnClickListener(new View.OnClickListener(){ // 接口可以直接实现,也可以转化成lambda
@Override
public void onClick(View v) {
// 结束所有活动,退出程序
ActivityCollector.finishAll();
}
});
}
}
2.4.3启动活动的最佳写法
- 启动活动的方法相信你已经非常熟悉了,首先通过Intent构建出当前的“意图”,然后调用startActivity()或startActivityForResult()方法将活动启动起来,如果有数据需要从一个活动传递到另一个活动,也可以借助Intent来完成。
- 我们在SecondActivity中添加了一个actionStart()方法,在这个方法中完成了Intent的构建,另外所有SecondActivity中需要的数据都是通过actionStart()方法的参数传递过来的,然后把它们存储到Intent中,最后调用startActivity()方法启动SecondActivity。这样写的好处在哪里呢?最重要的一点就是一目了然,SecondActivity所需要的数据在方法参数中全部体现出来了,这样即使不用阅读SecondActivity中的代码,不去询问负责编写SecondActivity的同事,你也可以非常清晰地知道启动SecondActivity需要传递哪些数据。另外,这样写还简化了启动活动的代码,现在只需要一行代码就可以启动SecondActivity,如下所示:
public class SecondActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = getIntent(); // 通过getIntent()方法获取到用于启动SecondActivity的Intent
//然后调用getStringExtra()方法,传入相应的键值,就可以得到传递的数据了
String data1 = intent.getStringExtra("param1");
String data2 = intent.getStringExtra("param2");
Log.d("SecondActivity", data1);
Log.d("SecondActivity", data2);
Button button2 = (Button) findViewById(R.id.buttom_2); // 通过id获取按钮,返回一个View对象,转换成Button对象
button2.setOnClickListener(new View.OnClickListener(){ // 接口可以直接实现,也可以转化成lambda
@Override
public void onClick(View v) {
// 结束所有活动,退出程序
ActivityCollector.finishAll();
}
});
}
// 封装信息传递和启动Intent方法
public static void actionStart(Context context, String data1, String data2) {
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra("param1", data1);
intent.putExtra("param2", data2);
context.startActivity(intent);
}
}
在FirstActivity的onClick( )中直接调用SecondActivity.actionStart()
// 直接调用SecondActivity.actionStart()
SecondActivity.actionStart(FirstActivity.this, "data1", "data2");