5.intent_activity

来源:互联网 发布:method(i,2))用法Java 编辑:程序博客网 时间:2024/04/30 08:06
Intent
Intent(意图)是对将要执行的动作的描述,android中由Intent来协助完成android各个组件之间的通讯。
比如调用Activity的startActivity(intent)来启动一个activity,或者由sendBroadcast(intent)
来传递给所有感兴趣的BroadcastReceiver, 或者由startService(intent)来启动一个后台的service。
 
intent主要用来启动activity或者service, 并携带需要传递的数据, 还可以发送广播.
intent理解成android组件之间的粘合剂。
 
总之,Intent具有激活组件和携带数据的功能!
 
== 通过意图激活activity ==
意图分为两种: 显示意图和隐式意图. 我们可以通过意图来激活一个activity
 
显示意图: 明确指定组件名的Intent为显式意图,指定了Intent应该传递给哪个组件。

  1. // Intent intent = new Intent();
  2. // intent.setClassName("com.gaoyuan.activity", "com.gaoyuan.activity.OtherActivity");
  3. // intent.setClassName(context, "com.gaoyuan.activity.OtherActivity");
  4. // intent.setClass(context, XxxActivity.class); // 本应用中的activity可以不写包名
  5. // 还可以启动别的应用中的activity
  6. // intent.setClassName("com.gaoyuan.internet","com.gaoyuan.internet.MainActivity");
  7. // 或者直接使用Intent的构造方法
  8. Intent intent = new Intent(context, OtherActivity.class);
  9. startActivity(intent);


 
隐式意图: 不指定类, 通过动作, 条件和数据启动activity

  1. Intent intent = new Intent();
  2. //设置动作
  3. intent.setAction("com.itheima.rpcalc.calc");
  4. //设置前提条件
  5. intent.addCategory("android.intent.category.DEFAULT");
  6. //设置数据
  7. intent.setData(Uri.parse("http://www.baidu.com/xxx.jsp"));
  8. startActivity(intent);


想要通过隐式意图启动activity, 那个activity需要做相应的配置, 下面会说
 
要激活自己应用中的activity, 一般使用显示意图.采用显示意图启动其他应用中的activity,
需要知道其包名, 但是包名一般是不公开的, 所以最好使用隐式意图.
 
激活别的应用中的activity, 一般使用隐式意图. 
隐式意图的好处: 动作和应用程序解耦, 一个动作可以由多个应用程序去执行, 比如, 可以有多个浏览器.
 
== Activity配置 ==
需要在application节点下配置
  1. <activity
  2. android:name="com.itheima.rpcalc.CalcActivity"
  3. android:label="@string/rp_calc" >
  4. <!-- <intent-filter> : 意图过滤器 -->
  5. <intent-filter>
  6. <!-- intent的动作 -->
  7. <action android:name="com.itheima.rpcalc.calc" />
  8. <!-- intent的动作的附加条件, 如果想通过隐式意图启动这个activity, 这个必须的
  9. 如果没有特别的附加条件, 可以指定为 DEFAULT -->
  10. <category android:name="android.intent.category.DEFAULT" />
  11. <!-- intent的数据, scheme表示数据的前缀, tel, http等等
  12. host表示主机名, 通过隐式意图激活此activity时, 必须保证前缀和主机名都符合 -->
  13. <data android:scheme="http"
  14. android:host="www.baidu.com" >
  15. </data>
  16. </intent-filter>
  17. </activity>

 只有配置了intent-filter的activity我们才能通过隐式意图激活.
intent-filter 可以配置多个. 当我们设置了intent的动作, 条件和数据时, 如果多个应用的
intent-filter都匹配, 则系统会让我们选择.
 
其他的配置:
- application节点的 label 是在应用程序管理中显示的名字
- activity节点的 label 是在 launcher 中显示的名字.
- label属性: 界面上方的标题, 如果没有, 则使用 application 的 label.
- activity的label属性会在 launcher 中生成一个图标, 点击进入相应的 activity.
- name属性: 要写 activity 的全类名. 如果 manifest 的 package 属性和activity所在包
    的名字一样, 则可以省略包名.
android:excludeFromRecents="true" 不显示在最近应用程序列表
 
== 隐式意图激活系统应用界面 ==
在windows下的注册表记录的系统中所有程序的信息. 其中有一些文件配置了什么样的文件
用什么软件打开.
在android中也一样, 当我们安装一个应用时, 我们配置的activity的信息也会被记录到
android的注册表中, 当使用一个设置了动作,条件,数据的intent启动activity时,
系统就会帮我们去寻找这样的activity.
 
通过隐式意图我们可以打开很多系统应用:
 
  1. // 打电话
  2. Intent intent = new Intent();
  3. intent.setAction(Intent.ACTION_CALL); // 为意图设置动作
  4. intent.setData(Uri.parse("tel://" + phone)); // 为意图设置数据.
  5. startActivity(intent);
  6. // 发短信
  7. intent.setAction(Intent.ACTION_SENDTO);
  8. intent.addCategory("android.intent.category.DEFAULT");
  9. intent.setData(Uri.parse("smsto:12345678"));
  10. // 给发短信activity带数据, 后面会说, 这个 key 可以查询源代码获得
  11. intent.putExtra("sms_body", "你好啊,嘎嘎嘎");
  12. startActivity(intent);
  13. // 打开一个网页(View不只是能开网页, 还能做其他很多事)
  14. intent.setAction(Intent.ANTION_VIEW);
  15. intent.setData(Uri.parse("http://www.baidu.com"));
  16. intent.addCategory(Intent.CATEGORY_BROWSABLE);
  17. startActivity(intent);

 注意:
- 如果一个activity配置了多个intent-filter, 而intent-filter里面又配置了多个
     action, category, data, 我们只需要满足一个就行了
- 打电话, 发短信都需要权限, 但是打开浏览器不需要, 这是个小bug
 
如果我们要开发自己的系统级应用, 需要遵守系统的命名规范, 一般做法为
拷贝系统应用activity的 intent-filter, 设置数据时的 key 也要相同.
这样使用隐式意图启动相应action对应的activity时, 系统就会让我们选择了.
 
== 通过intent给activity带数据 ==
  1. 很简单, startActivity之前使用:
  2. intent.putExtra("key","value"); // 往intent里存数据, 键值对形式
  3. startActivity(intent);
  4. }}}
  5. 在另一个activity中:
  6. {{{class="brush:java"
  7. Intent intent = getIntent(); // 得到激活当前activity的intent
  8. intent.getStringExtra("name"); // 通过key获得value
  9. intent.getStringExtra("age", 10);

  
注意: *不能直接传对象, 如果传对象, 此对象必须实现Serializable或者Parcelable接口*
这种方式在传递的时候, 传的是字节数组, 然后在另一个 activity 中再转成对象.
Parcelable是google工程师为了提升效率定义的新的序列化类型,
Serializable是将对象存入文件, Parcelable是存入内存中.
 
除此之外, 还可以使用 Bundle 传递数据, 这个对象类似map, 使用键值对形式保存数据.
  1. // 传数据的activity
  2. Intent intent = new Intent(this, ExplicitIntentActivity.class);
  3. intent.putExtra("number", 1);
  4. Bundle bundle = new Bundle();
  5. // Bundle 就像一个Map, 但是往里面存的东西可以是8种基本类型和字符串及他们的数组
  6. // 如果存对象, 必须是实现了 Serializable 接口或者 Parcelable接口 的对象
  7. Person p = new Person("gaoyuan1", 22);
  8. bundle.putSerializable("person", p);
  9. intent.putExtra("bundle", bundle);
  10. startActivity(intent);
  11. // 获取数据的activity
  12. Intent intent = getIntent();
  13. // String name = intent.getStringExtra("name");
  14. // int age = intent.getIntExtra("age", 20);
  15. tv_data = (TextView) findViewById(R.id.tv_data);
  16. int number = intent.getIntExtra("number", 0);
  17. Bundle bundle = intent.getBundleExtra("bundle");
  18. if(bundle != null) {
  19. // 注意要强转
  20. Person p = (Person) bundle.getSerializable("person");
  21. tv_data.setText(number + ": " +p.getName() + ": " +p.getAge());
  22. }

  
这些传递数据的方式无论显示还是隐式意图都可以使用.
 
---------
intent.setData(Uri uri); 和 intent.getData(); 是干嘛用的
----------
 
 
== activity通过Intent返回数据 ==
如果我们希望激活的activity在关闭时能给我们返回一些数据, 则需要使用:
startActivityForResult(intent, 100);
 
onActivityResult();
 
{{{class="brush:java"
    // 使用startActivityForResult(); 方法激活activity, 这样就可以获得返回的数据
    public void returnData(View v) {
        Intent intent = new Intent(this, ReturnActivity.class);
         intent.putExtra("name", "gaoyuan");
         intent.putExtra("age", 23);
         // 第二个参数是请求码
        startActivityForResult(intent, 100);
    }
 
    /*
     * 接收 其他 Activity 返回的数据, 此方法会在另一个activity销毁时调用,
     * 调用此方法时, 系统会自动帮我们把另一个activity设置的数据传递进来
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        String name = data.getStringExtra("name");
        int age = data.getIntExtra("age", 20);
        Toast.makeText(getApplicationContext(), name+": "+age, Toast.LENGTH_SHORT).show();
    }
 
    // 在另一个activity中给 MainActivity 返回数据
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_returndata);
 
        // 给 MainActivity 返回数据
        Intent data = new Intent(this, ExplicitIntentActivity.class);
        data.putExtra("name", "gaoyuan2");
        data.putExtra("age", 21);
        // 第一个参数是 结果码
        setResult(200, data);
    }
}}}
 
requestCode: 请求码, 用于区分是谁打开了activity.
如果当前activity有多个地方打开了新的activity, 此参数用于指定是谁打开了新的activity.
 
resultCode: 结果码, 用于区分是哪个activity返回的数据.
 
可以在onActivityResult根据这两个参数做出相应的处理.
 
= Activity =
onCreate() 方法: 在启动activity时调用.
setContentView: 设置layout文件
 
== Activity生命周期 ==
activity有三个状态:
- 1. 活动
- 2. 暂停
- 3. 停止
 
activity有七个生命周期方法:
- onCreate : activity 创建时调用, 只调用一次
- onStart : activity 开启时, 在 onCreate 或 onRestart 方法后调用
- onResume : activity 激活时, 在 onStart 后调用. 从 Pause 状态激活时也会调用
- onPause : activity 不在最顶层, 但仍可见时, 如弹出对话框
- onStop : activity 不可见, 但没有退出时调用(如启动其他activity, 或按home键)
- onDestroy : activity 被销毁时调用.
- onRestart : activity 从 Stop 状态激活时调用, 之后会调用 onRestart
 
回到桌面(home键)和被另一个activity覆盖时一样的, 都会 stop, 而不是destroy
 
PS: 一个应用中所有的Activity都使用同一个 UI线程
 
== finish() 方法 ==
{{{class="brush:java"
    /*
     * finish 方法并不属于生命周期方法, 调用此方法会关闭 Activity, 之后, 在结束过程中会调用
     * 生命周期方法(pause,stop,destroy). 另外, 在此方法中可以对 后退 键的行为进行处理.
     * 另外, 调用此方法时, activity设置的Result 会返回给启动此activity的 onActivityResult方法
     */
    @Override
    public void finish() {
        System.out.println("MainActivity.finish()");
        android.content.DialogInterface.OnClickListener listener =
            new android.content.DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                // 注意这里要调用 super 的 finish, 否则会死循环
                MainActivity.super.finish();
            }
        };
 
        Builder builder = new Builder(MainActivity.this);    // 创建对话框
        builder.setTitle("确定要退出吗?");                    // 设置标题
        builder.setPositiveButton("确定", listener);        // 设置确定按钮的文本以及监听器
        builder.setNegativeButton("取消", null);            // 设置取消按钮
        builder.show();                                        // 显示对话框
    }
}}}
 
== 横竖屏切换 ==
切换横竖屏时Activity会先destroy,再创建, 因为android会自动根据屏幕选择布局文件.
如果我们在res目录中创建如下两个文件夹:
- layout-port: 放竖屏布局文件
- layout-land: 放横屏布局文件
这两个目录中写同名的布局文件, android会自动选择.
想阻止这种行为: activity中属性配置 android:configChanges="orientation|screenSize" .
这样配置之后, 屏幕会旋转, 但是依然用以前的布局, 而且activity不会被摧毁.
 
如果希望屏幕只能是一个方向: android:screenOrientation="landscape"
这样就一直是横屏
 
更多的选项参考文档 API Guide - AndroidManifest - <activity>
 
== Activity摧毁时保存数据 ==
在activity可能被杀死的情况下保存数据, 存到了一个文件里
onSaveInstanceState
 
在onStart之后恢复数据, 调用onCreate方法时, 也会使用之前保存的数据
onRestoreInstanceState

== 还有几个特殊的方法 ==
onPostCreate
Called when activity start-up is complete (after onStart and onRestoreInstanceState have been called). Applications will generally not implement this method; it is intended for system classes to do final initialization after application code has run. 
Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
Overrides: onPostCreate(...) in Activity
Parameters:
savedInstanceState If the activity is being re-initialized after previously being shut down then this Bundle contains the data it most recently supplied in onSaveInstanceState. Note: Otherwise it is null.
 
{{{class="brush:java"
    // 如果系统认为 Activity 可能被kill, 则会调用此方法保存数据, 在 onStop 方法之前调用
    // 但是不保证每次调用 onPsuse, onStop 之间都会调用此方法
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putString("data", "onSaveInstanceState保存的数据");
        System.out.println("MainActivity.onSaveInstanceState()");
        super.onSaveInstanceState(outState);
    }
 
    // 恢复之前 onSaveInstanceState保存的数据, 这份方法里的 Bundle 和 onCreate 方法
    // 里的是一样的, 只是二者调用的时机不同, 此方法在onStart之后调用.
    // 在这个方法里恢复数据显得层次更清晰.
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        String string = savedInstanceState.getString("data");
        System.out.println("恢复: " + string);
        super.onRestoreInstanceState(savedInstanceState);
    }
}}}
 
 
= Activity任务栈 =
当应用被启动的时候, 系统会为其分配一个任务栈, 记录用户打开的activity 及先后顺序,
维护用户的操作体验. 如果任务栈清空了, 应用程序就结束了.
 
每次开启一个应用, 系统都会为其分配新的任务栈, 任务栈的id在系统中是自增长的.
手机重启后, 任务栈的id又从0开始算起.
 
应用中的activity以栈的形式存储的. 当打开一个activity时, activity会被放置到栈顶.
用户能看到的就是栈顶的 activity.
 
我们可以为activity配置启动模式, 在activity节点下配置 android:lunchMode
 
Activity的启动模式有以下四种:
standard:
标准模式, 无限制的创建activity, A-B-B-A-A-A-B
 
singleTop:
如果当前activity在栈顶, 则不会创建, 而是复用当前activity的实例.
调用当前activity的 *onNewIntent* 方法. A-B-A-B-C-B-A. (浏览器标签页)
 
singleTask:
任务栈中只能有一个当前activity实例, 如果再次调用, 不会创建新的,
而是将当前activity上面所有的activity都清空, 使自己成为栈顶, 很霸道
也是会调用 onNewIntent 方法. A-B-C-C-C >再次调B> A-B (浏览器主界面)
 
singltInstance:
当首次启动此activity是, 会开启一个新的任务栈, 此任务栈中只有当前activity,
而且会放在原先任务栈的前面. 如果此时原先任务栈又新创建
了activity, 此时当前activity的任务栈又会放在原先任务栈后面.

在整个系统中, 只有一个activity实例, 并且在自己的任务栈中.(接/打电话界面, 有道词典查词界面)

可以参考这篇文章: http://blog.csdn.net/liuhe688/article/details/6754323

 
旧的activity不finish, 新的就不会创建
onNewIntent
 
注意: *后两种启动模式的activity如果使用 startActivityForResult 启动, 是无法得到返回的数据的.*

参考博客:
http://www.cnblogs.com/feisky/archive/2010/01/16/1649081.html?t=1376744007734
http://www.cnblogs.com/xirihanlin/archive/2010/06/03/1750811.html

 

 
 
 
 


来自为知笔记(Wiz)


0 0