2.2 安卓活动基础 Activity跳转---Intent

Intent是安卓程序中各组件之间进行交互的重要方式,既可以指明当前组件要执行的动作,还可以在不同组件之间传递数据。
Intent一般可以被用于启动活动、启动服务以及发送广播等场景。
Intent可以分为两种:
1、显式Intent
2、隐式Intent
Intent有多个构造函数的重载, 重载的知识可以参照Java函数重载知识点,本文末尾附简单说明;

显式Intent的应用
其中一个是Intent(Context packageContext, Class<?>cls)。这个构造函数接收了两个参数:
第一个参数:Context要求提供一个启动活动的上下文 , Context上下文可以参照安卓Context知识点,本文末尾附简单说明;
第二个参数:Class则是指定想要启动的目标活动
通过Intent(Context packageContext, Class<?>cls)这个构造函数就可以构建出Intent的“意图”;
安卓的Activity提供了一个startActivity()的方法,我们可以利用这个方法启动活动,这个方法接收一个Intent参数,我们将构建好的Intent参数传入startActivity()方法就可以启动目标活动了。
比如我们通过主活动的一个按钮启动第二个活动。下面是示例代码:

button.setOnclickListener(new OnClickListener(){
    @override
    public void onClick(View v){
        //通过这个构造函数构建出我们的意图
        //Intent intent 新建一个Intent的引用,放在栈内存中
        //new Intent()新建一个Intent的对象,放在堆内存中
        //= 将Intent的对象赋值给Intent的引用intent
        Intent intent = new Intent(MainActivity.this, SecondActivity.class);
        //调用startActivity()方法,启动第二个活动;
        startActivity(intent);
    }
});

由于这种方式启动活动,Intent的意图很明显,所以称之为显式Intent

隐式Intent
隐式Intent并不明确指出我们想要启动哪一个活动,而是通过指定IntentFilter意图过滤器的action和category等信息,然后由系统分析判断这个Intent,然后帮助我们启动对应个活动。
首先我们在AndroidMainfest.xml的<activity>标签下配置<intent-filter>的内容。指定当前这个activity能够响应的action和category,当Java代码中的程序刚好匹配到的是这个意图过滤器中的内容,则可以自动启动这个活动
代码如下:

<activity android:name=".SecondActivity">
    <intent-filter>
        //此处我们指明了当前活动可以响应com.example.activity.ACTION_START这个action
        <action android:name="com.example.activity.ACTION_START"/>
        //category标签中我们指明了当前活动可以响应Intent中带有的category
        //必须加上category android:name="android.intent.category.DEFAULT",否则无法启动改活动
        <category android:name="android.intent.category.DEFFAULT"/>
        //下面一行代码为下面一段知识点使用,可以添加多个category,此处我们添加了自己的category
        //<category android:name="com.example.activityTest.MY_CATEGORY"/>
    </intent-filter>
</activity>

只有上述activity中的action和category中的内容同时匹配上Java代码的Intent中的action和category时,这个活动才能响应;android:name="android.intent.category.DEFFAULT是一个默认的category,在调用startActivity()方法的时候会自动将这个category添加到Intent中,所以默认的话,我们也可以不填写。
隐式Intent启动活动的Intent代码如下:
使用Intent的另外一种构造函数;

button.setOnclickListener(new OnClickListener(){
    @override
    public void onClick(View v){
        //通过这个构造函数构建出我们的意图,响应与com.example.activity.ACTION_START匹配的action
        //Intent intent 新建一个Intent的引用,放在栈内存中
        //new Intent()新建一个Intent的对象,放在堆内存中
        //= 将Intent的对象赋值给Intent的引用intent
        Intent intent = new Intent("com.example.activity.ACTION_START");
        //这一行是category,默认的这种方式可以不写;且category可以指定多个
        //比如我们调用Intent中的addCategory()方法来添加一个category;
        //intent.addCategory("android.intent.category.DEFFAULT");
        intent.addCategory("com.example.activityTest.MY_CATEGORY");
        //调用startActivity()方法,启动第二个活动;
        startActivity(intent);
    }
});

隐式Intent还有更多的用法,这里暂不详细解释,可以参照第一行代码第二版46-49页
1、启动其他程序中的活动,比如在我们自己的程序中展示一个网页,可以利用隐式Intent调用系统浏览器来打开这个网页

Intent传递数据
活动中传递数据的思路是:
Intent中提供了一系列的putExtra()方法的重载,可以把我们想要传递的数据暂存在Intent中,到达另一个活动中将数据从Intent中取出来即可

1、Intent向下一个活动传递数据
我们在A活动中通过Intent的putExtra()方法把传递字符串
传递数据的代码如下:

        //button1的点击事件访问hint,属于局部内部类(包括匿名局部内部类和普通内部类)中使用局部变量,那么这个局部变量必须使用final修饰
        //hint.getText()作为一个局部变量,其生命周期应该在该方法运行结束后就完结,但是在此处被内部类所引用,会导致其作用域的扩大。
        // 如果在此期间又对局部变量的值随意改变,将会造成混乱。因此要将该局部变量的属性硬性的修改为final,即可防止混乱的产生。
        final EditText hint = findViewById(R.id.tips_edt);
button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String data = String.valueOf(hint.getText());
                if (data.equals("")){
                    ToastShow(MainActivity.this, "请输入传递的数据!");
                }else {
                    //显式Intent启动活动2
                    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                    //这里的putExtra()接收两个参数,键值对的方式,第一个参数是键,下一级活动通过这个键可以从Intent中取值
                    //第二个参数才是真正传递的数据
                    intent.putExtra("data", data);
                    startActivity(intent);
                }
            }
        });

在下一级活动中,我们通过键值对中键名来获取值
获取数据的代码如下:

        TextView data_tv = findViewById(R.id.data_tv);
        //首先通过getInten()方法获取到用于启动SecondActivity的Intent
        Intent intent = getIntent();
        //然后调用getStringExtra()方法,传入键,即可得到键对应的值;
        //拓展:如果传递的是整形数据,则用getIntExtra()获取数据
        //如果传递的是布尔型数据,则用getBooleanExtra()获取数据
        data_tv.setText(intent.getStringExtra("data"));

实际APP运行gif见文末:

2、返回数据给上一级活动
与传递数据给下一级不同的是,返回上一个活动只需要按一下虚拟按键的返回键,并没有一个用于启动活动的Intent来传递数据。怎么办呢?我们知道Activity中还有一个startActivityForResult()方法也是用于启动活动的,这个方法是期望在活动销毁时能够返回一个结果给上一个活动,这正是我们需要的。
startActivityForResult()方法接收两个参数,第一个参数是Intent,第二个参数是请求码,这个请求码用于在之后的回调中判断数据的来源。接下来我们还是贴上程序
主活动的按钮点击事件代码:

button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent3 = new Intent(MainActivity.this, ForthActivity.class);
                //startActivityForResult()方法用来启动活动4,这个方法接收两个参数
                //第一个是Intent,从主活动跳转到活动4
                //第二个是请求码,用于在之后的回调中判断数据来源,请求码只要传入一个唯一值就行了
                startActivityForResult(intent3, 1);
            }
        });

这里我们使用startActivityForResult()方法用来启动活动4,这个方法接收两个参数:
第一个是Intent,从主活动跳转到活动4;
第二个是请求码,用于在之后的回调中判断数据来源,请求码只要传入一个唯一值就行了;

接下来是活动4的代码:

public class ForthActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_forth);

        final EditText data_edt = findViewById(R.id.data_edt);
        Button button = findViewById(R.id.send_btn);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //构建一个Intent,用于数据传递
                Intent intent = new Intent();
                //将数据以键值对的方式放入Intent
                intent.putExtra("data_return", String.valueOf(data_edt.getText()));
                Log.i("ForthActivity", "" + String.valueOf(data_edt.getText()));
                //调用setResult()方法,这个方法专门用于向上一级活动返回数据
                //setResult()接收两个参数
                //第一个参数:用于向上一级活动返回结果,一般只有RESULT_OK和RESULT_CANCELED这两个值
                //第二个参数是把带有数据的Intent传递回去
                setResult(RESULT_OK, intent);
                //然后调用finish()方法来销毁当前活动
                finish();
            }
        });
    }
}

由于我们是使用startActivityForResult()方法来启动活动4的,所以在活动4被销毁之后会回调上一个活动的onActivityResult()方法,因此我们需要再主活动中重写这个方法来得到返回的数据

//onActivityResult()方法带有三个参数
    //第一个参数requestCode,这是我们在启动活动是传入的请求码
    //第二个参数resultCode,这个是我们返回数据时传入的处理结果
    //第三个参数data,这个是携带返回数据的Intent,通过data.getStringExtra(键)我们可以获取到传递过来的数据
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode){
            //由于在一个活动中调用startActivityForResult()方法启动很多不同的活动,每一个活动返回的数据都会回调到onActivityResult()这个方法中
            //因此我们首先检查requestCode的值判断数据来源,确认数据是从哪个Activity返回的
            //之后判断resultCode判断处理的结果是否成功
            //最后从data中取出数据
            case 1:
                if (resultCode == RESULT_OK){
                    rec_tv.setText(String.valueOf(data.getStringExtra("data_return")));
                }
                break;
            default:
                break;
        }
    }

程序运行效果:

这里写图片描述

附件:
1、函数重载
什么是方法的重载呢?
如果同一个类中包含了两个或两个以上方法名相同、方法参数的个数、顺序或类型不同的方法,则称为方法的重载,也可以称方法被重载了。
public void show(); //无参方法
public void show(String name); //重载show方法,一个字符串参数
public void show(String name, int age); //重载show方法,两个参数
public void show(int age, String name); //重载show方法,两个参数顺序不同
如何区分调用的是哪个重载方法呢?
当调用被重载的方法时,Java会根据参数的个数和类型来判断应该调用哪个重载方法,参数完全匹配的方法将被执行。
判断方法重载的依据:
1、必须是在同一个类中
2、方法名相同
3、方法参数的个数、顺序或类型不同
4、与方法的修饰符或返回值没有关系

2、Context 上下文
Context在语文中,我们可以理解为语境,在程序中,我们可以理解为当前对象在程序中所处的一个环境
那Context到底是什么呢?一个Activity就是一个Context,一个Service也是一个Context。Android程序员把“场景”抽象为Context类,他们认为用户和操作系统的每一次交互都是一个场景,比如打电话、发短信,这些都是一个有界面的场景,还有一些没有界面的场景,比如后台运行的服务(Service)。
Context到底可以实现哪些功能呢?这个就实在是太多了,弹出Toast、启动Activity、启动Service、发送广播、操作数据库等等都需要用到Context。
在绝大多数场景下,Activity、Service和Application这三种类型的Context都是可以通用的。不过有几种场景比较特殊,比如启动Activity,还有弹出Dialog。出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System
Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。
如何获取Context
通常我们想要获取Context对象,主要有以下四种方法
1:View.getContext,返回当前View对象的Context对象,通常是当前正在展示的Activity对象。
2:Activity.getApplicationContext,获取当前Activity所在的(应用)进程的Context对象,通常我们使用Context对象时,要优先考虑这个全局的进程Context。
3:ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context,可以使用这个方法,这个方法在实际开发中使用并不多,也不建议使用。
4:Activity.this 返回当前的Activity实例,如果是UI控件需要使用Activity作为Context对象,但是默认的Toast实际上使用ApplicationContext也可以。
getApplication()和getApplicationContext()
上面说到获取当前Application对象用getApplicationContext,不知道你有没有联想到getApplication(),这两个方法有什么区别?相信这个问题会难倒不少开发者。
Application本身就是一个Context,所以这里获取getApplicationContext()得到的结果就是Application本身的实例。那么问题来了,既然这两个方法得到的结果都是相同的,那么Android为什么要提供两个功能重复的方法呢?实际上这两个方法在作用域上有比较大的区别。getApplication()方法的语义性非常强,一看就知道是用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在绝大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法了。
如何正确使用Context
一般Context造成的内存泄漏,几乎都是当Context销毁的时候,却因为被引用导致销毁失败,而Application的Context对象可以理解为随着进程存在的,所以我们总结出使用Context的正确姿势:
1:当Application的Context能搞定的情况下,并且生命周期长的对象,优先使用Application的Context。
2:不要让生命周期长于Activity的对象持有到Activity的引用。
3:尽量不要在Activity中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用,如果使用静态内部类,将外部实例引用作为弱引用持有。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值