Activity

Android中,界面对应Activity,相当于桌面客户端中的一个窗口,使用时直接继承Activity类,界面控件的响应逻辑都写在Activity中。使用Activity需要在清单文件中定义。

<manifest ... >
  <application ... >
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest >

Activity生命周期

Activity提供了一系列生命周期回调函数,也可以叫做生命周期钩子函数。总之,当Activity进入某一生命周期状态时,就会回调对应的函数。

onCreate()

系统第一次创建这个Activity时回调,一般重写这个方法里完成Activity的初始化,如setContentView()等,这个函数回调完后会回调onStart()。

onStart()

界面显示前的一些操作。

onResume()

这个Activity在窗口栈顶,获得用户焦点。也就是说,这个Activity正在和用户进行交互。

onPause()

界面失去焦点,如用户点击返回键,就会回调onPause()。你应该在这个函数里编写保存用户状态的操作,紧接着会回调onStop()或onRestart()。

onStop()

界面完全不可见,紧接着会回调onDestroy()或onRestart()。

onRestart()

stop状态的界面恢复时回调,紧接着调用onStart()。

onDestroy()

Activity最终的销毁步骤。

看这张图比较好理解:

常见生命周期循环

我们在每个声明周期钩子函数中,编写一条向控制台输出的语句,就能很容易的观察Activity的生命周期:

Activity启动

点击home键

从后台恢复

点击back键

activity1切换到activity2

使用back键从activity2退回activity1

窗口栈

和桌面应用一样,Android中也是使用窗口栈管理activity的。

manifest中定义activity窗口栈启动模式(launch mode)

  • standard 默认模式,调用一次就会创建一个activity对象放到窗口栈中。
  • singleTop 如果被调用的activity已经在栈顶,不会再次创建。
  • singleTask activity是单例的,调用时如果不存在就创建,如果存在就把它放在栈顶(该Activity之上的Activity全部弹出)。
  • singleInstance 基本同上,但创建的activity位于一个新的窗口栈,很少使用。

这四种启动模式文字描述起来可能不太直观,实际上用两个Activity试一试就能完全理解了。

Activity之间数据传递

我们知道可以使用显式意图对象启动新的Activity,意图对象中可以封装一些数据用于Activity之间的数据传递。activity之间可以使用extra传递键值对,也可以使用bundle传递基本类型或是实现Serializable或Parcelable接口的复合对象。

使用bundle传递对象示例:

Intent intent = new Intent();
Bundle bundle = new Bundle();
User user = new User("user");
bundle.putSerializable("user", user);
intent.putExtras(bundle);
intent.setClass(this, Main2Activity.class);
startActivity(intent);

接收bundle传递的对象:

Bundle bundle = getIntent().getExtras();
User user = (User)bundle.get("user");

Parcelable和Serializable

JavaSE提供了序列化对象的Serializable接口,Android额外提供了Parcelable接口,Parcelable在Android中使用更加高效,建议使用。

实现Parcelabel接口的实体类:

public class Student implements Parcelable
{
    private String name;
    private int age;

    public Student()
    {
    }

    protected Student(Parcel in)
    {
        name = in.readString();
        age = in.readInt();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags)
    {
        dest.writeString(name);
        dest.writeInt(age);
    }

    @Override
    public int describeContents()
    {
        return 0;
    }

    public static final Creator<Student> CREATOR = new Creator<Student>()
    {
        @Override
        public Student createFromParcel(Parcel in)
        {
            return new Student(in);
        }

        @Override
        public Student[] newArray(int size)
        {
            return new Student[size];
        }
    };

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }
}

实际上如果只包含基本类型,直接在AndroidStudio中使用alt+Enter快捷键就能生成正确的Parcelable接口实现代码。如果包含Date等复杂类型,则要考虑手动编写序列化和反序列化中的类型转换。

两种序列化的区别

Parcelable的序列化是手动实现的,速度比Serializable快很多。但传递数据量较少时,使用Serializable也不会感到明显卡顿。

被启动的Activity向源Activity回传数据

窗口回传数据这个需求也是比较常见的。

源Activity发送数据:

Intent intent  = new Intent(this, ChatActivity.class);
intent.putExtra("username", username);
LoginActivity.this.startActivityForResult(intent, 1);

目的Activity接收数据:

username = getIntent().getStringExtra("username");

目的Activity在返回键按下时回传数据:

@Override
public void onBackPressed()
{
  Intent intent = new Intent(this, LoginActivity.class);
  intent.putExtra("username", username + "111");
  this.setResult(1, intent);
  this.finish();
}

源Activity接收回传的数据:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
  Toast.makeText(LoginActivity.this, data.getStringExtra("username"), Toast.LENGTH_SHORT).show();
}

接收回传数据需要重写onActivityResult()方法。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。