一、Activity的基本使用
Activity是一种可以包含用户界面的组件,主要用于与用户交互。
创建
创建Activity:new->activity->empty activity
勾选Launcher Activity 表示会设为当前项目的主活动
创建时也会同时创建布局文件。基于逻辑与视图的分离,最好每个活动都能对应一个布局。布局就是用来展示画面内容的。创建布局:layout下new -> layout resource file
加载布局
setContentView(R.layout.activity_main);
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="52dp"
android:layout_marginLeft="52dp"
android:layout_marginBottom="136dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
:id 表示唯一标识符,之后可以在代码中操作这个view
这里的+id在同一个xml文件里不能重名,在不同xml文件里可以重名
+表示增加一个id,没有+号就是引用这个id
view不加id和加id的区别
https://blog.csdn.net/cyp331203/article/details/45313125
注册活动
所有活动必须在AndroidManifest.xml中注册
ide会自动帮我们注册
<activity android:name=".MainActivity"> // 活动名称
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
使用原生toast
1.上下文 2.文字 3.展示时间
Toast.makeText(MainActivity.this,"click1",Toast.LENGTH_SHORT).show();
使用menu
在res目录下新建menu的资源文件夹->创建main的资源文件
<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>
就是用来创建具体的某一个菜单项
在activity中:
重写方法
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// 第一个参数代表使用哪个资源文件
// getMenuInflater表示获得一个menuInflater对象,再调用inflate方法
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
@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();
case R.id.remove_item:
Toast.makeText(this,"remove",Toast.LENGTH_SHORT).show();
}
return super.onOptionsItemSelected(item);
}
二、活动调用活动
显式调用
Intend
是程序中各组件进行交互的一种重要方式,可以指明当前组件想要执行的动作,也可以在不同组件之间传递数据。可以用来启动活动,启动服务,以及发布广播等场景。
// 第一个参数是上下文环境 打开SecondActivity这个活动
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
start之后就进入了下一个活动
隐式调用
不明确想要启动哪一个活动,指定了一系列更为抽象的action
和category
等信息,然后交由系统去判断应该启动哪个活动。
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="activity.test.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
然后在代码中:
Intent intent = new Intent("activity.test.ACTION_START");
隐式调用可以一对多,即一个intend可以有多个活动供选择。一个动作用户可以选择不同的活动。
三、活动之间传递数据
传递简单数据
系统提供了一系列putExtra()
方法的重载,可以把想要传递的数据暂存在Intent中,启动另外一个活动时可以取出。
String data = "Hello SecondActivity";
intent.putExtra("extra_data",data);
// 取出
String data = intent.getStringExtra("extra_data");
返回数据:
startActivityForResult(intent,requestKey); // requestkey是请求码
// 返回
@Override
public void onBackPressed() {
// Intent不仅可以启动活动,也是
Intent intent = new Intent();
intent.putExtra("data_return","hello mainActivity");
setResult(RESULT_OK,intent);
finish();
}
// 接收后
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case requestKey:
if (resultCode == RESULT_OK) {
String returnData = data.getStringExtra("data_return");
Toast.makeText(MainActivity.this, returnData, Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
通过bundle
传递数据
如果要传递多组数据,可以通过bundle
的方式
封装比较简单
Bundle bundle = new Bundle();
bundle.putInt("id",1);
String data = "Hello SecondActivity";
bundle.putString("extra_data",data);
intent.putExtras(bundle);
取出
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = getIntent();
Bundle data = intent.getExtras();
Toast.makeText(this,
String.format("id=%d,data=%s",data.getInt("id"),data.getString("extra_data")),
Toast.LENGTH_SHORT).show();
}
传递一个对象
需要序列化
@Data
public class User implements Parcelable {
private int id;
private String name;
public User(int id,String name) {
this.id = id;
this.name = name;
}
public User(Parcel source) {
this.id = source.readInt();
this.name = source.readString();
}
@Override
public int describeContents() {
return 0;
}
// 写进Parcel,一定要按照顺序
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(getId());
dest.writeString(getName());
}
public static final Creator<User> CREATOR = new Creator<User>() {
// 读取
@Override
public User createFromParcel(Parcel source) {
return new User(source);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
}
// 如果没有序列化下面这行代码就会报错
intent.putExtra("user", new User(1,"name"));
// 因为写入的是Parcelable类型,所以取出也要Parcelable
User user = intent.getParcelableExtra("user");
四、活动的生命周期
深入理解生命周期的概念,可以写出更加连贯流畅的程序
返回栈
Android是使用Task管理活动,一个任务就是一组存放在栈里的活动的集合。
启动一个新活动->活动入栈
销毁一个活动 -> 栈顶弹出
活动状态
1.运行状态
处于栈顶即处于运行状态,系统最不愿意回收运行状态的活动
2.暂停状态
当一个活动不处于栈顶位置,但任然可见,活动就进入暂停状态。如对话框。同样,这种状态系统也不愿意回收
3.停止状态
不处于栈顶,完全不可见,也就进入了停止状态。系统仍然会为这种活动保存相应的状态和活动变量,但是并不是完全可靠,当其他地方需要内存时,处于停止状态的活动有可能会被系统回收。
4.销毁状态
当一个活动从返回栈移除后就变成了销毁状态,系统会倾向于回收处于这种状态的活动,从而保证手机的内存充足。
生命周期
当activity启动时系统会先调用onCreate()
,然后调用onStart()
,最后调用onResume()
方法,activity进入运行状态。
当activity被别的activity 覆盖在其上时:系统会掉用onPause()
,然后当覆盖在其上的activity会调用onCreate() -> onStart() -> onResume()
后,第一个activity会调用onStop()
方法使activity暂停。
当覆盖在其上的第二个activity关闭返回此activity时,系统会先调用第二个activity的onPause()
方法然后再调用第一个activity的onRestart() -> onStart() -> onResume()
方法,进入运行状态,此时第二个activity才调用onStop() -> onDestroy()
方法关闭。
用户退出当前activity:系统先调用onPause()
,然后调用onSotp()
,最后调用onDestroy()
方法,结束当前activity。
-
onRestart()
:表示activity正在重新启动,一般情况下是当前activity从不可见重新变成可见状态时,就会被调用,这种情况一般是用户行为导致的,如从其他页面返回当前页面时,或者用户按home键切换到桌面在重新打开app。 -
onStart()
和onStop()
:onStart()表示activity可见了,但是还没有获取焦点,无法进行交互。onStop()是和onStart()对应的当activity从可见转不可见是调用。 -
onResume()
和onPause()
:onResume()表示activity已经获取焦点了,可以进行交互了,onPause()是和onResume()方法对应的表示当前activity失去了焦点,此时可以做一些存储数据和停止动画等工作,但是不能太好时,不是会影响到新的activity的显示,因为只有onPause()执行完了,新的activity才会进入 onCreate() 等方法。 -
onDestroy()
:onDestroy()表示activity正在销毁,一般我们是在这进行资源的释放,以避免内存的泄漏。
五、活动的启动模式
https://blog.csdn.net/elisonx/article/details/80397519
六、活动的最佳实践
设置活动基类
- 知晓当前处于哪个活动
可能接手的是别人的代码,不清楚当前的页面是处于哪一个activity
- 删除所有活动,退出程序
如果有保存了所有activity的指针list,那就可以删除所有活动
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<>();
// 暂存活动
public static void addActivity(Activity activity) {
activities.add(activity);
}
// 移除活动
public static void removeActivity(Activity activity) {
activities.remove(activity);
}
// 全部销毁活动
public static void finishAll() {
for (Activity activity : activities) {
if (!activity.isFinishing()) {
activity.finish();
}
}
activities.clear();
}
}
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);
}
}
启动活动的最佳写法
如果启动活动需要一些关键的数据,之前的方法可能就是putExtra就行。但是这样可读性不好。
如果A活动要启动B活动,可以在B活动定义一个方法,把需要的数据定义好,暴露这个方法给外界。A调用这个犯法start活动B,B活动开发时也对传入的数据一清二楚
public class ThirdActivity extends AppCompatActivity {
@SuppressLint("DefaultLocale")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thrid);
Intent intent = getIntent();
Toast.makeText(this,
String.format("id=%d,name=%s",intent.getIntExtra("id",0),intent.getStringExtra("name")),
Toast.LENGTH_SHORT).show();
}
public static void actionStart(Context context,int id,String name) {
Intent intent = new Intent(context, ThirdActivity.class);
intent.putExtra("id",id); // 即需要id和name
intent.putExtra("name",name);
context.startActivity(intent);
}
}
// 启动活动时很简单
private void handleClick() {
Button button2 = (Button) findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ThirdActivity.actionStart(SecondActivity.this,1,"name");
}
});
}
这样写避免了重复代码,如果说B会被很多个活动启动,把传入数据的相关代码下行到B是个很好的解决方法。