Android Activity要点(2)

一、带返回值的Activity回退过程

一般情况下,我们要从当前Activity跳转到另一个Activity,采用的方法是通过startActivity(Intent)来携带数据并实现跳转 有时候又需要跳转到的Activity能够在回退时返回处理结果给前一个Activity,这就要用到以下方法了

public void startActivityForResult(Intent intent, int requestCode)

该方法同样是用于实现Activity的跳转,不过多了一个int类型的请求码requestCode requestCode用于标示当Activity回退时,处理结果是从哪一个Activity传递来的,因为当前Activity有可能需要跳转到多个Activity

此外,Activity类还包含有以下方法

protected void onActivityResult(int requestCode, int resultCode, Intent data)

requestCode即是请求码,resultCode用于标示数据处理结果,data用于携带数据

因此,我们可以用以下代码实现Activity的跳转

        private int REQUEST_CODE = 10;

        Intent intent = new Intent(MainActivity.this, Main2Activity.class);
        Bundle bundle = new Bundle();
        bundle.putString("requestText", "啊哈");
        intent.putExtras(bundle);
        startActivityForResult(intent, REQUEST_CODE);

向Intent中传入需要传递给Main2Activity的数据

然后,在onActivityResult中处理Main2Activity回退后传递而来的数据处理结果,这里用Log来输出

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) {
            Bundle bundle = data.getExtras();
            Log.e("MainActivity", bundle.getString("responseText"));
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

其中,需要判断requestCode是否与请求码相等 此外,查看源码可知,resultCode取值一般为以下三个,用来标示操作结果

    /** Standard activity result: operation canceled. */
    //标示操作取消
    public static final int RESULT_CANCELED    = 0;
    
    /** Standard activity result: operation succeeded. */
    //标示操作成功
    public static final int RESULT_OK           = -1;
    
    /** Start of user-defined activity results. */
    public static final int RESULT_FIRST_USER   = 1;

以上都是在MainActivity中操作,此外还需要在Main2Activity中设置返回结果 先取出传递而来的数据requestText

    private String requestText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        Intent intent = getIntent();
        if (intent != null) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                requestText = bundle.getString("requestText");
            }
        }
        init();
    }

通过setResult方法设置处理结果为RESULT_OK,并通过intent携带处理结果

public void init() {
        findViewById(R.id.response).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                Bundle bundle = new Bundle();
                bundle.putString("responseText", "收到第一个Activity的请求内容为:" + requestText);
                intent.putExtras(bundle);
                setResult(RESULT_OK, intent);
                finish();
            }
        });
    }

这样就可以实现当Activity回退时,携带处理结果到前一个Activity了


二、关于Activity启动模式的补充说明

在上一篇博文中已经介绍过Activity的四种启动模式了,这里再来补充一些内容

  • singleTask 此为栈内复用模式 如果以在AndroidManifest中声明属性的方式来设定启动模式的话,如果不指定taskAffinity属性,该Acitvity只会存在于当前栈中 想要让Activity以单实例的方式存在于一个新的栈的话,可以这样声明:
    <activity
        android:name=".Main2Activity"
        android:launchMode="singleTask"
        android:taskAffinity="com.custom.czy" />

注意,taskAffinity的值不能与包名相同,不然就相当于没有设置了

可以通过getTaskId()方法来查看当前Activity位于哪个栈,如:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e("第一个Activity", getTaskId() + "");
    }
  • singleInstance 即单实例模式 采用此种模式的Activity均会独立存在于一个栈内,即使两个Activity的taskAffinity属性相同 例如
    <activity
        android:name=".Main2Activity"
        android:launchMode="singleInstance"
        android:taskAffinity="com.custom.czy" />
    <activity
        android:name=".Main3Activity"
        android:launchMode="singleInstance"
        android:taskAffinity="com.custom.czy" />

Main2Activity和Main3Activity均声明为singleInstance模式且栈名为com.custom.czy 但通过Log.e("Activity", getTaskId() + "");查看,还是可以发现两个Activity存在于不同的栈中

三、Activity的隐式调用

隐式调用不需要明确指定要调用的Activity信息,而是根据Intent具有的信息去匹配目标组件的IntentFilter中所设置的过滤信息,如果匹配成功则启动,否则会报错 一个Activity可以包含有多个IntentFilter,只要Intent能够匹配其中一组< intent-filter >即可启动该Activity IntentFilter具有的属性有:action、category、data

  • action action属性值是一个字符串,系统也为我们提供了多个action,如Intent.ACTION_VIEW可用于打开系统自带的浏览器 在 < intent-filter >中可以声明多个action,只要求Intent中携带的action字符串与其中一个相同即成功匹配该Activity Intent中必须含有action属性,否则将直接匹配失败
<intent-filter>
        <action android:name="com.czy.action" />
        <action android:name="com.czy1.action" />
        <action android:name="com.czy1.action" />

        <category android:name="android.intent.category.DEFAULT" />
</intent-filter>
    public void startActivity(View view) {
        Intent intent = new Intent("com.bb.hh");
        intent.setAction("com.czy.action");
        Log.e("++++++", intent.getAction());
        startActivity(intent);
    }

这样依然可以成功启动Activity

  • category 在< intent-filter >中同样可以设定多个category属性,且Intent也可以通过addCategory(String category)添加多个category 与action属性不同的是,只要是在Intent中包含的category值,< intent-filter >都必须有category与之一一匹配,否则匹配失败

需要注意的是,系统在startActivity(Intent intent)的时候,会自动为Intent添加一个默认的category值,即:android.intent.category.DEFAULT 所以为了让Activity可以通过隐式调用的方式启动,需要在< intent-filter >同样为之添加一个默认的category值 如上述代码所示

  • data data属性用于指定当前活动能够响应什么类型的数据 如系统自带的浏览器自然就能响应http模式的网络连接要求,因此我们可以用隐式调用的方式来调用浏览器打开指定网页
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse("http://www.baidu.com"));
    startActivity(intent);

如果过滤规则中设置了data属性,则Intent中也必须含有data属性且相同才能匹配成功 data包含的属性值有:

    <data android:scheme="string"
        android:host="string"
        android:port="string"
        android:path="string"
        android:pathPattern="string"
        android:pathPrefix="string"
        android:mimeType="string"/>

data由两部分组成,mimeType和URI mimeType指媒体类型,可以是:image/jpeg、video/*,用于表示图片、文本、视频等不同的媒体格式 URL的结构如下所示: < scheme>://< host>:< port>/[< path>|< pathPrefix>|< pathPatten>]

scheme:URI的模式,如http,file,content,默认值为(content和file) host:URI的主机名,比如www.baidu.com port:URI的端口号 path、pathPatten和pathPrefix这三个参数表示路径信息

如,可以设置某Activity能够处理的数据类型为图片image

 <activity android:name=".Main2Activity">
    <intent-filter>
        <action android:name="com.czy.action" />
        <action android:name="com.czy1.action" />
        <action android:name="com.czy1.action" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.czy" />

        <data android:mimeType="image/*" />

    </intent-filter>

</activity>

则可以通过设置mimeType属性来启动该Activity

    public void startActivity(View view) {
        Intent intent = new Intent("com.bb.hh");
        intent.setAction("com.czy.action");
        intent.addCategory("android.intent.category.czy");
        intent.setType("image/png");
        startActivity(intent);
    }

或者为Intent设置完整的data属性

    public void startActivity(View view) {
        Intent intent = new Intent("com.bb.hh");
        intent.setAction("com.czy.action");
        intent.addCategory("android.intent.category.czy");
        intent.setDataAndType(Uri.parse("file://abc"),"image/png");
        startActivity(intent);
    }

此外,由于通过隐式调用有可能因为匹配不成功而导致报错,所以在调用之前可以先判断当前是否有合适的Activity

Intent intent = new Intent("com.bb.hh");
        intent.setAction("com.czy.action");
        intent.addCategory("android.intent.category.czy");
        intent.setDataAndType(Uri.parse("file://abc"), "image/png");

        ComponentName componentName = intent.resolveActivity(getPackageManager());
        if (componentName != null) {
            String name = componentName.getClassName();
            Log.e("MainActivity:", "匹配成功:" + name);
            startActivity(intent);
        } else {
            Log.e("MainActivity:", "匹配失败");
        }

如果匹配失败,resolveActivity方法就会返回null,否则就会返回匹配度最高的Activity信息

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android干货

Android接口回调机制

1063
来自专栏Android干货园

Android谈谈封装那些事--BaseActivity和BaseFragment(一)

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/53...

1113
来自专栏Android先生

Context都没弄明白,还怎么做Android开发?

作为Android开发者,不知道你有没有思考过这个问题,Activity可以new吗?Android的应用程序开发采用JAVA语言,Activity本质上也是一...

762
来自专栏水击三千

Android应用开发SharedPreferences存储数据的使用方法

SharedPreferences是Android中最容易理解的数据存储技术,实际上SharedPreferences处理的就是一个key-value(键值对)...

2856
来自专栏pangguoming

Android 子activity关闭 向父activity传值

使用startActivity方式启动的Activity和它的父Activity无关,当它关闭时也不会提供任何反馈。 可变通的,你可以启动一个Activity作...

3365
来自专栏吴小龙同學

Android之Intent和Intent过滤器

Intent 是一个消息传递对象,您可以使用它从其他应用组件请求操作。尽管 Intent 可以通过多种方式促进组件之间的通信,但其基本用例主要包括以下三个: 启...

2935
来自专栏Android开发实战

重新认识Android Context

Context在Android系统中的地位很重要,它几乎无所不能,但它也不是你想用就能随便用的,谨防使用不当引起的内存问题。我们总会忽略掉一些比较细节的东西,自...

743
来自专栏分享达人秀

Fragment回退栈及弹出方法

在上一期分享的文章末尾留了一个课后作业,有去思考如何解决吗?如果已经会了那么恭喜你,如果还不会也没关系,本期一起来学习。 一、回退栈 在前面两...

1986
来自专栏Android-薛之涛

Android - 懒加载

如果我们的项目中使用了ViewPager+Framgment实现底部Tab可点可滑,那么我们都知道ViewPager有预加载功能,通过viewpager.set...

662
来自专栏向治洪

android进程 清理及activity栈管理

MainActivity如下: package come.on;   import android.app.Activity;   import andro...

20610

扫码关注云+社区