面试_android基础


1.四大组件

1.1 activity和fragment的通信方式

  1. handler:Activity声明一个handler,fragment保存这个handler实例;
  2. 广播:在 Activity 中注册广播接收器,在 Fragment中发送广播。
  3. 接口回调:fragment定义接口,调用接口中的抽象方法,activity实现这个接口,通过抽象方法参数传递数据。
  4. eventbus:Activity注册订阅者,fragment发送消息
  5. Bundle setArguements()/getArguements()
DiscoverFragment discoverFragment = new DiscoverFragment();
Bundle bundle = new Bundle();
bundle.putString("email", email);
discoverFragment.setArguments(bundle);
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
      View view = inflater.inflate(R.layout.fragment_discover, null);
      Bundle bundle = getArguments();
      //这里就拿到了之前传递的参数
      email = bundle.getString("email");
      return view;
}

1.2 Activity LauncherMode

  • standard:默认启动模式,返回栈中会创建多个activity实例;
  • singletop:创建活动时会先读取返回栈栈顶活动,如果与栈顶活动相同会直接引用,如果不同则创建新activity实例。
  • singleTask:创建活动时会先查询返回栈中是否存在该activity,如果存在则直接引用该activity,并把该activity上的所有活动都出栈。主页
  • singleInstance:活动会启用一个新的返回栈来管理这个活动。

1.3 BroadcastReceiver和LocalBroadcastReceiver

  • BroadcastReceiver:跨应用广播,利用Binder机制实现,支持动态和静态两种方式注册方式。
  • LocalBroadcastReceiver:应用内广播,利用Handler实现,利用了IntentFilter的match功能,提供消息的发布与接收功能,实现应用内通信,效率和安全性比较高,仅支持动态注册。

1.4 Context

定义:应用的运行时环境/应用的上下文

结构:service、activity和application都是context的子类

内存泄漏问题:单例构造器中以context作为参数,activity调用单例传入this,如果acitivity生命周期已经结束,而单例的生命周期没有结束,就会造成activity的内存泄漏。

1.5 IntentFilter是什么?有哪些使用场景

IntentFilter:意图解释器,可以给四大组件配置自己关心的action。例如启动某个activity时

1.6 Service的startService和bindService的生命周期

startService:onCreate-onStartCommand-onDestroy

bindService:onCreate-onBind-onUnBind-onDestroy

onCreate方法在整个生命周期内只会被调用一次,即只存在一个Service实例

如果对一个Service既start了又bind了,则需要调用unBind和stopService方法,onDestroy才会执行。

场景:

  1. startService开启后只要不调用stopService就会一直存在,需要长时间在后台运行的服务使用startService;
  2. bindService开启后除了调用unBindService,所绑定的activity组件关闭后服务也会关闭,跟随组件生命周期的场景使用bindService。

1.7 activity的启动流程

  1. Launcher进程通过Binder IPC向system_server进程的AMS发送startAcitivity请求;
  2. system_server进程收到请求后通过socket向Zygote进程发送创建进程的请求;
  3. Zygote进程fork出新的子进程,即Application进程;
  4. App进程通过反射创建ActivityThread主线程并对其进行初始化,然后通过Binder IPC向system_server进程的AMS发起attach application请求;
  5. system_server进程的AMS收到attach application请求后通知 ApplicationThread bindApplication,然后发送 H.BIND_APPLICATION 消息;
  6. 主线程收到绑定成功后,初始化Application;
  7. system_server 进程的 AMS 在 bindApplication 后通过 Binder IPC 向 App 进程发送 scheduleLaunchActivity 请求;
  8. App进程的 ApplicationThread在收到请求后,通过 handler 向主线程发送 LAUNCH_ACTIVITY 消息

1.7 服务保活

1.设置为前台服务

2.利用系统广播拉活、利用系统服务拉活

1.8 说下Activity在切换横竖屏时,aictivity的生命周期变换

如果没有配置activity的configChanges属性,则:

竖屏启动:onCreate-onStart-onResume

切换横屏时:onPause-onSaveInstanceState-onStop-onDestroy-onCreate-onStart-onRestoreInstanceState-onResume

如果配置了configChanges属性:android:configChanges="orientation|keyboardHidden|screenSize"则只会调用onConfigurationChanged方法。

2.多线程

2.1 HandlerThread

工作在子线程的Handler

  1. 创建 HandlerThread 实例对象
    HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");
  1. 启动线程
    mHandlerThread .start();
  1. 创建Handler对象,重写handleMessage方法
    Handler mHandler= new Handler( mHandlerThread.getLooper() ) {
           @Override
           public boolean handleMessage(Message msg) {
               //消息处理
               return true;
           }
     });
  1. 使用工作线程Handler向工作线程的消息队列发送消息:
     Message  message = Message.obtain();
     message.what = “2”
     message.obj = "骚风"
     mHandler.sendMessage(message);
  1. 结束线程,即停止线程的消息循环
     mHandlerThread.quit();

2.2 IntentService

IntentService:是Service的子类,自动创建了一个工作线程,使用工作线程逐一处理所有的启动请求,在任务执行完毕后会自动停止服务。onHandlerIntent方法会接收每个启动请求的 Intent,能够执行后台工作和耗时操作。

public class MyIntentService extends IntentService {
    public static final String TAG ="MyIntentService";
    public MyIntentService() {
        super("MyIntentService");
    }
 
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
 
       boolean isMainThread =  Thread.currentThread() == Looper.getMainLooper().getThread();
        Log.i(TAG,"is main thread:"+isMainThread); // 这里会打印false,说明不是主线程
 
        // 模拟耗时操作
        download();
    }
 
    /**
     * 模拟执行下载
     */
    private void download(){
       try {
           Thread.sleep(5000);
           Log.i(TAG,"下载完成...");
       }catch (Exception e){
           e.printStackTrace();
       }
    }
}

2.3 AsyncTask的优缺点

优点:使用简单方便

缺点:默认任务串行执行,效率低。

复习AsyncTask的用法

2.4 Activity的runOnUiThread

会判断当前线程是否是主线程,如果是主线程则直接run,如果不是主线程则通过handler的post方法切换到主线程

public final void runOnUiThread(Runnable action) {
	if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}

2.5子线程能否更新UI

可以更新UI但是不建议这么做,会造成应用crash。因为在执行UI更新操作时会检查Thread,判断当前线程不是主线程则会抛异常。

2.6 Handler的机制和原理