Android Activity 基础详解

活动(Activity)是一种可以包含用户界面的组件,主要用和用户进行交互。一个应用程序中可以包含零个或多个活动。



1.活动的基本用法

首先我们创建一个工程。命名为TestActivity。


然后一直点击下一步会到以下界面。


因为这个时候系统默认想要为我们创建一个命名为MainActivity的活动,并加载了布局activity_main.xml。我们不去更改它,建立完成之后进去看它的代码,我们就知道怎么回事了。(下面的代码为了让读者看到路径更好的理解活动,我将会放出图片)


这就是一个活动的代码部分,首先新建一个活动类并让其继承Activity,然后在其中重写onCreate()方法进行初始化,最后通过setContentView()来加载一个布局。


这就是我们所加载的布局,布局通常放在res下的layout文件包下。


当然,作为安卓的四大组件,活动想要正常使用自然是需要在AndroidManifest.xml中注册(11-17行代码)的。如果想要在程序启动时候首先跳转到该活动,就需要写入图中12-16行代码的声明。

然后是几个知识点:

A)隐藏标题栏,只需要在加载布局之前,写入requestWindowFeature(WINDOW.FEATRUE_NO_TITLE)即可。

B)Toast提醒方式,在程序中使用它可以将一些短小的信息提示给用户,这些信息存在一段时间后会自动消失。写入Toast.makeText(Context, " ", Toast.LENGTH_SHORT).show即可。这个方法实际上传入的是三个参数:第一个是上下文Context;第二个是想要显示的文本内容;第三个是显示的时间长,内置的常量除了我们写出的Toast.LENGTH_SHORT还有Toast.LENGTH_LONG。然后调用show()就可以将Toast显示在屏幕上了。

C)菜单的使用,由于手机使用情况跟电脑不同,它只有很小的一个屏幕,而且很有可能由于某种需求,我们的活动上必须显示大量的菜单列表,这时候为了避免占用屏幕我们可以采用菜单方式来实现。由于在编写软件的过程中我们可能涉及到大量的菜单,因此我们可以新建一个文件夹专门用来放菜单(就像布局那样)。所以在res下新建一个menu文件夹,然后在里面创建我们的第一个菜单布局。如下图所示:


然后我们需要在活动中去实现如下代码:

package company.testactivity;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.add_item:
                Toast.makeText(MainActivity.this, "Add Selected", Toast.LENGTH_SHORT).show();
                break;
            case R.id.remove_item:
                Toast.makeText(MainActivity.this, "Remove Selected", Toast.LENGTH_LONG).show();
                break;
            default:
        }
        return true;
    }
}

首先通过重写构造方法onCreateOptionMenu()来创建菜单,通过getMenuInflater得到MenuInflater对象,在调用它的inflate方法就可以给当前活动创建菜单了。紧接着,我们为菜单定义一个点击事件,表示我们这个菜单不是“只可远观不可亵玩”的,同时应用了刚才所提到的Toast方法。


D)销毁一个活动。想要通过代码销毁一个活动时,只需要写入finish()方法即可。



2.Intent在活动中的使用

Intent为意图的意思,这很形象的描述了它的作用,而它主要分为显式和隐式两种。

我们先来看显式Intent。

首先新建一个活动,并加载一个布局,前面已经讲述过方法了,记得注册就好,不再赘述。重点来看主活动中的代码:

package company.testactivity;

    import android.content.Intent;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;

    public class MainActivity extends AppCompatActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            Button mButton = (Button) findViewById(R.id.explicit_intent);
            mButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    String data = "this is a extra information from MainActivity";
                    Intent explicitIntent = new Intent(MainActivity.this, AnotherActivity.class);
                    explicitIntent.putExtra("extra data", data);
                    startActivity(explicitIntent);
                }
            });
        }
    .
    .
    .    
    }

我们增添了一个按钮,然后为其设置了一个点击事件。在点击逻辑中写入了Intent相关的东西。首先new一个explicitIntent实例,里面传入两个参数:当前活动和目标活动。通过startActivity(explicitIntent)方法即可实现由一个活动跳转到另一个活动的操作。只不过我们这里一并演示了跳转过程中携带信息,这是Intent很重要的一个功能。通过putExtra()方法来实现,传入两个参数:信息的名称和信息的内容。

package company.testactivity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;

/**
 * Created by samyang on 2016/9/12.
 */
public class AnotherActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.another_activity);
        Intent intent = getIntent();
        String data = intent.getStringExtra("extra data");
        Toast.makeText(AnotherActivity.this, data, Toast.LENGTH_LONG).show();
    }
}

然而目标活动想要接收传过来的信息需要调用getIntent()方法来获取从第一个活动传过来的意图实例,然后利用该实例调用getStringExtra()方法并传入信息名称来拿到信息,这里我们还是通过Toast作一个简单的演示。


这里简单提一下,布局都很简单,左边是放了一个TextView,下面放了一个Button;右边仅放了一个TextView。代码就不放出来了,接下来的简单部分亦是。

接下来看隐式Intent

隐式Intent并不直接指定想要跳转的活动,而是指定一系列更为抽象的<action>及<category>信息,然后交给系统去分析这个intent从而判断想要启动的活动。我在在<action>标签中指定活动可以响应的action,而<category>则包含了一些附加信息,用于更精确的匹配响应。只有<action>及<category>能够同时匹配Intent中指定的action及category时这个活动才能响应Intent。核心代码为:

<activity android:name=".ThirdActivity">
    <intent-filter>
        <action android:name="company.testactivity.ACTION_START"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.MY_CATEGORY"/>
    </intent-filter>
</activity>

Button maButton = (Button) findViewById(R.id.implicit_intent);
maButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent implicitIntent = new Intent("company.testactivity.ACTION_START");
        implicitIntent.addCategory("android.intent.category.MY_CATEGORY");
        startActivity(implicitIntent);
    }
});
点击新加入的按钮之后跳转到ThirdActivity如下图所示:


除此之外,隐式的Intent还有更多用处。例如:可以启动其它程序的活动,这使得Android中的多个软件共享成为了可能。

返回数据

在演示显式Intent的时候我们使用到了将数据传送给下一个活动,那么自然还有将数据返回给上一个活动这一操作。此时你查阅文档可以知道,返回上一个活动按一下back即可,但是并没有用于启动活动Intent来传递数据的,不过Activity提供了一个startActivityForResult()方法,以实现我们并且它期望在活动销毁时返回一个数据给上一个活动,那么用它肯定可想要的操作。
更改explicitButton按钮的点击逻辑如下:
Button mButton = (Button) findViewById(R.id.explicit_intent);
mButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        String data = "this is a extra information from MainActivity";
        Intent explicitIntent = new Intent(MainActivity.this, AnotherActivity.class);
        explicitIntent.putExtra("extra data", data);
        startActivityForResult(explicitIntent, 1);
    }
});
startActivityForResult()方法接收两个参数:第一个还是Intent;第二个是请求码,用于在之后的回调判断数据的来源。
在跳转的活动中添加一个按钮,其中逻辑如下:
Button backButton = (Button) findViewById(R.id.back_button);
backButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent1 = new Intent();
        intent1.putExtra("data return", "Hello MainActivity");
        setResult(RESULT_OK, intent1);
        finish();
    }
});
这里又构建了一个Intent,但它没有任何“意图”,仅仅用来存放要返回的数据。然后 调用了setResult()方法,该方法很重要,专门用于向上一个活动返回数据。其中传入两个参数:第一个是活动返回处理结果,一般只传RESULT_OK或RESULT_CANCELED;第二个就是带有要返回数据的Intent对象。然后调用finish()销毁当前活动。
在MainActivity中重写onActivityResult构造方法如下:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case 1:
            if (resultCode == RESULT_OK){
                String returnedData = data.getStringExtra("data return");
                Toast.makeText(MainActivity.this, returnedData, Toast.LENGTH_SHORT).show();
            }
            break;
        default:
    }
}
返回到了上一个活动之后, 想要接收返回的数据必须要重写onActivityResult构造方法,它带有三个参数:第一个为requestCode即我们在启动活动时传入的请求码;第二个为resultCode即返回数据时传入的处理结果;第三个为data即携带着返回数据的intent。因此我们首先需要通过requestCode判断数据来源,然后通过resultCode判断处理结果是否成功,最后拿出数据
当然,我们这里采用的是按钮点击事件调用finish()方法销毁的活动。我们一样可以吧这段点击逻辑放在onBackPressed()方法中,这样通过back键就可以达到相同的效果了。


3.活动的生命周期

实际上Android是通过任务(task)来管理活动的,一个任务就是一组存放在栈里的活动集合,这个栈也被称为 返回栈(Back Stack),栈是一种先进后出的数据结构,采用下图来帮助理解:


而关于活动的生命周期,我们需要知道,每个活动在其生命周期内最多可能会有四种状态:

a)运行状态:当一个活动处于返回栈的栈顶时,就处于运行状态,这种状态的活动是系统最不愿意回收,因为这会带来极差的用户体验。

b)暂停状态:当一个活动不再处于栈顶但仍然可见时就会进入这种状态。处于暂停状态的活动仍然是完全存活的,系统也不愿意回收这样的活动,只有在内存极低的时候才会考虑去回收这样的活动。

c)停止状态:当一个活动不再处于栈顶位置,并且完全不可见,就进入了停止状态。此时系统仍然为这种活动保留了成员变量,但是当其他地方需要更多内存时就会回收这种活动,所以这种状态下保存的数据并不可靠。

d)销毁状态:当一个活动从返回栈中移除了之后就变成这种状态,系统最愿意回收这种状态的活动。

而生命周期的七种回调方法在理解上述四种状态之后再结合下图就可以很好的理解了。


另外你还需要知道对于活动的一种划分方式,除了onRestart()方法外,其他六种方法是两两对应并可划分如下:
a)完整生存期:活动在onCreate()方法和onDestory()方法之间所经历的,一般情况下,一个活动会在onCreate()时完成各种初始化操作,在onDestory()时释放内存。
b)可见生存期:活动在onStart()方法和onStop()方法之间所经历的,在可见生存 期内,活动对于用户总是可见的,即便有可能无法和用户进行交互。我们可以通过这两个方法,合理地管理那些对用户可见的资源。比如在 onStart()方法中对资源进行加载,而在onStop()方法中对资源进行释放,从而保证处于停止状态的活动不会占用过多内存。
c)前台生存期:活动在 onResume()方法和 onPause()方法之间所经历的,在前台生存期内,活动总是处于运行状态的,此时的活动是可以和用户进行交互的,我们平时看到和接触最多的也这个状态下的活动。


4.活动被回收了怎么办

当我们的临时数据还存放在活动中,可活动被回收了怎么办?这样的情况明显是常常会遇见的。查阅文档可以发现Activity提供了一个onSaveInstanceState()回调方法,这个方法可以保证活动在回收前一定可以调用。所以我们可以利用这个方法,在活动被销毁前,将一些我们期望保留的数据保存下来。
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    String tempData = "Something you want to save";
    outState.putString("data key", tempData);
}
可以看到 onSaveInstanceState()携带了一个Bundle类型的参数,Bundle类提供了一系列的方法用于保存数据,每个保存方法需要传入两个参数:取出数据时用到的键值和数据对象。
然后 取出的数据可以在onCreate中去恢复,因为它也有一个Bundle类型参数,这个参数在一般情况下都是 null,但是当活动被系统回收之前有通过 onSaveInstanceState()方法来保存数据的话,这个参数就会带有之前所保存的全部数据,我们只需对Bundle对象调用getString()方法并传入保存时写入的键值即可,当然我们在取出数据之前最好先判断一下Bundle对象是否为空。


5.活动的启动模式

standard:活动默认的启动模式,在这种模式下,每次活动启动时都不会考虑当前返回栈的栈顶是否为该活动,而去创建一个该活动的新实例并让其处于栈顶。

singleTop:在注册活动时可以指定活动的启动模式。在这种模式下,每次活动启动时会判断当前栈顶活动是否为我们想要启动的活动。若是则不再创建该活动的新实例;若不是则会创建一个新的活动实例并让其处于栈顶。缺点:该模式只考虑了栈顶活动,而没有考虑栈内处于非栈顶的地方是否已经创建了想要启动活动的实例。

singleTask:在这种模式下,每次活动启动时都会判断当前返回栈内是否已经存在该活动的实例,若是则将目标启动活动上面的活动移除返回栈直至该活动处于栈顶而不创建新的活动实例;若不是则创建一个新的活动实例并让其处于栈顶。

singleInstence:在这种模式下,活动启动时会开启一个新的返回栈来管理这个活动,这种模式主要用于当活动中数据需要跨程序共享时。




至此,Android四大组件中的Activity的常见用法已经介绍完毕。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值