Android四大组件之一——Activity123

来源:互联网 发布:ubuntu安装哪个版本好 编辑:程序博客网 时间:2024/06/05 06:03

Android四大组件之Activity123

Activity是Android最重要也是最常用的组件

一、Activity基本知识

  • Activity的生命周期

显示状态:onCreate,onStart,onResume

隐藏状态:onPause,onStop

销毁状态:onDestroy

当启动应用时会有如下方法得到执行onCreate-->onStart-->onResume

onStart是可见但不可交互状态

onResume是可见且可交互状态


当点击Back键时会调用onPause-->onStop-->onDestroy(一个Activity从创建到销毁的全过程,onRestart另说)

onPause是不可交互但可见状态

onStop是不可见且不可交互状态



通过Intent启动另一个Activity观察生命周期


需要注意的是点击button后首先执行的是onPause方法,然后创建另一个Activity,当SecondActivity可见时再执行MainActivity的onStop方法。

点击Back键后同理先执行onPause方法,回到MainActivity,因为MainActivity已经有实例,所以执行onRestart方法替代onCreate,之后依然类似,onStart-->onResume,以及SecondActivity的onStop-->onDestroy。



为什么只是先暂停当前Activity,而不是跳转Activity后再执行onPause-->onStop,或者先onPause-->onStop,然后再创建跳转Activity?

1)如果当前的应用是音乐播放器,当有电话打来时,当前的Activity在接听页面显示之前都不会暂停,不符合交互逻辑。

2)同样的例子,电话页面未显示而当前Activity已经stop,则会出现不可见的黑屏状态,直到接听页面创建并显示完成。


Activity横竖屏切换的生命周期

切换横竖屏时会将当前Activity按正常流程Destroy,然后重新创建Activity



切换横竖屏时,如果有输入框之类的控件,则需要保存竖屏时的状态,比如说有输入框之类的控件而且已经有输入内容,此时切到横屏不应该丢失数据,因此需要调用onSaveInstanceState保存状态信息。在onCerate方法中进行判断参数savedInstanceState是否为空

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                if (savedInstanceState != null) {            Log.i("tag", "MainActivity" + savedInstanceState.getString("libo"));        }        Log.i("tag", "MainActivity onCreate");        button = (Button) findViewById(R.id.button1);        button.setOnClickListener(this);    }        @Override    protected void onSaveInstanceState(Bundle outState) {        super.onSaveInstanceState(outState);        Log.i("tag", "MainActivity onSaveInstanceState");        outState.putString("libo", "abc");    }

Activity生命周期的应用——音乐播放

onDestroy方法常用作释放资源

private MediaPlayer mediaPlayer;private int position;//在onCreate方法中初始化mediaPlayer = MediaPlayer.create(this, R.raw.ifyou);mediaPlayer.start();//在onPause方法中暂停MediaPlayer,并记录播放进度@Overrideprotected void onPause() {   super.onPause();   Log.i("tag", "MainActivity onPause");   if (mediaPlayer.isPlaying()) {     mediaPlayer.pause();     position = mediaPlayer.getCurrentPosition();     Log.i("tag", position+"");   }}    //在onResume方法中读取进度播放@Overrideprotected void onResume() {   super.onResume();   Log.i("tag", "MainActivity onResume");   if (position != 0) {     mediaPlayer.seekTo(position);     Log.i("tag", position+"");     mediaPlayer.start();   }}//在onDestroy方法中进行资源的释放@Overrideprotected void onDestroy() {    super.onDestroy();     Log.i("tag", "MainActivity onDestroy");     if (mediaPlayer != null) {       mediaPlayer.release();       mediaPlayer = null;     }}

  • Activity之间的启动方式

显式启动

Intent是Android程序中各组件之间进行交互的一种重要方式,不仅可以指明当前组件想要执行的动作,还可以在不同的组件之间传递数据。一般可被用于启动Activity,启动Service,以及发送广播等。

通过构造Intent,指定需要跳转的Activity。

Intent intent = new Intent(ThirdActivity.this, FourthActivity.class);startActivity(intent);

隐式启动

为将要启动的Activity添加一个Intent过滤器,并指定action标签,指明当前Activity可以响应"libo"这个action。category标签默认为 android.intent.category.DEFAULT,更精确的指明了当前Activity能够响应带有category的Intent。action和category标签内容同时匹配时,这个Activity才能响应。当 category为默认时,可以省略 intent.addCategory() 方法。

        <activity android:name="com.example.activity.FourthActivity">            <intent-filter >                <action android:name="libo"/>                <category android:name="android.intent.category.DEFAULT"/>             </intent-filter>        </activity>
Intent intent = new Intent();intent.setAction("libo");startActivity(intent);
隐式启动多用于启动没有源文件的Activity,比如系统的浏览器,拨号,短信等

//打开网页Intent intent = new Intent();intent.setAction(Intent.ACTION_VIEW);Uri uri = Uri.parse("http://www.qq.com");intent.setData(uri);startActivity(intent);
//打开图库Intent intent = new Intent();intent.setAction(Intent.ACTION_GET_CONTENT);intent.setType("image/*");startActivity(intent);
//发送短信Intent intent = new Intent();intent.setAction(Intent.ACTION_SEND);intent.setType("text/plain");intent.putExtra(Intent.EXTRA_TEXT, "hello csdn");startActivity(intent);
//拨号Intent intent = new Intent();intent.setAction(Intent.ACTION_VIEW);Uri uri = Uri.parse("tel:666666");intent.setData(uri);startActivity(intent);

以上系统应用可以被调用,网页通过setData方法指定Intent操作的数据。另外,还可以通过Intent-Filter配置Data标签,更精确的指定当前活动可以响应什么类型的操作。

Data标签可以配置如下内容:

1.android:scheme 用于指定数据的协议部分,例如http、geo地理位置、tel拨打电话

2.android:host 用于指定数据的主机名部分,例如www.qq.com

3.android:port 用于指定数据的断口部分,一般紧随主机名之后

4.android:path 用指定主机名和端口之后的部分

5.android:mimeType 用于指定可以处理的数据类型。

更多系统的action可以查阅官方文档

  • Activity之间的数据传递

向下一个活动传递数据

通过Intent启动另一个Activity时,可以利用Intent携带一定量的具体数据。

具体方法为putExrta。通过键值对的方式。可以传递常用的8种类型及数组,String,int,double等

Intent intent = new Intent(ThirdActivity.this, FourthActivity.class);intent.putExtra("name", "libo");intent.putExtra("age", 21);startActivity(intent);
在被启动的Activity中需要先进行getintent,获取启动Intent,然后通过getStringExtra等的函数取出数据

Intent intent = getIntent();if (intent != null) {text.setText(intent.getStringExtra("name") + " " + intent.getIntExtra("age", 0));}

也可以通过Bundle先进行封装,再通过Intent传递

Intent intent = new Intent(ThirdActivity.this, FourthActivity.class);Bundle bundle = new Bundle();bundle.putString("name", "libo");bundle.putInt("age", 21);intent.putExtras(bundle);startActivity(intent);
Bundle也可以用于封装对象实例进行传递,不过对象须实现Serializable接口进行序列化(序列化是Java IO中的知识)
public class Person implements Serializable {private String name;private int age;private String address;public Person(String name, int age, String address){this.name = name;this.age = age;this.address = address;}@Overridepublic String toString() {return "name: " + name + "age: " + age + "address: " + address;}}

Intent intent = new Intent(ThirdActivity.this, FourthActivity.class);Person person = new Person("libo", 21, "xian");Bundle bundle = new Bundle();bundle.putSerializable("person", person);intent.putExtras(bundle);startActivity(intent);

Intent intent = getIntent();if (intent != null) {Person person = (Person) intent.getSerializableExtra("person");text.setText(person.toString());}
Bundle也可以用于传递图片,但大小不能过大,上限约为0.5M

Intent intent = new Intent(ThirdActivity.this, FourthActivity.class);Bundle bundle = new Bundle();Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);bundle.putParcelable("bitmap", bitmap);intent.putExtras(bundle);startActivity(intent);img.setImageBitmap((Bitmap) intent.getParcelableExtra("bitmap"));
当Bundle携带数据量过大时会抛出如下错误
!!! FAILED BINDER TRANSACTION !!!
如果需要在另一个Activity中使用本Activity的一些比较大的数据,可以考虑SQLite,或者文件

返回数据给上一个活动

此时启动Activity的方法不是startActivity而是startActivityForResult(Intent intent, int requestCode),request只要保证是唯一值就可以。

Intent intent = new Intent(MainActivity.this, FirstActivity.class);startActivityForResult(intent, 1);
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {switch (requestCode) {case 1:if (resultCode == RESULT_OK) {String str = data.getStringExtra("first");text.setText(str);}break;default:break;}}
Intent intent = new Intent();intent.putExtra("first", "libo");setResult(RESULT_OK, intent);finish();

  • Activity的启动模式( launchMode)

standard

默认是模式,可以创建条件允许的任意多个

singleTop

如果再次创建的Activity在栈顶,那么就不会再重新创建新Activity,而是执行onNewIntent方法

如果不在栈顶,则跟默认模式相同,还是会再创建新的Activity

singleTask

MainActivity->Activity->MainActivity(MainActivity默认,Activity singleTask),如果此时再启动Activity则会执行第二个MainActivity的onDestroy方法,即在任务栈中进行出栈,直到Activity处于栈顶。

singleInstance

启动Activity时会处于不同的任务栈中

Main1->First->Main2->First->Main3(Main默认模式,First singleInstance),First被启动两次但是只执行一次onCreate方法并创建一个新的任务栈,其余均为onNewIntent方法。

当First启动Main2时,因为是默认模式,则会寻找Task1,并创建Activity,Main3同样,此时显示的是Main3,单击Back键时会返回到Main2,Main1,最后才是First。

Back会先把此栈中的Activity全部出栈,再把Task2中的Activity出栈。

  • 启动活动的最佳写法

启动不是由自己开发的一个Activity,不清楚该Activity需要传递哪些数据,除了查看源码之外,完全可以在Activity创建一个静态方法来提示调用者该Activity的详细信息。

public static void activityStart(Context context, String data1, String data2){Intent intent = new Intent(context, FirstActivity.class);intent.putExtra("data1", data1);intent.putExtra("data2", data2);context.startActivity(intent);}
//启动时,只需一句代码,并且简单完整的传入所需的各个参数FirstActivity.activityStart(this, "abc", "def");



二、深入了解Activity




1 0
原创粉丝点击