Android 基础(二)四大组件之Activity的基本运用

一、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之后就进入了下一个活动

隐式调用

不明确想要启动哪一个活动,指定了一系列更为抽象的actioncategory等信息,然后交由系统去判断应该启动哪个活动。

<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是个很好的解决方法。

posted @ 2021-02-25 18:02  house_cat  阅读(278)  评论(0编辑  收藏  举报