Android进阶面试题之Activity干货篇

Activity知识点.png

Activity是什么

Activity是Android四大组件之一,它提供一个界面让用户点击和各种滑动操作,这就是Activity。

Activity生命周期

image.png

onCreate():你必须实现此回调,它会在系统创建你的 Activity 时触发。你的实现应该初始化Activity的基本组件。

onStart():此回调包含 Activity 进入前台与用户进行互动之前的最后准备工作。到了这一步用户可见不可交互。

onResume():此时,该Activity位于Activity堆栈的顶部,并会捕获所有用户输入。应用的大部分核心功能都是在onResume()方法中实现的。到了这一步用户可见可交互。

onPause():当用户点按"返回"或"最近使用的应用"按钮时,Activity失去焦点并进入"已暂停"状态时,系统就会调用onPause()。到这一步用户可见不可交互。系统会停止动画等消耗CPU的操作。

onStop():到了这一步用户不可见。停止动画和刷新UI等。

onRestart():当处于"onStop()"状态的Activity即将重启时,系统就会调用此回调。onRestart()会从Activity停止时的状态恢复Activity至运行状态。

onDestroy():这是Activity最后一个方法。可以用isFinishing()来判断它,如果有dialog在运转,要在这个界面将dialog给cancel掉,不然抛异常。

Activity主要的四种状态

image.png

Running(运行):在屏幕前台(位于当前任务堆栈的顶部)

Paused(暂停):失去焦点但仍然对用户可见(覆盖Activity可能是透明或未完全遮挡)

Stopped(停止):完全被另一个Activity覆盖

Destroyed(销毁):退出,完全销毁

Activity栈(先进后出)

多个Activity运行时,Android 是通过一种 Activity 栈的方式来管理 Activity 的,一个 Activity 的实例的状态决定它在栈中的位置。
处于前台的 Activity 总是在栈的顶端,当前台的 Activity 因为异常或其它原因被销毁时,处于栈第二层的 Activity 将被激活,上浮到栈顶。
当新的 Activity 启动入栈时,原 Activity 会被压入到栈的第二层。
一个 Activity 在栈中的位置变化反映了它在不同状态间的转换。


image.png

启动Activity

1.简单启动

在AndroidManifest.xml中声明



    
        
            
                
 
                
            
        
        
        
    

在MainActivity.java中启动

Intent intent = new Intent(MainActivity.this,RedActivity.class);
startActivity(intent);

2.数据传递

2.1简单数据传递
MainActivity.class

Intent intent = new Intent(MainActivity.this,BlueActivity.class);
intent.putExtra("scc","aiyouyou");
startActivity(intent);

BlueActivity.class

Log.e(getClass().getName(),getIntent().getStringExtra("scc"));
打印结果:aiyouyou

2.2复杂数据传递

2.2.1使用数据包Bundle
MainActivity.class

Intent intent = new Intent(MainActivity.this,BlueActivity.class);
Bundle bundle = new Bundle();
bundle.putString("scc","heiha");
bundle.putString("size","18");
intent.putExtras(bundle);
startActivity(intent);

BlueActivity.class

Intent intent = getIntent();
Bundle bundle = intent.getExtras();
Log.e(getClass().getName(),bundle.getString("scc")+":"+bundle.getString("size"));

运行结果:

heiha:18

2.2.2使用Serializable(序列化)

2.2.2.1创建一个实体类User implements Serializable

MainActivity.class

Intent intent = new Intent(MainActivity.this,BlueActivity.class);
intent.putExtra("user",new User("帅次","男",20));
startActivity(intent);

BlueActivity.class

User user = (User)getIntent().getSerializableExtra("user");
Log.e(getClass().getName(),user.getName()+":"+user.getGender()+user.getAge());

运行结果:

帅次:男20

3.启动带返回值

启动的MainActivity.java

Intent intent = new Intent(MainActivity.this,BlueActivity.class);
intent.putExtra("scc","俺来咧");
startActivityForResult(intent,998);
Log.e(getClass().getName(),"startActivityForResult");
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Log.e(getClass().getName(),"requestCode:"+requestCode+":resultCode:"+resultCode);
    //启动ActivityCode值998,回传ActivitiyCode值500
    if(requestCode==998&&resultCode==500){
        Log.e(getClass().getName(),"Intent data:"+data.getStringExtra("scc_result"));
    }
}

被启动的BlueActvitiy.java

Log.e(getClass().getName(),getIntent().getStringExtra("scc"));
btn_back.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.e(getClass().getName(),"onClick.setResult");
        Intent intent = new Intent();
        intent.putExtra("scc_result", "恕瑞玛你们的皇帝回来啦");
        setResult(500, intent);
        finish();
    }
});

运行结果:

点击MainActivity启动按钮
MainActivity$1: startActivityForResult
BlueActivity: 俺来咧
点击BlueActvitiy返回按钮
lueActivity$1: onClick.setResult
requestCode:998:resultCode:500
Intent data:恕瑞玛你们的皇帝回来啦
这就算完事了。

注意:requestCode不能等于resultCode,否则回传会失效。

Activity的启动模式(launchMode)

Activity启动模式.png

standard:每次激活Activity时(startActivity),都创建Activity实例,并放入任务栈;

image.png

singleTop:如果某个Activity自己激活自己,即任务栈栈顶就是该Activity,则不需要创建,其余情况都要创建Activity实例;

image.png

singleTask:如果要激活的那个Activity在任务栈中存在该实例,则不需要创建,只需要把此Activity放入栈顶。并调用其onNewIntent();

image.png

singleInstance:应用1的任务栈中创建了MainActivity实例,如果应用2也要激活MainActivity,则不需要创建,两应用共享该Activity实例。

image.png

进程的优先级

1. 前台进程(Foreground process)。它表明用户正在与该进程进行交互操作优先级是最高的。Android系统依据下面的条件来将一个进程标记为前台进程:

  • 该进程持有一个用户正在与其交互的Activity(也就是这个activity的生命周期方法走到了onResume()方法)。

  • 该进程持有一个正在执行生命周期方法(onCreate()、onStart()、onDestroy())的Service。

  • 该进程持有一个正在执行onReceive()方法的BroadcastReceiver。

2、可见进程(Visible process)。它表明虽然该进程没有持有任何前台组件,但是它还是能够影响到用户看得到的界面。android系统依据下面的条件将一个进程标记为可见进程:

  • 该进程持有一个非前台Activity,但这个Activity依然能被用户看到(也就是这个Activity调用了onPause()方法)。例如,当一个activity启动了一个对话框,这个activity就被对话框挡在后面。

  • 该进程持有一个正在执行方法Service.startForeground()的Service。

3、服务进程(Service process)。除了符合前台进程和可见进程条件的Service,其它的Service都会被归类为服务进程。

4、后台进程(Background process)。持有不可见Activity(调用了onStop()方法)的进程即为后台进程。通常情况下都会有很多后台进程,当内存不足的时候,在所有的后台进程里面,会按照LRU(最近使用)规则,优先回收最长时间没有使用过的进程。

5、空进程(Empty process)。不持有任何活动组件的进程。保持这种进程只有一个目的,就是为了缓存,以便下一次启动该进程中的组件时能够更快响应。当资源紧张的时候,系统会平衡进程缓存和底层的内核缓存情况进行回收。

  • 这些进程通常包含用户当前不可见的一个或多个Activity实例(onStop()方法已被调用并返回)。

scheme跳转协议

1、android中的scheme是一种页面内跳转协议,通过定义自己的scheme协议,可以跳转到app中的各个页面

2、服务器可以定制化告诉app跳转哪个页面

3、App可以通过跳转到另一个App页面

4、可以通过H5页面跳转页面

样例:

1.在AndroidManifest.xml中对activity标签增加intent-filter设置Schema


    
        
        
        
        
    

2.调用

2.1、在html中调用

打开源生应用指定的RedActivity

2.2、应用内调用

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("sccdemo://scc:2021/redActivity?color=0000&ad=10086"));
startActivity(intent);

2.3、获取Url和其他参数

Intent intent = getIntent();
Uri data = intent.getData();
String action = intent.getAction();
String scheme = intent.getScheme();
Set categories = intent.getCategories();
Log.e("SCHEME", "data:"+data);
Log.e("SCHEME", "action:"+action);
Log.e("SCHEME", "categories:"+categories);
Log.e("SCHEME", "DataString:"+intent.getDataString());
Log.e("SCHEME", "-------------------");
Log.e("SCHEME", "scheme:"+scheme);
Log.e("SCHEME", "id:"+data.getQueryParameterNames());
Log.e("SCHEME", "host:"+data.getHost());
Log.e("SCHEME", "path:"+data.getPath());
Log.e("SCHEME", "port:"+data.getPort());

Android本身API并未声明会抛出异常,则其在运行时有无可能抛出Runtime异常,你遇到过吗?有的话会导致什么问题?如何解决?

会。比如NullPointerException。我遇到过,比如textview.setText()时,textview没有初始化。会导致程序无法正常运行出现forceclose(当前应用程序发生了冲突NullPointExection(空指针),IndexOutOfBoundsException(角标越界)等等一系列未捕获异常)。打开控制台查看logcat信息找出异常信息并修改程序。

如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?

重写onSaveInstanceState()方法,在此方法中保存需要保存的数据,该方法将会在activity被回收之前调用。通过重写onRestoreInstanceState()方法可以从中提取保存好的数据(建议你将保存的状态保持在50k数据以下)。

将Activity设置成窗口的样式

在AndroidMainfest.xml中的中配置:android:theme="@android:style/Theme.Dialog" ,另外 android:theme="@android:style/Theme.Translucent"是设置透明。

退出Activity?退出已调用多个Activity的Application?

对于单个 activity退出:

单一Activity的应用来说,退出很简单,直接 finish()即可。也可以用 killProcess()和 System.exit()这样的方法。

对于多个 activity同时退出:

1、抛异常强制退出:该方法通过抛异常,使程序Force Close。但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。

2、记录打开的 Activity:每打开一个Activity就记录下来。在需要退出时关闭每一个Activity即可。

3、发送特定广播:在需要结束应用时,发送一个特定的广播,每个 Activity 收到广播后,关闭即可。

4、递归退出在打开新的 Activity 时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。

为了编程方便,最好定义一个Activity基类,处理这些共通问题。

Activity之间使用Intent传递大量数据带来问题

Intent在传递数据时是有大小限制的,这里官方并未详细说明,不过通过实验的方法可以测出数据应该被限制在1MB(1024KB)以内,发现当数据大小超过1MB的时候,程序就会出现闪退、停止运行等异常(不同的手机反应不同),因此可以判断Intent的传输容量在1MB以内,但是根据不同版本、不同厂商,这个值会有区别。

解决方案如下:

1、减少通过 Intent 传递的数据,将非必须字段使用 transient 关键字修饰。

2、将对象转化为 JSON 字符串,减少数据体积。因为 JVM 加载类通常会伴随额外的空间来保存类相关信息,将类中数据转化为 JSON 字符串可以减少数据大小。

横竖屏切换时候activity的生命周期?

1、不设置Activity的android:configChanges,横、竖屏切换时都会重新调用各个生命周期。

2、设置Activity的android:configChanges="orientation",横、竖屏切换时都会重新调用各个生命周期。

3、设置Activity的android:configChanges="orientation|screenSize",横、竖屏切换时不会重新调用各个生命周期。仅执行onConfigurationChanged()方法。

你可能感兴趣的:(Android进阶面试题之Activity干货篇)