美文网首页Android交流
Android进阶面试题之Activity干货篇

Android进阶面试题之Activity干货篇

作者: 帅次 | 来源:发表于2021-07-28 11:49 被阅读0次
    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中声明

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.scc.demo">
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.Demo">
            <activity
                android:name=".actvitiy.MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
     
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity android:name="com.scc.demo.actvitiy.RedActivity"/>
            <activity android:name="com.scc.demo.actvitiy.BlueActivity"/>
        </application>
    </manifest>
    

    在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

    <activity android:name="com.scc.demo.actvitiy.RedActivity"
       >
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data
                android:host="scc"
                android:path="/redActivity"
                android:port="2021"
                android:scheme="sccdemo" />
        </intent-filter>
    </activity>
    

    2.调用

    2.1、在html中调用

    <a href="sccdemo://scc:2021/redActivity?color=0000&ad=10086">打开源生应用指定的RedActivity</a>
    

    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<String> 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中的<activity>中配置: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干货篇

        本文链接:https://www.haomeiwen.com/subject/xkkzmltx.html