Android 基础总结(四)Activity

Android 开发的四大组件分别是:活动(activity),用于表现功能;服务(service),后台运行服务,不提供界面呈现;广播接受者(Broadcast Receive),用于接收广播;内容提供者(Content Provider),支持多个应用中存储和读取数据,相当于数据库。

一 什么是activity

Activity是一个应用程序的组件,他在屏幕上提供了一个区域,允许用户在上面做一些交互性的操作, 比如打电话,照相,发送邮件,或者显示一个地图!Activity可以理解成一个绘制用户界面的窗口, 而这个窗口可以填满整个屏幕,也可能比屏幕小或者浮动在其他窗口的上方!
一个应用通常是由多个彼此松散联系的Activity组成,一般会指定应用中的某个Activity为主活动,也就是说首次启动应用时给用户呈现的Activity。将Activity设为主活动的方法,如下面代码所示需要在AndroidManifest文件中添加以下内容

<application>
     ....
    <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
     </activity>
     ....
</application>    

当然Activity之间可以进行互相跳转,以便执行不同的操作。每当新Activity启动时,旧的Activity便会停止,但是系统会在堆栈也就是返回栈中保留该Activity。当新Activity启动时,系统也会将其推送到返回栈上,并取得用户的操作焦点。当用户完成当前Activity并按返回按钮时,系统就会从堆栈将其弹出销毁,然后恢复前一Activity。
当一个Activity因某个新Activity启动而停止时,系统会通过该Activity的生命周期回调方法通知其这一状态的变化。Activity因状态变化每个变化可能有若干种,每一种回调都会提供执行与该状态相应的特定操作的机会。

二 Activity的生命周期

周期即活动从开始到结束所经历的各种状态。生命周期即活动从开始到结束所经历的各个状态。从一个状态到另一个状态的转变,从无到有再到无,这样一个过程中所经历的状态就叫做生命周期。

Activity本质上有四种状态:
1.运行(Active/Running):Activity处于活动状态,此时Activity处于栈顶,是可见状态,可以与用户进行交互
2.暂停(Paused):当Activity失去焦点时,或被一个新的非全面屏的Activity,或被一个透明的Activity放置在栈顶时,Activity就转化为Paused状态。此刻并不会被销毁,只是失去了与用户交互的能力,其所有的状态信息及其成员变量都还在,只有在系统内存紧张的情况下,才有可能被系统回收掉
3.停止(Stopped):当Activity被系统完全覆盖时,被覆盖的Activity就会进入Stopped状态,此时已不在可见,但是资源还是没有被收回
4.系统回收(Killed):当Activity被系统回收掉,Activity就处于Killed状态

tivity的生命周期如下图:
在这里插入图片描述
Activity其实是继承了ApplicationContext这个类,我们可以重写以下方法,如下代码:

public class Activity extends ApplicationContext {
protected void onCreate(Bundle savedInstanceState);
protected void onStart();
protected void onRestart();
protected void onResume();
protected void onPause();
protected void onStop();
protected void onDestroy();
}

onCreate():首次创建 Activity 时调用。在此方法中执行所有正常的静态设置 — 创建视图、将数据绑定到列表等等。始终后接onStart()
onStart():此方法被回调时表示Activity正在启动,此时Activity已处于可见状态,只是还没有在前台显示,因此无法与用户进行交互。可以简单理解为Activity已显示而我们无法看见罢了。onStart()之后如果Activity转入前台,则后接 onResume() 如果 Activity 转入隐藏状态,则后接 onStop()。
onResume():当此方法回调时,则说明Activity已在前台可见,可与用户交互了(处于前面所说的Active/Running形态),onResume方法与onStart的相同点是两者都表示Activity可见,只不过onStart回调时Activity还是后台无法与用户交互,而onResume则已显示在前台,可与用户交互。始终后接onPause()
onPause():当前 Activity正在停止(Paused形态),系统即将开始继续另一个Activity时会调用此方法。 它应该非常迅速地执行所需操作,因为它返回后,下一个 Activity 才能继续执行。 如果 Activity 返回前台,则后接 onResume(),如果 Activity 转入对用户不可见状态,则后接 onStop()。
onStop():在 Activity 对用户不再可见时调用。如果 Activity 被销毁或另一个Activity 继续执行并将其覆盖,就可能发生这种情况。如果Activity恢复与用户的交互,则后接onRestart(),如果Activity被销毁则后接onDestroy()
onDestroy():在 Activity 被销毁前调用。这是 Activity 将收到的最后调用。当 Activity 结束(有人对 Activity 调用了 finish()),或系统为节省空间而暂时销毁该 Activity 实例时,可能会调用它。
onRestart():在 Activity 已停止并即将再次启动前调用。后接onStart()

onWindowFocusChanged
当前activity的窗口获得或失去焦点的时候会调用。(activity是否对用户可见)

大多数情况下只要调用了onResume 就会调用 onWindowFocusChanged,也有例外,比如下拉系统菜单的时候只会调用onWindowFocusChanged。
应用:我们在下拉菜单中改变了网络的状态(开启或者关闭),我们这时候就不能在onResume()中处理更新网络状态,而应该将更新网络状态放到onWindowFocusChanged中处理。

官方解释:
当前activity的窗口获得或失去焦点的时候会调用。
这个函数是最好的方向标对于activity是否对用户可见,它默认的实现是清除键跟踪状态,所以应该总是被调用。
它也提供了全局的焦点状态,它的管理是独立于activity生命周期的。当焦点改变时一般都伴随着生命周期的改变,你不应该依赖onWindowFocusChanged 调用和其他生命周期的方法(例如onResume) 的先后顺序,来处理我们要做的事情。
通常的规则是,当一个activity被唤醒,那么就拥有窗口焦点。除非这个窗口已经显示了对话框或者其他弹出框抢占焦点,这个窗口只有等到这些对话框关闭后,才能获取焦点,同理,当系统显示系统级的窗口,系统级的窗口会临时的获取窗口输入焦点同时不会暂停前景 activity。

横竖屏切换时 Activity 的生命周期
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

注意
当前Activity产生事件弹出Toast和AlertDialog的时候Activity的生命周期不会有改变

三 各种情况下函数调用过程

第一次进入ActivityA:
A | onCreate
A | onStart
A | onResume
A | onWindowFocusChanged | hasFocus:true

下拉系统菜单(已开启程序,从屏幕上往下拉)
A | onWindowFocusChanged | hasFocus:false

收回系统下拉菜单(已开启程序,且下拉菜单已显示)
A | onWindowFocusChanged | hasFocus:true

从ActivityA中退出:
A | onPause
A | onWindowFocusChanged | hasFocus:false
A | onStop
A | onDestory

ActivityA启动ActivityB(普通Activity):
A | onWindowFocusChanged | hasFocus:false
A | onPause
B | onCreate
B | onStart
B | onResume
B | onWindowFocusChanged | hasFocus:true
A | onSaveInstanceState | param: 1
A | onStop

ActivityA启动ActivityB(对话框Activity):
A | onWindowFocusChanged | hasFocus:false
A | onPause
B | onCreate
B | onStart
B | onResume
B | onWindowFocusChanged | hasFocus:true

从AcitivityB(普通Activity)返回到ActivityA:
B | onPause
A | onRestart
A | onStart
A | onResume
A | onWindowFocusChanged | hasFocus:true
B | onWindowFocusChanged | hasFocus:false
B | onStop
B | onDestory

从ActivityB(对话框Activity)返回到ActivityA:
B | onPause
A | onResume
A | onWindowFocusChanged | hasFocus:true
B | onWindowFocusChanged | hasFocus:false
B | onStop
B | onDestory

手机黑屏时:
A | onPause
A | onSaveInstanceState | param: 1
A | onStop
A | onWindowFocusChanged | hasFocus:false

手机亮屏时:
A | onWindowFocusChanged | hasFocus:true
A | onRestart
A | onStart
A | onResume

按home键(已启动ActivityA)
A | onPause
A | onWindowFocusChanged | hasFocus:false
A | onSaveInstanceState | param: 1
A | onStop

多任务切回程序(开启程序,home键切换程序到后台)
A | onRestart
A | onStart
A | onResume
A | onWindowFocusChanged | hasFocus:true

点击应用图标重启程序(开启程序,home键切换到后台)
A | onRestart
A | onStart
A | onResume
A | onWindowFocusChanged | hasFocus:true

点击back键(已开启程序,back键未自己处理)
A | onPause
A | onWindowFocusChanged | hasFocus:false
A | onStop
A | onDestory

点击多任务键(已开启程序)
A | onWindowFocusChanged | hasFocus:false
A | onPause
A | onSaveInstanceState | param: 1
A | onStop

切回程序(已开启程序,且已点击多任务键)
A | onRestart
A | onStart
A | onResume
A | onWindowFocusChanged | hasFocus:true

四 常见的Activity

//1.拨打电话
// 给移动客服10086拨打电话
Uri uri = Uri.parse(“tel:10086”);
Intent intent = new Intent(Intent.ACTION_DIAL, uri);
startActivity(intent);

//2.发送短信
// 给10086发送内容为“Hello”的短信
Uri uri = Uri.parse(“smsto:10086”);
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
intent.putExtra(“sms_body”, “Hello”);
startActivity(intent);

//3.发送彩信(相当于发送带附件的短信)
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(“sms_body”, “Hello”);
Uri uri = Uri.parse(“content://media/external/images/media/23”);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setType(“image/png”);
startActivity(intent);

//4.显示地图:
// 打开Google地图中国北京位置(北纬39.9,东经116.3)
Uri uri = Uri.parse(“geo:39.9,116.3”);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

//5.多媒体播放:
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse(“file:///sdcard/foo.mp3”);
intent.setDataAndType(uri, “audio/mp3”);
startActivity(intent);

//获取SD卡下所有音频文件,然后播放第一首=-=
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, “1”);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

//6.打开摄像头拍照:
// 打开拍照程序
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 0);
// 取出照片数据
Bundle extras = intent.getExtras();
Bitmap bitmap = (Bitmap) extras.get(“data”);

//另一种:
//调用系统相机应用程序,并存储拍下来的照片
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
time = Calendar.getInstance().getTimeInMillis();
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment
.getExternalStorageDirectory().getAbsolutePath()+"/tucue", time + “.jpg”)));
startActivityForResult(intent, ACTIVITY_GET_CAMERA_IMAGE);

//7.打开Google Market
// 打开Google Market直接进入该程序的详细页面
Uri uri = Uri.parse(“market://details?id=” + “com.demo.app”);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

//8.进入手机设置界面:
// 进入无线网络设置界面(其它可以举一反三)
Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
startActivityForResult(intent, 0);

//9.安装apk:
Uri installUri = Uri.fromParts(“package”, “xxx”, null);
returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);

//10.卸载apk:
Uri uri = Uri.fromParts(“package”, strPackageName, null);
Intent it = new Intent(Intent.ACTION_DELETE, uri);
startActivity(it);

//11.进入联系人页面:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(People.CONTENT_URI);
startActivity(intent);

//12.查看指定联系人:
Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, info.id);//info.id联系人ID
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(personUri);
startActivity(intent);

五 Activity使用

知晓当前是哪个Activity
在这里插入图片描述

随时关闭所有Activity
有时我们可能会打开了很多个Activity,突然来个这样的需求,在某个页面可以关掉 所有的Activity并退出程序!好吧,下面提供一个关闭所有Activity的方法, 就是用一个list集合来存储所有Activity!

public class ActivityCollector {  
    public static LinkedList<Activity> activities = new LinkedList<Activity>();  
    public static void addActivity(Activity activity)  
    {  
        activities.add(activity);  
    }  
    public static void removeActivity(Activity activity)  
    {  
        activities.remove(activity);  
    }  
    public static void finishAll()  
    {  
        for(Activity activity:activities)  
        {  
            if(!activity.isFinishing())  
            {  
                activity.finish();  
            }  
        }  
    }  
}  

完全退出App的方法
上面说的是关闭所有Activity的,但是有些时候我们可能想杀死整个App,连后台任务都杀死 杀得一干二净的话,可以使用搭配着下述代码使用:

/** 
 * 退出应用程序 
 */  
public void AppExit(Context context) {  
    try {  
        ActivityCollector.finishAll();  
        ActivityManager activityMgr = (ActivityManager) context  
                .getSystemService(Context.ACTIVITY_SERVICE);  
        activityMgr.killBackgroundProcesses(context.getPackageName());  
        System.exit(0);  
    } catch (Exception ignored) {}  
}  

双击退出程序的两种方法:
1)定义一个变量,来标识是否退出

// 定义一个变量,来标识是否退出
private static boolean isExit = false;
Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        isExit = false;
    }
};

public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        if (!isExit) {
            isExit = true;
            Toast.makeText(getApplicationContext(), "再按一次退出程序",
                    Toast.LENGTH_SHORT).show();
            // 利用handler延迟发送更改状态信息
            mHandler.sendEmptyMessageDelayed(0, 2000);
        } else {
            exit(this);
        }
        return false;
    }
return super.onKeyDown(keyCode, event);
}

2)保存点击时间:

//保存点击的时间
private long exitTime = 0;
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        if ((System.currentTimeMillis() - exitTime) > 2000) {
            Toast.makeText(getApplicationContext(), "再按一次退出程序",
                    Toast.LENGTH_SHORT).show();
            exitTime = System.currentTimeMillis();
        } else {
                        exit();
                      }
        return false;
    }
        return super.onKeyDown(keyCode, event);
}

六 Activity四种加载模式

standard模式:
标准启动模式,也是activity的默认启动模式。在这种模式下启动的activity可以被多次实例化,即在同一个任务中可以存在多个activity的实例,每个实例都会处理一个Intent对象。如果Activity A的启动模式为standard,并且A已经启动,在A中再次启动Activity A,即调用startActivity(new Intent(this,A.class)),会在A的上面再次启动一个A的实例,即当前的桟中的状态为A–>A。

singleTop模式:
如果一个以singleTop模式启动的Activity的实例已经存在于任务栈的栈顶, 那么再启动这个Activity时,不会创建新的实例,而是重用位于栈顶的那个实例, 并且会调用该实例的onNewIntent()方法将Intent对象传递到这个实例中。 举例来说,如果A的启动模式为singleTop,并且A的一个实例已经存在于栈顶中, 那么再调用startActivity(new Intent(this,A.class))启动A时, 不会再次创建A的实例,而是重用原来的实例,并且调用原来实例的onNewIntent()方法。 这时任务栈中还是这有一个A的实例。如果以singleTop模式启动的activity的一个实例 已经存在与任务栈中,但是不在栈顶,那么它的行为和standard模式相同,也会创建多个实例。

singleTask模式:
只允许在系统中同一个Task有一个Activity实例。如果系统中已经有了一个实例, 持有这个实例的任务将移动到顶部,同时intent将被通过onNewIntent()发送。 如果没有,则会创建一个新的Activity并置放在合适的任务中。

singleInstance模式
保证系统无论从哪个Task启动Activity都只会创建一个Activity实例,并将它加入新的Task栈顶 也就是说被该实例启动的其他activity会自动运行于另一个Task中。 当再次启动该activity的实例时,会重用已存在的任务和实例。并且会调用这个实例 的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同, 同一时刻在系统中只会存在一个这样的Activity实例。

七 Activity拾遗

使用命令行查看当前所有Activity的命令:
使用下述命令即可,前提是你为SDK配置了环境变量:adb shell dumpsys activity

设置Activity全屏的方法:
1)代码隐藏ActionBar
在Activity的onCreate方法中调用getActionBar.hide();即可

2)通过requestWindowFeature设置
requestWindowFeature(Window.FEATURE_NO_TITLE); 该代码需要在setContentView ()之前调用,不然会报错!!!

3)通过AndroidManifest.xml的theme
在需要全屏的Activity的标签内设置 theme = @android:style/Theme.NoTitleBar.FullScreen

定义对话框风格的Activity
在某些情况下,我们可能需要将Activity设置成对话框风格的,Activity一般是占满全屏的, 而Dialog则是占据部分屏幕的!实现起来也很简单!

直接设置下Activity的theme:
android:theme="@android:style/Theme.Dialog"

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值