00-面试查漏补缺

2024.3.13

Handler

  • sendMessage
  • post
    • 有callback的message
    • looper循环执行
  • sendMessage
    • 发送自定义的message
    • 可以没有callback
    • 可以有what、obj去和接收者传递消息

Message源码(仅public)

  • Message的获取
    • Handler包装的runnable
    • new Message()
    • obtain() 推荐,Message中的recycle方法会回收不用的Message,obtain的时候如果消息池不空,可以服用消息池
      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
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      208
      209
      210
      211
      212
      213
      214
      215
      216
      217
      218
      219
      220
      221
      222
      223
      224
      225
      226
      227
      228
      229
      230
      231
      232
      233
      234
      235
      236
      237
      238
      239
      240
      241
      242
      243
      244
      245
      246
      247
      248
      249
      250
      251
      252
      253
      254
      255
      256
      257
      258
      259
      260
      261
      262
      263
      264
      265
      266
      267
      268
      269
      270
      271
      272
      273
      274
      275
      276
      277
      278
      279
      280
      281
      282
      283
      284
      285
      286
      287
      288
      289
      290
      291
      292
      293
      294
      295
      296
      297
      298
      299
      300
      301
      302
      303
      304
      305
      306
      307
      308
      309
      310
      311
      312
      313
      314
      315
      316
      317
      318
      319
      320
      321
      322
      323
      324
      325
      326
      327
      328
      329
      330
      331
      332
      333
      334
      335
      336
      337
      338
      339
      340
      341
      342
      343
      344
      345
      346
      347
      348
      349
      350
      351
      352
      353
      354
      355
      356
      357
      358
      359
      360
      361
      362
      363
      364
      365
      366
      367
      368
      369
      370
      public final class Message implements Parcelable {
      /**
      * User-defined message code so that the recipient can identify
      * what this message is about. Each {@link Handler} has its own name-space
      * for message codes, so you do not need to worry about yours conflicting
      * with other handlers.
      */
      public int what;

      /**
      * arg1 and arg2 are lower-cost alternatives to using
      * {@link #setData(Bundle) setData()} if you only need to store a
      * few integer values.
      */
      public int arg1;

      /**
      * arg1 and arg2 are lower-cost alternatives to using
      * {@link #setData(Bundle) setData()} if you only need to store a
      * few integer values.
      */
      public int arg2;

      /**
      * An arbitrary object to send to the recipient. When using
      * {@link Messenger} to send the message across processes this can only
      * be non-null if it contains a Parcelable of a framework class (not one
      * implemented by the application). For other data transfer use
      * {@link #setData}.
      *
      * <p>Note that Parcelable objects here are not supported prior to
      * the {@link android.os.Build.VERSION_CODES#FROYO} release.
      */
      public Object obj;
      @UnsupportedAppUsage
      /*package*/ int flags;

      /**
      * The targeted delivery time of this message. The time-base is
      * {@link SystemClock#uptimeMillis}.
      * @hide Only for use within the tests.
      */
      @UnsupportedAppUsage
      @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
      public long when;


      /** @hide */
      public static final Object sPoolSync = new Object();

      /**
      * Return a new Message instance from the global pool. Allows us to
      * avoid allocating new objects in many cases.
      */
      public static Message obtain() {
      synchronized (sPoolSync) {
      if (sPool != null) {
      Message m = sPool;
      sPool = m.next;
      m.next = null;
      m.flags = 0; // clear in-use flag
      sPoolSize--;
      return m;
      }
      }
      return new Message();
      }

      /**
      * Same as {@link #obtain()}, but copies the values of an existing
      * message (including its target) into the new one.
      * @param orig Original message to copy.
      * @return A Message object from the global pool.
      */
      public static Message obtain(Message orig) {
      Message m = obtain();
      m.what = orig.what;
      m.arg1 = orig.arg1;
      m.arg2 = orig.arg2;
      m.obj = orig.obj;
      m.replyTo = orig.replyTo;
      m.sendingUid = orig.sendingUid;
      m.workSourceUid = orig.workSourceUid;
      if (orig.data != null) {
      m.data = new Bundle(orig.data);
      }
      m.target = orig.target;
      m.callback = orig.callback;

      return m;
      }

      /**
      * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
      * @param h Handler to assign to the returned Message object's <em>target</em> member.
      * @return A Message object from the global pool.
      */
      public static Message obtain(Handler h) {
      Message m = obtain();
      m.target = h;

      return m;
      }

      /**
      * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on
      * the Message that is returned.
      * @param h Handler to assign to the returned Message object's <em>target</em> member.
      * @param callback Runnable that will execute when the message is handled.
      * @return A Message object from the global pool.
      */
      public static Message obtain(Handler h, Runnable callback) {
      Message m = obtain();
      m.target = h;
      m.callback = callback;

      return m;
      }

      /**
      * Same as {@link #obtain()}, but sets the values for both <em>target</em> and
      * <em>what</em> members on the Message.
      * @param h Value to assign to the <em>target</em> member.
      * @param what Value to assign to the <em>what</em> member.
      * @return A Message object from the global pool.
      */
      public static Message obtain(Handler h, int what) {
      Message m = obtain();
      m.target = h;
      m.what = what;

      return m;
      }

      /**
      * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
      * members.
      * @param h The <em>target</em> value to set.
      * @param what The <em>what</em> value to set.
      * @param obj The <em>object</em> method to set.
      * @return A Message object from the global pool.
      */
      public static Message obtain(Handler h, int what, Object obj) {
      Message m = obtain();
      m.target = h;
      m.what = what;
      m.obj = obj;

      return m;
      }

      /**
      * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
      * <em>arg1</em>, and <em>arg2</em> members.
      *
      * @param h The <em>target</em> value to set.
      * @param what The <em>what</em> value to set.
      * @param arg1 The <em>arg1</em> value to set.
      * @param arg2 The <em>arg2</em> value to set.
      * @return A Message object from the global pool.
      */
      public static Message obtain(Handler h, int what, int arg1, int arg2) {
      Message m = obtain();
      m.target = h;
      m.what = what;
      m.arg1 = arg1;
      m.arg2 = arg2;

      return m;
      }

      /**
      * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
      * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
      *
      * @param h The <em>target</em> value to set.
      * @param what The <em>what</em> value to set.
      * @param arg1 The <em>arg1</em> value to set.
      * @param arg2 The <em>arg2</em> value to set.
      * @param obj The <em>obj</em> value to set.
      * @return A Message object from the global pool.
      */
      public static Message obtain(Handler h, int what,
      int arg1, int arg2, Object obj) {
      Message m = obtain();
      m.target = h;
      m.what = what;
      m.arg1 = arg1;
      m.arg2 = arg2;
      m.obj = obj;

      return m;
      }

      /** @hide */
      public static void updateCheckRecycle(int targetSdkVersion) {
      if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
      gCheckRecycle = false;
      }
      }

      /**
      * Return a Message instance to the global pool.
      * <p>
      * You MUST NOT touch the Message after calling this function because it has
      * effectively been freed. It is an error to recycle a message that is currently
      * enqueued or that is in the process of being delivered to a Handler.
      * </p>
      */
      public void recycle() {
      if (isInUse()) {
      if (gCheckRecycle) {
      throw new IllegalStateException("This message cannot be recycled because it "
      + "is still in use.");
      }
      return;
      }
      recycleUnchecked();
      }
      /**
      * Return the targeted delivery time of this message, in milliseconds.
      */
      public long getWhen() {
      return when;
      }

      public void setTarget(Handler target) {
      this.target = target;
      }

      /**
      * Retrieve the {@link android.os.Handler Handler} implementation that
      * will receive this message. The object must implement
      * {@link android.os.Handler#handleMessage(android.os.Message)
      * Handler.handleMessage()}. Each Handler has its own name-space for
      * message codes, so you do not need to
      * worry about yours conflicting with other handlers.
      */
      public Handler getTarget() {
      return target;
      }

      /**
      * Retrieve callback object that will execute when this message is handled.
      * This object must implement Runnable. This is called by
      * the <em>target</em> {@link Handler} that is receiving this Message to
      * dispatch it. If
      * not set, the message will be dispatched to the receiving Handler's
      * {@link Handler#handleMessage(Message)}.
      */
      public Runnable getCallback() {
      return callback;
      }

      /** @hide */
      @UnsupportedAppUsage
      public Message setCallback(Runnable r) {
      callback = r;
      return this;
      }

      /**
      * Obtains a Bundle of arbitrary data associated with this
      * event, lazily creating it if necessary. Set this value by calling
      * {@link #setData(Bundle)}. Note that when transferring data across
      * processes via {@link Messenger}, you will need to set your ClassLoader
      * on the Bundle via {@link Bundle#setClassLoader(ClassLoader)
      * Bundle.setClassLoader()} so that it can instantiate your objects when
      * you retrieve them.
      * @see #peekData()
      * @see #setData(Bundle)
      */
      public Bundle getData() {
      if (data == null) {
      data = new Bundle();
      }

      return data;
      }

      /**
      * Like getData(), but does not lazily create the Bundle. A null
      * is returned if the Bundle does not already exist. See
      * {@link #getData} for further information on this.
      * @see #getData()
      * @see #setData(Bundle)
      */
      public Bundle peekData() {
      return data;
      }

      /**
      * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members
      * as a lower cost way to send a few simple integer values, if you can.
      * @see #getData()
      * @see #peekData()
      */
      public void setData(Bundle data) {
      this.data = data;
      }

      /**
      * Chainable setter for {@link #what}
      *
      * @hide
      */
      public Message setWhat(int what) {
      this.what = what;
      return this;
      }

      /**
      * Sends this Message to the Handler specified by {@link #getTarget}.
      * Throws a null pointer exception if this field has not been set.
      */
      public void sendToTarget() {
      target.sendMessage(this);
      }

      /**
      * Returns true if the message is asynchronous, meaning that it is not
      * subject to {@link Looper} synchronization barriers.
      *
      * @return True if the message is asynchronous.
      *
      * @see #setAsynchronous(boolean)
      */
      public boolean isAsynchronous() {
      return (flags & FLAG_ASYNCHRONOUS) != 0;
      }

      /**
      * Sets whether the message is asynchronous, meaning that it is not
      * subject to {@link Looper} synchronization barriers.
      * <p>
      * Certain operations, such as view invalidation, may introduce synchronization
      * barriers into the {@link Looper}'s message queue to prevent subsequent messages
      * from being delivered until some condition is met. In the case of view invalidation,
      * messages which are posted after a call to {@link android.view.View#invalidate}
      * are suspended by means of a synchronization barrier until the next frame is
      * ready to be drawn. The synchronization barrier ensures that the invalidation
      * request is completely handled before resuming.
      * </p><p>
      * Asynchronous messages are exempt from synchronization barriers. They typically
      * represent interrupts, input events, and other signals that must be handled independently
      * even while other work has been suspended.
      * </p><p>
      * Note that asynchronous messages may be delivered out of order with respect to
      * synchronous messages although they are always delivered in order among themselves.
      * If the relative order of these messages matters then they probably should not be
      * asynchronous in the first place. Use with caution.
      * </p>
      *
      * @param async True if the message is asynchronous.
      *
      * @see #isAsynchronous()
      */
      public void setAsynchronous(boolean async) {
      if (async) {
      flags |= FLAG_ASYNCHRONOUS;
      } else {
      flags &= ~FLAG_ASYNCHRONOUS;
      }
      }

      /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
      */
      public Message() {
      }
      }

Looper每次循环在做什么

  • 取消息
  • 分发消息
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @SuppressWarnings({"UnusedTokenOfOriginalCallingIdentity",
    "ClearIdentityCallNotFollowedByTryFinally"})
    private static boolean loopOnce(final Looper me,
    final long ident, final int thresholdOverride) {
    Message msg = me.mQueue.next(); // might block
    if (msg == null) {
    // No message indicates that the message queue is quitting.
    return false;
    }
    msg.target.dispatchMessage(msg);
    // 省略部分大概是和observer交互还有打log
    }

Handler.dispatchMessage

  • 有callback就执行callback
  • 没有则通过mCallback对象或者子类重写handleMessage分发消息。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
    handleCallback(msg);
    } else {
    if (mCallback != null) {
    if (mCallback.handleMessage(msg)) {
    return;
    }
    }
    handleMessage(msg);
    }
    }

MessageQueue

enqueue消息的操作

  • 按照when大小入队
  • 如果不是异步消息且队初始为空或队列中消息为异步消息或消息没有target,则wake对方
    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
    boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
    throw new IllegalArgumentException("Message must have a target.");
    }

    synchronized (this) {
    if (msg.isInUse()) {
    throw new IllegalStateException(msg + " This message is already in use.");
    }

    msg.markInUse();
    msg.when = when;
    Message p = mMessages;
    boolean needWake;
    if (p == null || when == 0 || when < p.when) {
    // New head, wake up the event queue if blocked.
    msg.next = p;
    mMessages = msg;
    needWake = mBlocked;
    } else {
    // Inserted within the middle of the queue. Usually we don't have to wake
    // up the event queue unless there is a barrier at the head of the queue
    // and the message is the earliest asynchronous message in the queue.
    needWake = mBlocked && p.target == null && msg.isAsynchronous();
    Message prev;
    for (;;) {
    prev = p;
    p = p.next;
    if (p == null || when < p.when) {
    break;
    }
    if (needWake && p.isAsynchronous()) {
    needWake = false;
    }
    }
    msg.next = p; // invariant: p == prev.next
    prev.next = msg;
    }

    // We can assume mPtr != 0 because mQuitting is false.
    if (needWake) {
    nativeWake(mPtr);
    }
    }
    return true;
    }
  • enqueue的时候不是全部检查target不为空了吗?为什么后续还有target为空的消息?

取消息的操作

  • 取消息
    • 如果有消息
      • ready了,就返回
      • 没ready,阻塞等着通过nativePollOnce,如果有人enqueue,则会通过nativeWake唤醒
    • 没有消息了
      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
      @UnsupportedAppUsage
      Message next() {
      int pendingIdleHandlerCount = -1; // -1 only during first iteration
      int nextPollTimeoutMillis = 0;
      for (;;) {
      if (nextPollTimeoutMillis != 0) {
      Binder.flushPendingCommands();
      }

      nativePollOnce(ptr, nextPollTimeoutMillis);
      // 如果消息还没有ready,阻塞等待一段时间
      // nextPollTimeoutMillis的计算在上一次循环,看下面的代码

      synchronized (this) { // 只有一个线程能拿消息
      // Try to retrieve the next message. Return if found.
      final long now = SystemClock.uptimeMillis();
      Message prevMsg = null;
      Message msg = mMessages;
      if (msg != null && msg.target == null) {
      // Stalled by a barrier. Find the next asynchronous message in the queue.
      do {
      prevMsg = msg;
      msg = msg.next;
      } while (msg != null && !msg.isAsynchronous());
      }
      if (msg != null) {
      if (now < msg.when) {
      // Next message is not ready. Set a timeout to wake up when it is ready.
      nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
      // nextPollTimeoutMillis的计算
      } else {
      // Got a message.
      mBlocked = false;
      if (prevMsg != null) {
      prevMsg.next = msg.next;
      } else {
      mMessages = msg.next;
      }
      msg.next = null;
      if (DEBUG) Log.v(TAG, "Returning message: " + msg);
      msg.markInUse();
      return msg; // 拿到消息,返回
      }
      } else {
      // No more messages.
      nextPollTimeoutMillis = -1;
      }
      }
      }
      }

Handler实战

  • 普通进程使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class LooperThread extends Thread {
    public Handler mHandler;
    public void run() {
    Looper.prepare();
    mHandler = new Handler(Looper.myLooper()) {
    public void handleMessage(Message msg) {
    //处理即将发送过来的消息
    System.out.println("thread id="+Thread.currentThread().getId());
    }
    }
    Looper.loop();
    }
    }
    // 外部开启线程、获取handler,post/sendMessage
  • HandlerThread

    1
    2
    3
    4
    HandlerThread handlerThread = new HandlerThread("name");
    handlerThread.start(); // 创建HandlerThread
    Handler handler = new Handler(handlerThread.getLooper());
    // 拿到HandlerThread的Looper,创建handler
  • Looper退出

    • quit : 删除所有消息,包括正在运行的
    • quitSafely() : 删除未运行的消息

AOT和JIT的对比

AOT和JIT的对比

System.arraycopy

Performance of System.arraycopy() vs. Arrays.copyOf()

arraycopy是native方法,用c实现的,可能是memcpy等方法实现的,效率因平台而不同

ANR(App Not Responding)

  • 哪些场景导致ANR
    • Service Timeout:Service在特定的时间内无法处理完成
    • BroadcastQueue Timeout:BroadcastReceiver在特定时间内无法处理完成
    • ContentProvider Timeout:内容提供者执行超时
    • inputDispatching Timeout: 按键或触摸事件在特定时间内无响应。

ServiceANR

realStartServiceLocked()->bumpServiceExecutingLocked()->scheduleServiceTimeoutLocked()

在Service启动过程中,scheduleServiceTimeoutLocked通过native层的handler发送了DelayedMessage

1
2
3
4
5
6
7
8
9
10
11
12
13
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
// 在serviceDoneExecutingLocked中会remove该SERVICE_TIMEOUT_MSG消息,
// 当超时后仍没有remove SERVICE_TIMEOUT_MSG消息,则执行ActiveServices. serviceTimeout()方法;
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
// 前台进程中执行Service,SERVICE_TIMEOUT=20s;后台进程中执行Service,SERVICE_BACKGROUND_TIMEOUT=200s
}

在Service的OnCreate结束后或启动过程抛出异常,调用serviceDoneExecutingLocked删除消息

1
2
3
4
if (r.app.executingServices.size() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortName);
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);

在service的oncreate阶段不要执行过重的任务

InputDispatchingANR

在分派输入事件时,InputDispatcher会检查当前是否有聚焦的窗口和应用,获取超时时间,如果当前时间大于超时时间,就弹出ANR

Activity.onCreate执行耗时操作,不管用户如何操作都不会发生ANR,因为输入事件相关监听机制还没有建立起来;InputChannel通道还没有建立

应对方案

  • 耗时操作子线程处理,结束后切回主线程更新ui

Logs

除了主体逻辑,发生ANR时还会输出各种类别的日志:
event log:通过检索”am_anr”关键字,可以找到发生ANR的应用
main log:通过检索”ANR in “关键字,可以找到ANR的信息,日志的上下文会包含CPU的使用情况
dropbox:通过检索”anr”类型,可以找到ANR的信息
traces:发生ANR时,各进程的函数调用栈信息

看完这篇 Android ANR 分析,就可以和面试官装逼了!

Activity/Fragment Lifecycle

Activity

Activity Lifecycle

  • onSaveInstanceState() 与 onRestoreIntanceState()

    • 不属于生命周期
    • onSaveInstanceState保存临时性的状态
    • onRestoreIntanceState恢复临时性的状态
    • 调用时机
      • 异常终止的时候才会调用
      • 资源内存不足导致低优先级的 Activity 被杀死
        • 高优先级:前台Activity
        • 中优先级:可见且非前台
        • 低优先级:后台Activity
      • 资源相关的系统配置发生改变导致Activity被杀死并重新创建
      • 旋转屏幕
    • 旋转屏幕时
      • 旧Activity:puase->onSaveInstanceState->stop->destory
      • 新Activity:create->start->onRestoreInstanceState->onresume
        • onCreate中也能取到onSaveInstanceState,但是官方建议使用onRestoreInstanceState恢复数据
  • onCreate: 创建中,

  • onStart:可见但不可交互

  • onResume:可见可交互

  • onPause:可见不可交互

    • 其他应用需要内存,就会Kill进程,下次回来时,进入onCreate
  • onStop:不可见

    • 其他应用需要内存,就会Kill进程,下次回来时,进入onCreate
    • 一般情况下,下次回来时,调用onRestart然后onCreate
  • onDestroy:销毁

其他Activity进入前台,当前Activity就会onPause,onStop。如果手快一点,在当前Activity没有彻底消失时就关闭下一个Activity,就不会进入onStop

Fragment

Fragment Lifecycle

AAR

  • 也是一种打包的zip文件
  • 远程aar和本地arr

R文件

  • 资源id
  • 编译时会生成resources.arsc,包含id到实际值的映射
  • 都是static final,可以被内联
    • application module被内联了
  • 部分不是final,是static的
    • library module的R文件中的常量没有被内联
    • aar没有被内联
  • 压缩
    • AGP 4.1.0打包时,在release包中已经彻底优化掉R文件
    • 混淆,缩短id等标识符长度
    • 删除不需要的资源
    • 从应用及其库依赖中检测并安全地移除不使用的类、字段、方法和属性

HTTP断点续传

各种生命周期

sql事务

view绘制原理

activity启动模式

这里的都不太会

2024.3.17美团笔试

面向对象的各种概念

  • 单一职责

编译原理相关知识

  • 文法自动机相关知识

2024.3.19美团二面

Service生命周期

  • 非绑定式
    • -(首次startService)->onCreate()
    • -(非首次startService)->onStartCommand()
    • -(stopService/stopSelf)->onDestroy()
  • 绑定式
    • -(首次bindService)->onCreate()
    • -(非首次bindService)->onBind()
    • -(unbindService/stopSelf)->onUnbind()->onDestroy()

Activity与Service交互信息

  • 非绑定式
    • startService时用Intent传递
  • 绑定式
    • 创建ServiceConnect对象,获取IBinder
    • 通过IBinder交互
    • Service中创建对象,继承Binder

前台Service

  • 前台服务,一般用来创建notification,且不可移除的通知
  • onCreate时通过startForeground创建通知
  • 通过stopForeground停止前台服务

动态广播的使用

sendBroadCast

接受

创建IntentFilter
创建BroadcastReceiver
registerReceiver
unregistReceiver

  • 两个Activity之间传递消息

静态广播

创建接收器
在Manifest文件中注册,指定接收器类名和IntentFilter

  • 8.0后无法接受隐式广播(intent只指定action)
    • intent.setPackage(getPackageName()) // 接收方的包名
    • intent.addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND)

有序广播无序广播

  • 无序广播
    • 默认就是无序广播
    • 多个接收器同时接受
  • 有序广播
    • 接收器依照优先级依次接受广播
    • 通过context.sendOrderedBroadcast(intent, permission);发送
    • intentFilter.setPriority()
    • sendOrderedBoradcast
    • 在广播接收器中abortBroadcast会截断广播向低优先级的传递
    • setResultExtras和getResultExtras,上游接收器向下游发送消息
    • setResultData和getResultData,上游接收器向下游发送消息

本地广播全局广播

  • 本地广播:仅在app内部传播
    • 只能动态注册
    • LocalBroadCastReceiver(已废弃,需要手动添加依赖)
  • 全局广播:整个系统都能接受
    • 默认就是全局的

Java新技术(kotlin早已支持)

  • 密封类
    • 规定可以有哪些子类
      1
      2
      public abstract sealed class Reference<T>
      permits PhantomReference, SoftReference, WeakReference, FinalReference {

Hook技术

通过反射,将某些回调字段设置成一个代理对象,代理字段中对invoke进行hook

Xposed框架

通过替换/system/bin/app_process程序控制zygote进程,使app_process在启动过程中加载XposedBridge.jar,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持

  • posed自定义模块开发
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class Main implements IXposedHookLoadPackage { 
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
    if (!loadPackageParam.packageName.equals("com.example.pengchengxiang.inputdemo")) {
    return;
    }

    XposedBridge.log("Loaded app:" + loadPackageParam.packageName);
    //Hook 类的方法
    findAndHookMethod("className", loadPackageParam.classLoader, "methodNAme", String.class, new XC_MethodHook() {
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
    }

    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
    }
    });
    }
    }
作者

Meow Meow Liu

发布于

2024-03-13

更新于

2025-04-15

许可协议

评论