Android面试基础题详解1

本文深入解析了安卓开发中的关键概念,包括ANR的原理及预防措施、Activity的生命周期管理、Fragment的功能与使用技巧、Service的工作机制及其启动方式的区别。通过详实的例子帮助开发者更好地理解和运用这些核心组件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于ANR

一、什么是ANR?

ANR就是Application Not Responding,是安卓中弹出的一个对话框,让用户来选择等待或者直接关闭程序。activity响应超过5秒,service响应超过10秒,都会出现ANR。

二、ANR产生的原因

刚才也说了,activity响应超过5秒,service响应超过10秒,都会出现ANR。那么为什么activity或者service会用这么长时间来响应呢?最大的原因可能就是主线程被阻塞了。所以产生ANR的原因有以下两个:

  • 主线程中存在耗时的计算
  • 主线程被IO操作阻塞(安卓4.0以后,网络IO禁止在主线程执行)

那么安卓中有哪些是在主线程中执行的呢?

  • activity的所有生命周期方法;
  • service默认是在主线程的;、
  • broadcast中的onReceive()回调方法;
  • AsyncTask中除了doInBackgroud方法,其他的四个方法都是在主线程中的;
  • Handler的handleMessage()和post(Runnable)方法,前提是这个Handler没有使用子线程的looper。

基本上就是这么多,所以在上述这些方法中是绝对不能做耗时操作的,否则就会出现ANR异常。

三、怎么避免ANR?

避免ANR的总方针就是不要阻塞主线程,具体的方法有以下这些:

  • 使用AsyncTask来进行耗时操作;
  • 使用Thread或者HandlerThread来提高线程优先级;
  • 使用Handler来处理工作线程;
  • 不要在Activity中执行耗时的计算。

一般做到以上几步就可以避免ANR了。


      关于Activity

一、简述一下Activity的生命周期

  • 首先在回答这个问题之前,我们先来说一下什么是Activity。 
    • Activity是安卓中与用户进行交互的接口,它提供了一个界面,可以让用户进行点击、滑动等一系列操作。
  • 在了解了activity是什么以后,我们还必须了解一下activity的四种状态 
    • running状态:这时activity处于活跃状态,用户可以与其进行交互,可以进行点击、滑动等操作,界面会做出响应。
    • pause状态:这时activity处于可见状态,但是失去触摸的能力。一般activity被一个透明的activity或者非全屏的activity覆盖,此时被覆盖的activity就处于pause状态。如果内存紧张,会被系统回收。
    • stop状态:此时的activity处于完全不可见状态。一般是被另一个activity完全覆盖时,被覆盖的activity处于的状态。如果内存紧张,会被系统回收。
    • killed状态:此时的activity已经被系统回收,它保存的信息以及成员变量都会被销毁。

在了解了以上内容以后,我们就可以来说一下activity的生命周期了。

activity一共有7个生命周期方法。

  • 当activity启动的时候,它会经过如下生命周期方法,依次是:onCreate()–>onStart()–>onResume() 
    • onCreate():一般是完成界面以及数据的初始化工作,是activity启动时第一个被调用的方法。
    • onStart():此时的activity处于可见状态,但是还不可以与用户进行交互。
    • onResume():此时的activity已经完全完成加载动作,用户可以对其进行滑动、点击等操作。
  • 当点击Home键返回主界面的时候,此时的activity处于不可见状态了,它会经过以下生命周期方法:onPause()–>onStop() 
    • onPause():此时activity还是处于可见状态的,但是已经失去与用户进行交互的能力了。与之对应的是onResume()方法。
    • onStop():此时的activity处于完全不可见状态了。
  • 再次返回原Activity,由于之前已经缓存过activity,所以再次回来不会走onCreate()方法,它的生命周期方法如下:onRestart()–>onStart()–>onResume() 
    • onRestart():从缓存中重新加载activity会走此方法。
  • 退出activity,它会走如下生命周期方法:onPause()–>onStop()–>onDestroy() 
    • onDestroy():走到该方法表示activity已经被销毁了,它的成员变量等已经被系统回收了。

二、Android任务栈

任务栈是后进先出的栈结构,Android通过任务栈可以有序管理每一个Activity。任务栈并不是唯一的,一个App中可以有多个任务栈,但是,在某些情况下,一个Activity也可以独享一个任务栈。

三、activity有几种启动模式,各有什么区别?

1.Standard模式 :每次启动Activity都会创建一个Activity实例,加入任务栈中,不会考虑任务栈中是否有相同的Activity。较为消耗资源。

2.SingleTop模式 :栈顶复用模式,如果新创建的Activity与当前的Activity一致,处于栈顶的话,就不会创建新的Activity,而是复用栈顶的Activity。

3.SingleTask模式 :任务栈复用模式,在新建Activity之前会检测任务栈中是否有相同的Activity,有的话直接把Activity移到栈顶,这个Activity以上的Activity都会被移除和销毁;没有就新建一个。

4.SingleInstance模式 :在整个系统中,有且只有一个实例,而且这个Activity独享任务栈。

四、Android进程优先级

1.前台进程 :处于前台正在与用户进行交互的Activity,或者在前台绑定的Service。

2.可见进程 :可见但不可交互的Activity。

3.服务进程 :在后台开启的Service就是服务进程。

4.后台进程 :当处于前台的Activity,被按下Home键之后,该Activity会变成后台进程,但后台进程不会被立马销毁,系统会根据内存情况进行相应的回收。

5.空进程 :表示没有活跃的组件,只是出于缓存的目的而保留,可被随时收回。

五、Scheme跳转模式

android中的scheme是一种页面内跳转协议,是一种非常好的实现机制,通过定义自己的scheme协议,可以非常方便跳转app中的各个页面;通过scheme协议,服务器可以定制化告诉app跳转哪个页面,可以通过通知栏消息定制化跳转页面,可以通过H5页面跳转页面等。


关于Fragment

一、Fragment为什么被称为第五大组件?

首先在使用频率上,fragment不低于其他四大组件,而且它有自己的生命周期。使用fragment比activity更加节省内存,同时,它可以很灵活的加载到activity中,所以它被称为第五大组件。虽然它有自己的生命周期,但是它必须依附于宿主activity存在。

二、Fragment加载到activity中的两种方式?

  • 静态加载:在activity的布局文件中以标签的形式添加fragment。
  • 动态加载:在java文件中以代码的形式加载fragmet。 
    • 1、获取FragmentManager管理者对象;
    • 2、通过上述对象的beginTranscation()方法创建FragmentTranscation对象;
    • 3、通过transcation对象的add()/remove()/replace()/hide()/show()等方法来显示或者移除fragment;
    • 4、通过transcation对象的commit()方法来提交。

总结起来就是如下两行代码: 
getFragmentManager().beginTranscation().add() 
getFragmentManager().beginTranscation().commit()

注意: 
1、同一个fragment只能被add一次; 
2、同一个transcation只能被提交一次; 
3、transcation.addToBackStack(null)将碎片添加到返回栈中,此时按下返回键,不会退出程序,而是返回上一个碎片。

三、fragmentPagerAdapter和fragmentStatePagerAdapter的区别?

fragmentPagerAdapter在destroyItem()的时候调用的是detach()方法,只是把UI进行了分离,并没有真正的移除fragment,所以只适用于页面较少的情况。而fragmentStatePagerAdapter在切换页面的时候调用的是remove()方法,是真正回收内存的,所以它适用于页面较多的情况。

四、fragment的生命周期?

onAttach()–>onCreate()–>onCreateView()–>onViewCreate()–>activity.onCreate()–>onActivityCreate()–>activity.onStart()–>activity.onResume()–>activity.onPause()–>activity.onStop()–>onDestroyView()–>onDetach()

这里写图片描述

五、fragment与activity之间的传值通信?

1、fragment向activity之间的传值:

  • 在fragment中通过getActivity()获取activity的对象,然后调用activity中的方法;
  • 接口回调:在fragment中设置一个接口,然后让activity实现这个接口,这样就可以在接口中将数据传递给activity.

2、activity向fragment传值:

  • 在 activity中创建Bundle数据包,通过putExtra()方法将数据放进去,然后调用fragment对象的setArguments(bundle)方法,在fragment中就可以通过getArguments()方法获取数据。
  • 在activity中通过getFragmentManager.findFragmentById()获取fragment对象,然后就可以调用fragment的方法了。

3、fragment与fragment传值:

  • 在第一个fragment中调用getActivity().getFragmentManager().findFragmentById()获取第二个fragment的对象,然后调用第二个fragment中的方法;
  • 接口回调:在fragment1中设置一个接口,宿主activity实现这个接口,fragment1在接口中与activity实现通信,然后在activity中的回调方法中,实现与fragment2的通信。

总结:fragment与activity通信的关键点就是要拿到对方的对象,fragment通过getActivity()获取activity的对象,activity通过getFragmentManager().getFragmentById()来获取fragment对象。fragment与activity之间可以直接通信,而fragment之间必须通过activity这个宿主来实现通信。


关于service

一、什么是Service?

Service是一个可以在后台长时间运行操作而且没有用户界面的组件。它是运行在主线程中的,所以不能在Service中执行耗时操作。它可以由其他组件来启动,比如activity或者broadcast,服务一旦启动,就会一直在后台运行,即使启动它的组件被销毁了,也不会影响它的运行。我们可以把service和activity进行绑定,这样就可以实现两者之间的数据交互。

二、service和thread的区别?

  • 定义:thread是程序运行的最小单元,我们可以通过开启子线程来完成一些耗时操作,而service是后台服务,是安卓中的一种机制,如果是本地的service,那么它就运行在它所在的主线程,所以service中不能进行耗时操作。
  • 实际开发:不能在service中进行耗时操作,如果一定要进行,那么也必须要开启子线程,那为什么不在activity中开启子线程呢?因为activity很难对子线程进行把控,一旦activity销毁了,那么将很难获得子线程的实例,容易造成内存泄漏。而service不一样,即使activity被销毁了,service依然可以在后台执行。
  • 应用场景:如果我们需要进行耗时操作,那么就必须要开启子线程。而service是需要长时间在后台运行,并且不需要用户界面的情况下才会使用,比如后台播放音乐,天气预报的统计等。

三、service的两种启动方式以及区别?

  • startService:通过此种方式启动的服务,会一直在后台运行,除非手动关闭。 
    • 执行步骤如下:
    • 1、定义一个类继承service;
    • 2、在manifest.xml文件中注册service;
    • 3、使用context的startService()启动服务;
    • 4、如果不再使用,调用stopService()方法来停止该服务。
  • bindService:此时service和activity处于绑定状态,两者之间可以进行数据交互。 
    • 执行步骤如下:
    • 定义一个服务端继承service,并且在类中实现IBinder接口的实例对象,并提供公共方法给客户端调用;
    • 在onBind()方法中返回此Binder实例;
    • 客户端在onServiceConnected()方法中接收Binder实例,并通过服务端提供的方法绑定服务。

接下来通过代码来深刻理解两种启动service的方法到底什么区别。

  • 首先是startService
public class StartService extends Service {
    private static final String TAG = "StartService";

    /**
    * 首次创建服务时,系统将调用此方法执行一次性设置程序(在调用onStartCommand()或者onBind()之前),
    * 如果服务已在运行,则不会调用此方法,该方法只被调用一次。
    */

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "StartService Thread id is ==="+Thread.currentThread().getId() );
    }

    /**
    * 绑定服务的时候才会调用
    * 必须要实现的方法
    * @param intent
    * @return
    */

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
    * 每次通过startService()启动Service时都会被回调。
    * @param intent
    * @param flags
    * @param startId
    * @return  return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
    * 如果返回START_STICKY,那么在系统内存空暇时,系统会尝试重新启动服务,而此时的intent为null;
    */

    @Override
    public int onStartCommand(Intent intent,  int flags, int startId) {
        System.out.println("onStartCommand invoke");

        Log.e(TAG, "StartService Thread id is ==="+Thread.currentThread().getId() );

        return super.onStartCommand(intent, flags, startId);
    }

    /**
    * 服务销毁时的回调
    */

    @Override
    public void onDestroy() {
        System.out.println("onDestroy invoke");
        super.onDestroy();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private Button mBtStop,mBtStart,mBtBind;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBtStart= (Button) findViewById(R.id.btn_start);
        mBtStop= (Button) findViewById(R.id.btn_stop);

        Log.e(TAG, "MainActivity thread id is=="+Thread.currentThread().getId() );

        final Intent intent=new Intent(MainActivity.this,StartService.class);

        mBtStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startService(intent);
            }
        });

        mBtStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(intent);
            }
        });



    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

-接下来是bindService

public class BindService extends Service {

    private static final String TAG = "BindService";
    private LocalBinder binder=new LocalBinder();
    private int count;
    private Thread thread;
    private boolean quit;

    /**
    * 创建Binder对象,返回给客户端的Activity使用,提供数据交接的接口
    */
    public class LocalBinder extends Binder{
        //申明一个方法getService(),提供给客户端调用
        BindService getService(){
            //返回当前对象LocalBinder,这样我们就可以在客户端调用Service的公共方法了。
            return BindService.this;
        }
    }

    /**
    * 把Binder类返回给客户端
    * @param intent
    * @return
    */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "Service is invoke Created" );
        thread =new Thread(new Runnable() {
            @Override
            public void run() {
                while (!quit){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count++;
                }
            }
        });
        thread.start();

    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "Service is invoke Destroyed" );
        this.quit=true;
        super.onDestroy();
    }

    /**
    * 公共方法
    * @return
    */
    public int getCount(){
        return count;
    }

    /**
    * 解除绑定时调用
    * @param intent
    * @return
    */
    public boolean onUnbind(Intent intent){
        Log.e(TAG, " Service is invoke onUnbind" );
        return super.onUnbind(intent);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
public class BindActivity extends AppCompatActivity {
    private static final String TAG = "BindActivity";

    private Button btnBind,btnUnBind,btnGetDatas;

    private BindService mService;
    private ServiceConnection conn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bind);

        btnBind= (Button) findViewById(R.id.btn_Bind);
        btnUnBind= (Button) findViewById(R.id.btn_UnBind);
        btnGetDatas= (Button) findViewById(R.id.btn_GetDatas);

        //创建绑定对象
        final Intent intent=new Intent(this,BindService.class);

        //开启绑定
        btnBind.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "绑定调用:bindService" );
                bindService(intent,conn, Service.BIND_AUTO_CREATE);
                Log.e(TAG, "绑定成功");
            }
        });

        //解除绑定
        btnUnBind.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "解除绑定调用:unbindService" );
                if(mService!=null){
                    mService=null;
                    unbindService(conn);
                }
            }
        });

        //获取数据
        btnGetDatas.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mService!=null){
                    //通过绑定服务传递的Binder对象,获取Service暴露出来的数据
                    Log.e(TAG, "从服务器获取数据 "+mService.getCount() );
                }else {
                    Log.e(TAG, "还没有进行绑定,请先绑定");
                }
            }
        });

        /**
        * ServiceConnection代表与服务器的连接,它只有两个方法
        * @param savedInstanceState
        */
        conn=new ServiceConnection(){

            /**
            * 与服务器交互的接口方法,绑定服务的时候被回调,在这个方法中获取绑定Service 传递过来的IBinder对象
            * 通过这个IBinder对象,实现宿主与Sevice的交互
            * @param name
            * @param service
            */
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.e(TAG, "绑定成功调用  onServiceConnected");
                BindService.LocalBinder binder= (BindService.LocalBinder) service;
                mService=binder.getService();
            }

            /**
            * 当取消绑定的时候被回调,但正常情况下式不会被回调的,只有当Service服务被意外销毁时
            * 例如内存不足时这个方法才会被自动调用
            * @param name
            */
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.e(TAG, "绑定失败调用  onServiceDisconnected");
            }
        };

    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值