1.反正屏切换时Activity的生命周期

  • 在没有配置activity的configChanges特点时 Activity的生命周期:onPause->onStop->onCreate->onStart->onResume
  • 配置了activity的configChanges onConfigurationChanged

2..怎么设置activity成窗口样式

android:theme=“@android:style/Theme.Dialog

3..Activity的发动办法

  • standard 不论有没有已存在的实例,都生成新实例
  • singleTop 假如发现有对应的Activity实例坐落栈顶,则重复使用,不然创立实例
  • singleTask a)栈内复用,复用时具有clearTop机制 b)single taskAffinity in task
  • singleInstance a)启用一个新的栈结构,将Activity放置于栈结构中,并保证不会有其它Activity实例进入 b)方便多个应用共享大局唯一的实例

4.Service的生命周期

经过startService调用 onCreate->onStartCommand->onDestroy 经过bindService调用 onCreate->onBind->onUnbind->onDestroy

Service Binder

>>//示例
  a).public class LocalService extends Service{
    private static LBinder binder=new LBinder();            //必须声明为static
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
      super.onCreate(savedInstanceState);
    }
     @Override
    public IBinder onBind(Intent intent)
    {
      return binder;
    }
    static class LBinder extends Binder{
      public int getCount(){
       return count;
      }
    }
   }
​

5..IntentService

//敞开线程处理耗时操作

>>onCreate              //创立单独的HandlerThread处理所有的intent恳求
  :1.HandlertThread thread = new HandlerThread("") 
   thread.start()
   mServiceLooper =thread.getLooper()
   mServiceHandler =new ServiceHandler(mServiceLooper) 
​

onSTartCommand.

  :1.public int onStartCommand(Intent intent,int startId){
    onStart(intent,startId)
    return mRedelivery?START_REDELIVER_INTENT:START_NOT_STICKY;//在于service挂掉了intent是否会回传
   }
  :2.public void onStart(Intent intent,int startId)
   {
    Message msg=mServiceHandler.obtainMessage()
     msg.obj=intent
    msg.arg1=startId
    mServiceHandler.sendMessage(msg)
   }
​

ServiceHandler.

//onHandleIntent,为自定义的类所实现的耗时操作
  :1.private final class ServiceHandler extends Handler{
    public ServiceHandler(Looper looper){super(looper);}
    public void handleMessage(Message msg)
    {
      onHandleIntent((Intent)msg.obj)
      stopSelf(msg.arg1)//当id为最终一个startService的startId时,进行封闭
    }
   }

总结

a).经过HandlerThread创立线程,并调用getLooper获取looper变量,以新建Handler
b).IntentService经过onStartCommand接纳新的intent,并放在message.obj发送过handler
c).handler调用实现的onHandleIntent(intent)
d).Message msg=mServiceHandler.obtainMessage() //obtainMessage和Looper调用msg.relycleUnchecked是以刺进链表头部和撤除的形式分配、释放Message资源

6.Android有哪几种布局

  • LinearyLayout 按照水平或笔直的顺序排列子元素,android:layout_weight收效
  • FrameLayout 后来的子元素掩盖在之前子元素的上层,以左上角为基准点
  • AbsoluteLayout android:layout_x和android:layout_y会收效
  • RelativeLayout android:layout_below和android:layout_above

TableLayout //表格布局由TableRow构成,layout_column指定开始列,layout_span拟定规模 a).大局特点 android:shrinkColumns=“0,1” //可缩短的列 android:stretchColumns=“0,1” //可拉伸的列 b).单元格特点 android:layout_span=“2” //该TableRow中的子View所横跨的列 android:layout_column=“1” //拟定子view在哪列开始排列

7.HashMap、HashTable的区别 //从线程安全性、速度

>>线程方面
  :1.HashTable是线程安全的
>>HashTable的key、value不允许设置null,而hashmap能够
>>是否可在遍历时进行操作
  :1.HashMap:fail-fast  
   a).既在遍历HashMap时,假如经过实例目标进行修正则报ConcurrentModificationException, 
    expectedModCount==modCount
>>解决抵触
  :1.HashMap的装载因子是3/4,链接法解决抵触,当链表过长时转化为红黑树
>>实现
  :1.HashMap 经过数组+链表的结构
   >transient Node<K,V>[] table;
   >static class Node<K,V> implements Map.Entry<K,V>{
    final int hash;
    final K key;
    final V value;
    Node<K,V> next;
    public final int hashCode(){
      return Objects.hashCode(key)^Objects.hashCode(v)
    }
   }
  :2.hashCode 经过Objects.hashCode(key)^Objects.hashCode(value)计算
  :3.扩容  哈希桶的容量形若100...0,扩容容量为2倍,阀值也为2倍,需要rehash
   >final Node<K,V>[] resize(){
    //oldTab 为当时表的哈希桶
     Node<K,V>[] oldTab = table;
    int oldCap=oldTab.length
    //当时的阈值
     int oldThr = threshold;
    if (oldCap > 0) {
      if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
           oldCap >= DEFAULT_INITIAL_CAPACITY)
      {
       newThr=oldThr<<1;
      }
    }   
    //更新阈值 
     threshold = newThr
    table= newTab
     if(oldTab!=null){
      for (int j = 0; j < oldCap; ++j) {
       Node<K,V> e;
       if((e=oldTab[j])!=null){
        oldTab[j] = null//将原哈希桶置空以便GC
        if (e.next == null)
          newTab[e.hash & (newCap - 1)] = e; //直接将这个元素放置在新的哈希桶里
        else
        {
          //因为扩容是容量翻倍,所以原链表上的每个节点,现在可能存放在原来的下标,即low位, 或者扩容后的下标,
          //即high位。 high位=  low位+原哈希桶容量
          //低位链表的头结点、尾节点
          Node<K,V> loHead = null, loTail = null;
          //高位链表的头节点、尾节点
          Node<K,V> hiHead = null, hiTail = null;
          Node<K,V> next;//暂时节点 存放e的下一个节点
          do {
            next = e.next;
            //这儿又是一个使用位运算 替代常规运算的高效点: 使用哈希值 与 旧的容量 能够得到哈希值去模后,
            //是大于等于oldCap还是小于oldCap,等于0代表小于oldCap,应该存放在低位,不然存放在高位
            if ((e.hash & oldCap) == 0) {
             //给头尾节点指针赋值
             if (loTail == null)
               loHead = e;
             else
               loTail.next = e;
             loTail = e;
            }//高位也是相同的逻辑
              else {
               if (hiTail == null)
                hiHead = e;
               else
                hiTail.next = e;
               hiTail = e;
              }//循环直到链表结束
             } while ((e = next) != null)
            //将低位链表存放在原index处,
             if (loTail != null) {
               loTail.next = null;
               newTab[j] = loHead;
             }
             //将高位链表存放在新index处
             if (hiTail != null) {
               hiTail.next = null;
               newTab[j + oldCap] = hiHead;
             }
        }
       }
​
    }
   }
​
  :4.刺进节点
   >public V put(K key,V value){return putVal(hash(key),key,value)}
   >final V putVal(int hash,K key,V value,...)
    {
    Node<K,V>[] tab=table 
    int n=tab.length
    Node<K,V> p;
    //假如当时哈希表是空的,代表是初始化
     if ((tab = table) == null || (n = tab.length) == 0)
       //那么直接去扩容哈希表,而且将扩容后的哈希桶长度赋值给n
       n = (tab = resize()).length;
    //假如当时index的节点是空的,表示没有发生哈希碰撞。 直接构建一个新节点Node,挂载在index处即可。
     //这儿再啰嗦一下,index 是使用 哈希值 & 哈希桶的长度-1,替代模运算
     if(p=tab[I=?(n-1)&hash)==null)      
      tab[I]=newNode(hash,key,value,null)
    else//发生了抵触
    {
      Node<K,V> e;K k;
      if(p.hash==hash && ((k=p.key)==key || key.equals(k))//键值相同,寻觅成功
       e=p;
      else if(p instance TreeNode)          //红黑树
       e=TreeNode<K,V)p.putTreeVal(this, tab,hash,key,value)
      else{
       //遍历链表
       for(int binCount=0;;++binCount)
       {
        if((e=p.next)==null)            //遍历到尾部,追加新节点到尾部
        { 
          p.next=newNode(hash, key, value)     //生成结点并刺进
          if(binCount>=TREEIFY_THRESHOLD-1)   //将链表转化为树结构
            treeifyBin(tab,hash)
          break
        }
        //假如找到了要掩盖的节点
        if(e.hash==hash&&((k=e.key)==key)
          break
        p=e                 //迭代
       }
      }
      if(e!=null)
       e.value=value              //设置新值
    }
    }
  :5.删去结点
   >final Node<K,V> removeNode(int hash, Object key, Object value,
                boolean matchValue, boolean movable) {
    // p 是待删去节点的前置节点
     Node<K,V>[] tab; Node<K,V> p; int n, index;
    if ((tab = table) != null && (n = tab.length) > 0 &&
       (p = tab[index = (n - 1) & hash]) != null) {
      Node<K,V> node = null, e; K k; V v
      //假如链表头的便是需要删去的节点
      if (p.hash == hash &&
         ((k = p.key) == key || (key != null && key.equals(k))))
         node = p;//将待删去节点引用赋给node
      else if ((e = p.next) != null) {//不然循环遍历 找到待删去节点,赋值给node
       if (p instanceof TreeNode)
           node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
        else {
         do {
           if (e.hash == hash &&
             ((k = e.key) == key ||
              (key != null && key.equals(k)))) {
             node = e;
             break;
           }
           p = e;
         } while ((e = e.next) != null);
        }
      }
      //假如有待删去节点node,  且 matchValue为false,或者值也相等
      if (node != null && (!matchValue || (v = node.value) == value ||
                 (value != null && value.equals(v)))) {
       if (node instanceof TreeNode)
           ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
       else if (node == p)//假如node ==  p,说明是链表头是待删去节点
         tab[index] = node.next;
       else//不然待删去节点在表中间
         p.next = node.next;
       ++modCount;//修正modCount
       --size;//修正size
       return node;
      }
    }
   }
  :6.查找
  >final Node<K,V> getNode(int hash, Object key) {
     Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
     //查找进程和删去根本差不多, 找到回来节点,不然回来null
     if ((tab = table) != null && (n = tab.length) > 0 &&
       (first = tab[(n - 1) & hash]) != null) {
       if (first.hash == hash && // always check first node
         ((k = first.key) == key || (key != null && key.equals(k))))
         return first;
       if ((e = first.next) != null) {
         if (first instanceof TreeNode)
           return ((TreeNode<K,V>)first).getTreeNode(hash, key);
         do {
           if (e.hash == hash &&
             ((k = e.key) == key || (key != null && key.equals(k))))
             return e;
         } while ((e = e.next) != null);
       }
     }
     return null;
   }
  :7.iterator遍历
   > final Node<K,V> nextNode() {
     Node<K,V>[] t;
     Node<K,V> e = next;
     //fail-fast战略
     if (modCount != expectedModCount)
       throw new ConcurrentModificationException();
     if (e == null)
       throw new NoSuchElementException();
     //顺次取链表下一个节点,
     if ((next = (current = e).next) == null && (t = table) != null) {
      //假如当时链表节点遍历完了,则取哈希桶下一个不为null的链表头
      do {} while (index < t.length && (next = t[index++]) == null);
      }
      return e;
     }
40.LinkedHashMap 
>>成员 
  :1.LinkedHashMapEntry         //增加了before和after域,成为双向链表
   static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> {
     LinkedHashMapEntry<K,V> before, after;//双向链表
     LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) {
       super(hash, key, value, next);
     }
   }
  :2.head tail
  >transient LinkedHashMap.Entry<K,V> head //双向链表的头结点
  >transient LinkedHashMap.Entry<K,V> tail //双向链表的尾节点
  :3.accessOrder    //默以为false,是按照刺进结点的顺序,若为true,则可构造LruCache
>>重写newNode,在HashMap调用putVal()办法被调用
   >//在构建新节点时,构建的是`LinkedHashMap.Entry` 不再是`Node`.
   Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    LinkedHashMap.Entry<K,V> p =
       new LinkedHashMap.Entry<K,V>(hash, key, value, e);
    linkNodeLast(p);  //!!!
    return p;
   }
   //将新增的节点,连接在链表的尾部
   private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
     LinkedHashMap.Entry<K,V> last = tail;
     tail = p;
     //集合之前是空的
     if (last == null)
       head = p;
     else {//将新节点连接在链表的尾部
       p.before = last;
       last.after = p;
     }
   }
>>删去结点
   >//在删去节点e时,同步将e从双向链表上删去
   void afterNodeRemoval(Node<K,V> e) { // unlink
     LinkedHashMap.Entry<K,V> p =
       (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
     //待删去节点 p 的前置后置节点都置空
     p.before = p.after = null;
     //假如前置节点是null,则现在的头结点应该是后置节点a
     if (b == null)
       head = a;
     else//不然将前置节点b的后置节点指向a
       b.after = a;
     //同理假如后置节点时null ,则尾节点应是b
     if (a == null)
       tail = b;
     else//不然更新后置节点a的前置节点为b
       a.before = b;
   }
>>get  //获取结点
  >public V get(Object key) {
     Node<K,V> e;
     if ((e = getNode(hash(key), key)) == null)
       return null;
     if (accessOrder)
       afterNodeAccess(e);//因为访问了该结点,所以动态调整其位置
     return e.value;
   } 
  >若accessOrder==true          //按访问顺序
   void afterNodeAccess(Node<K,V> e) { // move node to last
    LinkedHashMapEntry<K,V> last;//原尾节点
    //假如accessOrder 是true ,且原尾节点不等于e
    if (accessOrder && (last = tail) != e) {
       //节点e强转成双向链表节点p
       LinkedHashMapEntry <K,V> p =
         (LinkedHashMapEntry <K,V>)e, b = p.before, a = p.after;
       //p现在是尾节点, 后置节点一定是null
       p.after = null;
       //假如p的前置节点是null,则p以前是头结点,所以更新现在的头结点是p的后置节点a
       if (b == null)
         head = a;
       else//不然更新p的前直接点b的后置节点为 a
         b.after = a;
       //假如p的后置节点不是null,则更新后置节点a的前置节点为b
       if (a != null)
         a.before = b;
       else//假如原本p的后置节点是null,则p便是尾节点。 此刻 更新last的引用为 p的前置节点b
         last = b;
       if (last == null) //原本尾节点是null  则,链表中就一个节点
         head = p;
       else {//不然 更新 当时节点p的前置节点为 原尾节点last, last的后置节点是p
         p.before = last;
         last.after = p;
       }
       //尾节点的引用赋值成p
       tail = p;
       //修正modCount。
       ++modCount;
     }
   }
​

8.怎么在ListView间增加分割线


//引荐用divider设置drawable的分割线
>>.设置大局特点			
   a).android:divider="#FFF"   	        //设置为null可无视距离     
   b).android:dividerHeight="1px"    
   c).默许的list view不支持设置footerDevider,采取在每个item布局中增加
      > <View
          android:layout_width="match_parent"
          android:layout_height="1dp"
          android:background="#999"
          />

今日分享到此结束,对你有协助的话,点个赞再走呗,每日一个面试小技巧

重视公众号:Android老皮
解锁 《Android十大板块文档》 ,让学习更贴近未来实战。已形成PDF版

内容如下

1.Android车载应用开发体系学习指南(附项目实战)
2.Android Framework学习指南,助力成为体系级开发高手
3.2023最新Android中高级面试题汇总+解析,离别零offer
4.企业级Android音视频开发学习道路+项目实战(附源码)
5.Android Jetpack从入门到通晓,构建高质量UI界面
6.Flutter技术解析与实战,跨平台首要之选
7.Kotlin从入门到实战,全方面提高架构基础
8.高级Android插件化与组件化(含实战教程和源码)
9.Android 性能优化实战+360全方面性能调优
10.Android零基础入门到通晓,高手进阶之路