欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android面试知识点汇总(一)

程序员文章站 2022-04-11 18:15:56
...

Android基础

一、Activity相关

1.Activity生命周期

  • Activity是与用户交互的接口
  • Android系统通过Activity栈的形式来管理Activity
  • Active/Paused/Stopped/Killed

正常情况下回调方法:

  • onStart()回调表示可见但无法与用户交互。
  • onResume()回调表示处于前台,可见且可与用户交互。
  • onPause()表示正在停止,与onResume()成对出现。
  • onStop()在onPause()执行完以后立即执行,表示即将停止或完全由一个新的Activity覆盖,此时Activity不可见,只能在后台运行。
  • onCreate()与onDestroy()成对出现,前者进行初始化,后者做回收、资源释放工作。
  • onRestart()是当Activity由onStop()变为onStart()方法之间回调。

异常情况下(系统配置发生改变或内存不足等情况下,Activity异常终止时)系统回调方法:

  • onSaveInstanceState(Bundle outState)保存当前Activity状态信息,用此方法恢复数据是需进行Bundle非空判断。
  • onRestoreInstanceState(Bundle savedInstanceState),当Activity被重新创建后调用,Bundle为非空,不需进行非空判断。

总结

  1. Activity正常启动:onCreate-onStart-onResume
  2. 点击back回退:onPause-onStop-onDestroy
  3. 打开新的Activity:onPause-onStop
  4. Activity异常:onSaveInstanceState保存数据
  5. Activity重新创建:调用onRestoreInstanceState

2.Activity通信

Activity之间通信的三种方式:Intent/Bundle、类静态变量、全局变量

Activity与Fragment通信:Bundle、直接在Activity中定义方法

利用Bundle,Activity将数据传到依附它的Fragment上:

public class FragmentActivity1 extends Activity {
    public String productId;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle bundle = new Bundle();
        bundle.putString(Constant.NTENT_D,productId);
        Fragment fragment = null;
        fragment.setArguments(bundle);
    }
}
public class Fragment1 extends Fragment {
    public String productId;
    @Override
    public void onStart() {
        super.onStart();
        if (isAdded()){//判断Fragment是否已经依附Activity
            productId = getArguments().getString(Constant.NTENT_D);
        }
    }
}

通过定义方法通信: 

public class FragmentActivity2 extends Activity {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    public String getTitles(){
        return "getTitle";
    }
}
public class Fragment2 extends Fragment {
    public String titles;
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        titles = ((FragmentActivity2) activity).getTitle();
    }
}

Fragment与Activity通信:接口回调

  1. 在fragment中定义一个内部回调接口,使包含此fragment的Activity实现这个接口,则fragment可调用此接口传递数据
  2. 当fragment添加到Activity中时调用fragment生命周期方法中的onAttach()方法,可在此方法中检查相应Activity是否实现了fragment中定义的内部接口。即对它类型转换,赋值给fragment中对应的内部接口
  3. 调用onDetach时,要将传递进来的activity对象释放掉
public class Fragment3 extends Fragment implements View.OnClickListener{
    // 定义用来与外部activity交互,获取到宿主activity
    private FragmentListener listener;

    // 定义了所有activity必须实现的接口方法
    public interface FragmentListener {
        void process(String str);
    }

    // 当Fragment被加载到activity的时候会被回调


    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        if (activity instanceof FragmentListener) {
            listener = (FragmentListener)activity;
        } else {
            throw new IllegalArgumentException("activity must implement fragment interface");
        }
    }

    @Override
    public void onClick(View v) {
        listener.process("我是接口");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        listener = null;
    }
}

二、事件分发机制

核心方法

  • dispatchTouchEvent()
  • onInterceptTouchEvent()
  • onTouchEvent()

Android面试知识点汇总(一)

1.Activity事件分发

Android面试知识点汇总(一)
Activity事件分发示意图

2.ViewGroup事件分发 

 

Android面试知识点汇总(一)
ViewGroup事件分发示意图

3.View事件分发 

 

Android面试知识点汇总(一)
View事件分发示意图

三、异步消息处理机制相关面试问题

1.Handler

Android面试知识点汇总(一)
Handler四大组件和运作机制

首先在主线程中为主线程创建Looper(Looper为线程持有),同时在Looper内部创建一个消息队列(MessageQueue对象)。当创建Handler时会取出当前线程的Looper,通过这个Looper不断轮询消息队列中的Message。Handler在子线程中发送消息的实质就是在MessageQueue中添加一条Message,最后通过Looper中的消息循环取得Message再交给Handler进行处理。

分析源码可知:

  • 创建Handler对象时如果Looper为空则会抛出异常。因为Handler发送消息必须发送到指定的消息队列中,而消息队列由Looper管理,所以创建Handler对象必须在当前线程中有指定Looper对象。
  • 消息队列核心方法为插入队列enqueueMessage()和读取和删除next(),内部由单链表实现。
  • 为确保每一个线程获取到的Looper都是唯一的,Looper.prepare()方法内部用sThreadLocal容器来保存Looper对象本身。ThreadLocal也称为线程本地变量,它为每个变量在每个线程都创建一个数据副本。

2.AsyncTask

Handler+线程池。使用线程池的主要原因是避免不必要的创建和销毁线程的开销。

分析源码可知:

  • 手机CPU核数(CPU_COUNT)+1作为AsyncTask线程使用的线程数核心(CORE_POOL_SIZE)大小,CPU核数*2+1作为线程池最线程数(MAXIMUM_POOL_SIZE)大小,线程池为静态。
  • 创建了ThreadFactory实例用于创建线程池,其中mCount变量为原子类型,为保证后面获得此数据时线程安全。
  • AsyncTask内部串行执行任务。
  • (未完待续)