android

 


https://blog.csdn.net/u014644594/article/details/112861591
Handler      Thread    Java
  ThreadLocalMap的key是ThreadLocal的对象,value是独享数据。         
       ThreadLocal           

ThreadLocal
     67、ThreadLocal的原理  
                
          ThreadLocal  

          实现单个线程单例以及单个线程上下文信息存储,比如交易id等。
          
实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例。

ThreadLocal  ThreadLocal
          
承载一些线程相关的数据,避免在方法中来回传递参数。

synchronized        synchronized

synchronized

ThreadLocal可以让线程独占资源,存储于线程内部,避免线程堵塞造成CPU吞吐下降。

synchronized
synchronized()
    ThreadLocal可以让线程独占资源,存储于线程内部,避免线程堵塞造成CPU吞吐下降。
    
    
    ThreadLocal
    
    在每个Thread中包含一个ThreadLocalMap,ThreadLocalMap的key是ThreadLocal的对象,value是独享数据。
    
    value=是独享数据。 key = ThreadLocal
    
    68、计算一个view的嵌套层级
    
    Model
    
    
    getParents  ViewParents  view
    
    ViewParents
    view.getParents()
    
    69、MVP,MVVM,MVC解释和实践
    
    
    MVC     View    Controller 控制层
    
    MVC中Android的控制层是由Activity来承担的,
    
    MVC中Android的控制层是由Activity来承担的, Android
    Activity        MVC
    模型层(Model)
    
    具有一定的分层,model彻底解耦,controller和view并没有解耦 
    
    model彻底解耦,controller和view并没有解耦 
    controller和view在android中无法做到彻底分离,但在代码逻辑层面一定要分清
    
    view
    
    MVP

通过引入接口BaseView,让相应的视图组件如Activity,Fragment去实现BaseView,实现了视图层的
    
    MVP  BaseView
    
    BaseView
    //
    MVVM
    
    MVP中我们说过随着业务逻辑的增加,UI的改变多的情况下,会有非常多的跟UI相关的case,
    
    这样就会造成View的接口会很庞大
    
    
    通过双向绑定的机制
    
    
    MVVM与DataBinding的关系?
    
    MVVM DataBinding去实现MVVM。
    
    
    
    DataBinding去实现MVVM。
    
    用MVVM的话可以考虑使用官方的架构组件ViewModel、LiveData、DataBinding去实现MVVM。
    
    ViewModel LiveData、DataBinding去实现MVVM。
    
    ViewModel        LiveData、DataBinding去实现MVVM。
    
    可以考虑使用官方的架构组件ViewModel、LiveData、DataBinding去实现MVVM。
    
    
    SharedPrefrences的apply和commit有什么区别?
    apply方法不会提示任何失败的提示。(commit)
    apply() commit
    
    https://blog.csdn.net/u014644594/article/details/112861591
    
    apply
    apply commit
    
    sharedPreference
    
    71、Base64、MD5是加密方法么?
    
    Base64、MD5是加密方法么? 45
    
    
    Base64是用文本表示二进制的编码方式,它使用4个字节的文本来表示3个字节的原始二进制数据。 
    它将二进制数据转换成一个由64个可打印的字符组成的序列:A-Za-z0-9+/
    
    
    Base64 64
    
    Base64 MD5
    
    Base64是用文本表示二进制的编码方式,它使用4个字节的文本来表示3个字节的原始二进制数据。
    它将二进制数据转换成一个由64个可打印的字符组成的序列:A-Za-z0-9+/
    
    Base64 MD5
    
    67md5 md5    128位(16字节)
    
    Base64也不是加密算法,它是一种数据编码方式
    
    MD5  MD5
    
    
    72、HttpClient和HttpConnection的区别?
    
    HttpClient和HttpConnection的区别?
    
    
    。(并在Android 6.0中抛弃了Http Client,替换成OkHttp)
    
    Android 6.0 HttpClient和HttpConnection的区别? OkHttp
    
    
    且在Android 4.0中增加了response cache
    response cache
    
    response cache response cache    HttpResponseCache的install()方法
    
    HttpResponseCache的install install
    
    HttpResponseCache的install install
    
    304 Not Modified Not Modified
    
    HttpURLConnection
    
    ActivityA跳转ActivityB然后B按back返回A,各自的生命周期顺序,A与B均不透明。
    
    
Activity A:onPause
Activity B:onCreate
Activity B:onStart
Activity B:onResume
Activity A:onStop
    
Activity B:onPause
Activity A:onRestart
Activity A:onStart
Activity A:onResume
Activity B:onStop
Activity B:onDestroy

onPause
    74、如何通过广播拦截和abort一条短信?
    
    abort  abort
    
    75、BroadcastReceiver,LocalBroadcastReceiver 区别?
    BroadcastReceiver LocalBroadcastManager
    
    LocalBroadcastManager LocalBroadcastManager
    
    1) 与BroadcastReceiver是以 Binder 通讯方式为底层实现的机制不同,LocalBroadcastManager 的核心实现实际还是 Handler,
    
    
    只是利用到了 IntentFilter 的 match 功能,
    
    IntentFilter match
    
    IntentFilter match
    
        https://blog.csdn.net/u014644594/article/details/112861591
    
    (1) 与BroadcastReceiver是以 Binder 通讯方式为底层实现的机制不同,
    LocalBroadcastManager 的核心实现实际还是 Handler,只是利用到了 IntentFilter 的 match 功能,至于 BroadcastReceiver 换成其他接口也无所谓,顺便利用了现成的类和概念而已。

    背景,该开源库由谁推出,由哪个公司推出来的。
    
    77、简单说下接入支付的流程,是否自己接入过支付功能?

Alipay支付功能:
    
    2.签约成功后,需要配置秘钥。使用支付宝提供的工具生成RSA公钥和私钥,公钥需要设置到管理后台。
    Alipay支付功能:
    RSA RSA
    apply
    78、单例实现线程的同步的要求:
    
    copy jar包;
    
    https://blog.csdn.net/liboxiu/article/details/99933392
    Wiegand(韦根)--26bit数据格式
    79、如何保证Service不被杀死?

Android 进程不死从3个层面入手:
    
方法二:启动前台service。

方法三:提升service优先级:

在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"

intent-filter可以通过android:priority = "1000"

onDestroy方法里重启service:service + broadcast 方式,就是当service走ondestory的时

onDestroy service service + broadcast 

    service + broadcast     onDestroy
    
     A/B test
     接入腾讯信鸽或极光推送与小米推送做 A/B Test。
     
     80、说说ContentProvider、ContentResolver、ContentObserver 之间的关系?
     
     ContentProvider:管理数据,提供数据的增删改查操作,数据源可以是数据库、文件、XML、网络等,ContentProvider为这些数据的访问提供了统一的接口,可以用来做进程间数据共享。
     ContentResolver、ContentObserver  
     
    ContentProvider:管理数据,提供数据的增删改查操作,数据源可以是数据库、文件、XML、网络等,ContentProvider为这些数据的访问提供了统一的接口,可以用来做进程间数据共享。
    ContentResolver、ContentObserver ContentObserver:观察ContentProvider中的数据变化,并将变化通知给外界。
    
    81、如何导入外部数据库?

把原数据库包括在项目源码的 res/raw。
    
    res/raw。
    android系统下数据库应该存放在 /data/data/com.(package name)/ 目录下,
    
    /data/data/com .(package name)/)
    
    FileInputStream FileInputStream FileOutputStream
    FileOutputStream
    
    
    82、LinearLayout、FrameLayout、RelativeLayout性能对比,为什么?
    
    LinearLayout,   FrameLayout、RelativeLayout性能对比,为什么?
    
RelativeLayout性能对比,为什么?
    
LinearLayout、FrameLayout、RelativeLayout性能对比,为什么?
    RelativeLayout会让子View调用2次onMeasure,LinearLayout
    2 onMeasure  
    
    为什么Google给开发者默认新建了个RelativeLayout,而自己却在DecorView中用了个LinearLayout?
    
    RelativeLayout会让子View调用2次onMeasure,LinearLayout
    
    onMeasure
    
    https://blog.csdn.net/u014644594/article/details/112861591
    
    
    为什么Google给开发者默认新建了个RelativeLayout,而自己却在DecorView中用了个LinearLayout?
    
    RelativeLayout会让子View调用2次onMeasure,LinearLayout
    
    DecorView LinearLayout    DecorView
    
    
    因为复杂的View嵌套对性能的影响会更大一些。
    
    ViewModel            83、scheme跳转协议
    
    scheme跳转协议()
    
    
    84、HandlerThread

1、HandlerThread原理
    
    
    HandlerThread
    创建HandlerThread后必须先调用HandlerThread.start()方法
    
    创建HandlerThread后必须先调用HandlerThread.start()方法
    
    它在Android中的一个具体的使用场景是IntentService
    
    
IntentService        quit  quitSafely

    quitSafely
    
    
    HandlerThread优点是异步不会堵塞,减少对性能的消耗。
    
    HandlerThread与线程池不同,
    HandlerThread是一个串队列,背后只有一个线程。
    
    85、IntentService

IntentService是一种特殊的Service,它继承了Service并且它是一个抽象类,
因此必须创建它的子类才能使用IntentService。
    IntentService
    
    ,onCreat()方法会创建一个HandlerThread,然后使用它的Looper来构造一个Handler对象mServiceHandler,
    
    onCreat
    
    
    生成一个默认的且与主线程互相独立的工作者线程来执行所有传送至onStartCommand()方法的Intetnt。
    onStartCommand
    
    
    
            onHandleIntent((Intent)msg.obj);
            
            onHandleIntent msg.obj
    
    onHandleIntent
    
    
    86、如何将一个Activity设置成窗口的样式。
    
    android:theme="@android:style/Theme.Dialog"
    
theme android:theme = @android:style/Theme.Dialog
    
    android:theme="@android:style/Theme.Translucnt"
    Translucnt
    
    Intent intent = callIntent
    
    Intent callIntent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
    
startActivity(callIntent);

2:Content Provider 如访问系统相册

3:广播(Broadcast) 如显示系统时间

4:AIDL服务        AIDL服务        BroadcastReceiver
    
    88、显示Intent与隐式Intent的区别
    
    显示Intent与隐式Intent的区别        Intent
    
    
    对于隐式意图,在定义Activity时,指定一个intent-filter,当一个隐式意图对象被一个意图过滤器进行匹配时,将有三个方面会被参考到:
    
    intent-filter可以通过android
    
动作(Action)

类别(Category ['kætɪg(ə)rɪ] )

数据(Data )
    
    
    ANR
Android BroadCastReceiver是10秒,Service是20秒(均为前台)。
   

ANR
Android BroadCastReceiver是10秒,Service是20秒(均为前台)。

data/anr/traces.txt即可,最新的ANR信息在最开始部分。

android -android-android
https://www.it610.com/article/1344194310530215936.htm

Thread.34.sleep
AsyncTask(AsynTask会一直执行,直到doInBackground)

、使用Handler处理工作线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。

4、Activity的onCreate和onResume回调中尽量避免耗时的代码。 
BroadcastReceiver中onReceive代码也要尽量减少耗时,建议使用IntentService处理。

Activity  onCreate onResume

BroadCastReceiver是10秒,Service是20秒(均为前台)。 onReceive


handler.sendMessage、runonUIThread、AsyncTask、RxJava等方式更新UI

runonUIThread、AsyncTask、RxJava等方式更新UI AsyncTask RxJava等方式更新UI

深入回答

2、Activity和Fragment生命周期有哪些?

Activity 和 Fragment 

android:configChanges

android:configChanges=“orientation” keyboardHidden

onConfigurationChanges

4、AsyncTask的缺陷和问题,说说他的原理。
AsyncTask是什么?

AsyncTask

android
https://blog.csdn.net/u014644594/article/details/112861591

Params Process Result

ThreadPoolExecutor


AsyncTask  可以尝试自定义线程池,配合Asynctask使用。

ThreadPoolExecutor

AsyncTask里面线程池是一个核心线程数为CPU + 1,最大线程数为CPU * 2 + 1,
工作队列长度为128的线程池,线程等待队列的最大等待数为28,但是可以自定义线程池。线程池是由AsyncTask来处理的,线程池允许tasks并行运行,需要注意的是并发情况下数据的一致性问题,新数据可能会被老数据覆盖掉。所以希望tasks能够串行运行的话,使用SERIAL_EXECUTOR。

SERIAL_EXCUTOR tasks

从1.6开始,AsyncTask引入了线程池

每次只启动一个线程执行一个任务,完了之后再执行第二个任务,也就是相当于只有一个后台线程在执行所提交的任务。

doInBackground
onPostExecute(Result result)

onCancelled(Result result)


onPostExecute(Result result)

onPostExecute Result result

所以,我们是必须确保在销毁活动之前取消任务

2.内存泄漏

如果AsyncTask被声明为Activity的非静态内部类,那么AsyncTask会保留一个对Activity的引用。

AsyncTask

onPostExecute Result result
execute

executeOnExecutor

SerialExecutor用于排队,THREAD_POOL_EXECUTOR为真正的执行任务,Handler将工作线程切换到主线程),其必须在

ThreadPoolExecutor

onSaveInstanceState onRestoreInstanceState

onCreate Bunder传递对象为什么需要序列化?Serialzable和Parcelable的区别?

深入理解

6、android中进程的优先级?

1. 前台进程:

即与用户正在交互的Activity或者Activity用到的Service等,如果系统内存不足时前台进程是最晚被杀死的

2. 可见进程:

可以是处于暂停状态(onPause)的Activity或者绑定在其上的Service,即被用户可见,但由于失了焦点而不能与用户交互

3. 服务进程:

onPause        startService  onStop

7、Bunder传递对象为什么需要序列化?
Serialzable和Parcelable的区别?

SerialExecutor用于排队,THREAD_POOL_EXECUTOR为真正的执行任务,Handler将工作线程切换到主线程),其必须在

Serializable 
Parcelable(android专用):

IPC(比如启动另一个进程的Activity、Service和Reciver)之间进行传输,也可以存储到本地。

Activity        SerialExecutor用于排队,THREAD_POOL_EXECUTOR为真正的执行任务,Handler将工作线程切换到主线程),其必须在

Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这也就实现传递对象的功能了。

Parcelable(android专用):

tween View Rotate。tween
View 
frame  AnimationDrawable控制animation-list

Alpha Scale Translate  Rotate。

frame 帧动画。AnimationDrawable控制animation-list.xml布局
PropertyAnimation 属性动画3.0引入,属性动画核心思想是对值的变化。

PropertyAnimation
evaluate
 fraction

TypeEvaluator去计算运动中的属性值。

TimeInter

elapsed time/ duration

elapsed fragment

ValueAnimator

计算已完成动画分数 elapsed fraction。

elapsed fraction

计算插值(动画变化率)interpolated fraction 

interpolated

interpolated fraction
interpolated

计算得到一个interpolated(插值)分数,在计算过程中,

已完成动画百分比会被加入到新的插值计算中。

计算属性值当插值分数计算完成后,Valu
两个概念:已完成动画分数(elapsed fraction)、插值分数( interpolated fraction )。


elapsed interpolated fraction

TypeEvaluator去计算运动中的属性值。

elapsed fraction interpolated fraction


TimeInterpolator        interpolated

计算插值(动画变化率)interpolated fraction 

TypeEvaluator去计算运动中的属性值。


1.属性动画:

插值器:作用是根据时间流逝的百分比来计算属性变化的百分比

AnimatonDrawable
AnimationDrawable控制animation-list

AnimationDrawable控制animation-list

repeatCount

repeatCount

为什么属性动画移动后仍可点击?
ViewGroup

9、Context相关

1、Activity和Service以及Application的Context是不一样的,Activity继承自ContextThemeWraper.其他的继承自ContextWrapper。

Activity Service        Application
ContextImpl

ContextImpl

ContextThemeWraper

getApplication

BroadcastReceiver  getApplicationContext  Application

getApplicationContext Application

5、Context的数量等于Activity的个数 + Service的个数 +1,这个1为Application。

MaterialDesign

Dalvik        JIT AOT    AOT JIT

通知详情可以用户自己设计
Android6.0新特性

V2签名

Notification Channel

android::supportsPictureInPicture

Android9.0(P)新特性

室内WIFI定位

“刘海”屏幕支持
Q)目前曝光的新特性


Java Script

com.google.code

 Gson
 
gson.fromJson  int[].class
int [] ages= 
int[].class

3、直接解析成List.

newTypeToke(){}.getType

List

轻量级的数据交换格式
读写更加容易
易于机器的解析和生成

DOM解析

XML中定义的几何形状
DOM解析器的API在使用上也相对比较简单

如果XML文档体积比较大时,将文档读入内存是非消耗系统资源的.

W3C    XML中定义的几何形状 DOM解析

DOM 是以层次结构组织的节点的集合.
以层次结构

SAX解析


SAX 这种扩展能力得到了更好的体现.

Xmlpull解析        Stream        dom
不会像dom那样要把所有节点以对象树的形式展现在内存中
xmlpull和sax类似

Jar Aar
Jar和Aar的区别    Android Library,我们可以直接引用
14、Android为每个应用程序分配的内存大小是多少

runonUIThread、AsyncTask、RxJava等方式更新UI

View.postDelay    Handler AsynTask会一直执行,直到doInBackground

LiveData RxJava2

View.post Handler AsyncTask  RxJava2 LiveData

ContentProvider使用方法。

getContentResolver

ContentProvider使用方法。

通过 Uri匹配进行数据的增删改查

17、Thread、AsyncTask、IntentService的使用场景与特点。

run


SerialExecutor用于排队,THREAD_POOL_EXECUTOR为真正的执行任务,Handler将工作线程切换到主线程),其必须在


Thread_POOL


IntentService的使用场景与特点。

onHandleIntent

onHandleIntent

Merge    ViewStub    

ViewStub

Merge
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ; 
mContext.startActivity(intent);

setFlags FLAG_ACTIVITY_NEW_TASK


dialog.getWindow.setType

WindowManager.LayoutParams

TYPE_SYSTEM_ALERT

21、Asset目录与res目录的区别?


AssetManager
res/anim:存放动画资源。

res:会在 R 文件中生成 id 标记,

//

res/raw:和 asset
22、Android怎么加速启动Activity?

onCreate    RxJava2 LiveData

AsyncTask        Handler


dialog.getWindow.setType WindowManager.LayoutParams
.TYPE_SYSTEM_ALERT

res/raw:和 asset  会映射到 R 文件中

onCreate onResume

减少主线程阻塞时间。

Adapter AdapterView

优化布局文件。

ViewStub: 按需加载,减少内存使用量、加快渲染速度、不支持 merge 标签。

ViewStub        TYPE_SYSTEM_ALERT

Adapter AdapterView


23、Handler机制        Handler


sendMessage、runonUIThread、AsyncTask、RxJava等方式更新UI

enqueueMessage

dispatchMessage

dispatchMessage

Target():Handler


Looper loop

Message   Target Handler
Looper
MessageQueue  loop


15万基金不动,
2月28号到期资金 做短期波段操作,因为每月月初会涨,月末会跌,中间为振荡期;
(每月必须)(月末最后一周的周五3点前) 买入(到期资金),
(每月最后期限)(月末倒数第二周的周五3点前) 卖出(到期资金),


MessageQueue Looper
MessageQueue:消息队列,负责消息的存储与管理
Handler Message

读取会自动删除消息,单链表维护,插入和删除上有优势。
next
Looper    Looper:消息循环器    loop

Looper

Handler

Looper:消息循环器,负责关联线程以及消息的分发,

MessageQueue
loop->next

MessageQueue,调用loop()方法的时候消息循环开始,
其中会不断调用messageQueue的next()方法,
当有消息就处理,否则阻塞在messageQueue的next()方法中。


MessageQueue Message Handler
Looper.quit MessageQueue.quit
quit

handler:消息处理器,负责发送并处理消息


loop        target handler

loop sendMessage、runonUIThread、AsyncTask、RxJava等方式更新UI

target handler handleMessage

MessageHandler
WeakMess

target handler

MessageQueue

Handler        handleMessage

MessageQueue与Looper相关功能都通过MessageQueue的Native方法来完成,

Handler 发送的消息由 MessageQueue 存储管理,并由 Looper 负责回调消息到 handleMessage()。
线程的转换由 Looper 完成,handleMessage() 所在线程由 Looper.loop() 调用者所在线程决定。

Looper handleMessage Looper.loop

Handler 引起的内存泄露原因以及最佳解决方案

Activity

removeCallbacksAndMessages(null)

removeCallbacksAndMessages(null)

为什么我们能在主线程直接使用 Handler,而不需要创建 Looper ?

Handler Looper


handler.removeCallbacksAndMessages null


Looper.prepareMainLooper() 
main
prepareMainLooper    Callback Handler  Hook

ActivityThread.mH        ActivityThread.mH

主线程的 Looper 不允许退出

Callback(Handler)
Message.obtain()    Dialog。Toast

妙用 Looper 机制

将 Runnable post 到主线程执行;
利用 Looper 判断当前线程是否是主线程

Runnable post  Looper

Toast Handler DialogFragment

Runnable    post    

Looper    Linux pipe/epoll机制

Linux pipe/epoll机制    MessageQueue

nativePoll        epoll机制

handler postDelay

postDelay

所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。hand

handler.postDelay MessageQueue

24、程序A能否接收到程序B的广播?

LocalBroadCastRecevier只限于本进程的广播间通信。

LocalBroadCastRecevier只限于本进程的广播间通信。

RecyclerView
26、通过google提供的Gson解析json时,定义JavaBean的规则是什么?

google    javaBean        Gson gson

Serializable

 

 

https://blog.csdn.net/u014644594/article/details/112861591
SDK提供JSONArray,JSONObject

FixThreadPool、CachedhreadPool、SingleThreadPool、ScheduleThreadExecutr.

FixThreadPool    CachedThreadPool

ScheduledThreadExecutor

CachedThreadPool        CachedThreadPool

SynchronousQuue        CachedThreadPool
SynchronousQuue


ScheduledThreadPool

指定定时任务以及固定周期的重复任务

ScheduledThreadPool


29、内存泄露,怎样查找,怎么产生的内存泄露?


Cursor,File文件等

1.资源对象没关闭造成的内存泄漏


SQLiteCursor        close null

Cursor,File文件等

2.构造Adapter时,没有使用缓存的convertView

context。这个context的生存周期和你的应用的生存周期一样长,而不是取决于activity的生存周期。如果你想保持一个长期生存的对象,并且这个对象需要一个context

Adapter

在BaseAdapter中提供了方法: public View getView(int position, ViewconvertView, ViewGroup parent) 来向ListView提供每一个item所需要的view对象。

ListView回收list BaseAdapter

。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的 view对象


list item    item
getView
convertView
 android.widget.AbsListView.java --> voidaddScrapView(View scrap)

 AbsListView.java

voidaddScrapView()

view = convertView; 


3.Bitmap对象不在使用时调用recycle()释放内存

4.试着使用关于application的context来替代和activity相关的context

这是一个很隐晦的内存泄漏的情况

Context.getApplicationContext() or Activity.getApplication()
Context.getApplicationContext Activity.
getApplication
5.注册没取消造成的内存泄漏

但是别的引用程序仍然还有对我们的Android程序的某个对象的引用


register  unregister    LockScreen

TelePhone    TelePhone    system_proces
6.集合中对象没清理造成的内存泄漏
查找内存泄漏可以使用Android Studio 自带的AndroidProfiler工具或MAT

Android

1、使用AndroidProfiler的MEMORY工具:And heap dumpsys

shell dumpsys meminfo  .heap
hprof必须手动使用android-context。这个context的生存周期和你的应用的生存周期一样长,而不是取决于activity的生存周期。如果你想保持一个长期生存的对象,并且这个对象需要一个context


Histogram和Dominator Tree。


Dominator Thre    Regex


Merge Shortest Paths to GC Root中的exclude all phantom/weak/soft etc.references

Merge shell    Paths    weak/soft etc.

Leakcanary
hprof必须手动使用android -conv

/weak/soft etc.references

weak/soft    Regex        Merge Shortest Parcelable

Root中的exclude all phantom/weak/soft etc.references选项来查看该类的GC强引用链。最后,通过引用链即可看到最终强引用该类的对象。

Histogram:直方图注重量的分析。使用方式与Dominator Tree类似。

Navigation History    

查看引用关系或对象数量去进行分析即可。
hprof必须手动使用android
hprof必须手动使用android
navigation

ViewPager使用细节     ViewPager使用细节    Fragment

自定义一个 LazyLoadFragment 基类,利用 setUserVisibleHint 和 生命周期方法

LazyLoadFragment setUserVisibleHint    requestData requestData

setUserVisibleHint        requestData

setUserVisibleHint        requestData        isVisibleToUser

forceUpdate    getUserVisibleHint

requestData();
isDataLoaded = true;
35、Android为什么引入Parcelable?

Serializable 使用 I/O 读写存储在硬盘上,而 Parcelable 是直接 在内存中读写

Serializable            marshalled &unmarshalled
marshalled unmarshalled

marshalled unmarshalled

Android parent generator)进行实体类的序列化的实现。

使用Parcelable插件(Android Parcelable code generator)进行实体类的序列化的实现。

code generator)进行实体类的序列化的实现。


Bitmap 使用时候注意什么?

1、要选择合适的图片规格(bitmap类型):

ALPHA_8   每个像素占用1byte内存        
ARGB_4444 每个像素占用2byte内存       
ARGB_8888 每个像素占用4byte内存(默认)      
RGB_565 每个像素占用2byte内存

bitmap            1byte

BitmapFactory.Options 
//
BitmapFactory.Options inSampleSize

options.inJustDecodeBounds = true

inJustDecodeBounds = true
https://blog.csdn.net/u014644594/article/details/112861591

calculateSampleSize

2、降低采样率。

3、复用内存。即,通过软引用(内存不够的时候才会回收掉),复用内存块,

不需要再重新给这个bitmap申请一块新的内存,避免了一次内存的分配和回收,从而改善了运行效率。
bitmap
recycle            bitmap

Java中管理内存除了显式地catch OOM之外还有更多有效的方法:

catch OOM之外还有更多有效的方法:
SoftReference        WeakReference    硬盘缓存等。

在JVM用光内存之前,会多次触发GC,这些GC会降低程序运行的效率。

JVM        GC        Service

java heap

 Canvas.recycle     Canvas.save
 40、Canvas.save()跟Canvas.restore()的调用时机
 
 java heap
 
 save        平移 缩放 旋转、错切、裁剪等操作。
 
 restore        Canvas
 
 restore ->save
 save-> Canvas
 如果restore调用次数比save多,会引发Error
 
 save
 
 41、数据库升级增加表和删除表都不涉及数据迁移,
 但是修改表涉及到对原有数据进行迁移。升级的方法如下所示:
 
 case    DBService    DBService
 
 create
integer primarykey,text
 alter table    book    rename to
 
 
 
            db.beginTransaction();
 
            db.execSQL(CREATE_TEMP_BOOK);
            db.execSQL(CREATE_BOOK);
            db.execSQL(INSERT_DATA);
            db.execSQL(DROP_BOOK);
 
            db.setTransactionSuccessful();
            db.endTransaction();

 db.execSQL        DROP_BOOK
 
 42、编译期注解跟运行时注解
 
 RunTime
 @Retention(RetentionPolicy.RUNTIME)。
 
 编译期(Compile time)注解,以及处理编译期注解的手段APT和Javapoet,对应
 
 Compile time        APT和Javapoet
 
 ALPHA_8    APT
 
 如EventBus3.0+,页面路由 ARout、Dagger、Retrofit等均有使用的身影,注解不仅仅是通过反射一种方式来使用,也可以使用APT在编译期处理
 
 
 43、bitmap recycler 相关
 recycle
 
 
 44、强引用置为null,会不会被回收?
 
 bitmap recycler
 
 而 垃圾收集器是运行在后台的线程,
 
 bitmap
 
 45、Bundle传递数据为什么需要序列化?

序列化,表示将一个对象转换成可存储或可传输的状态。序列化的原因基本三种情况:
 
 Bundle传递数据为什么需要序列化?
 
 1.永久性保存对象,保存对象的字节序列到本地文件中;

2.对象在网络中传递;

3.对象在IPC间传递。
 
 
 1.永久性保存对象,保存对象的字节序列到本地文件中;
 
 传递大数据,不应该用Intent;考虑使用ContentProvider或者直接匿名共享内存。简单情况下可以考虑分段传输。
 
 ContentProvider的权限管理
 
 ContentProvider的权限管理
 
 47、是否了解硬件加速?
 
 
 对于自定义View的时候或者一些特殊的绘制函数就需要考虑是否需要关闭硬件加速
 
 View
 硬件加速的优势还有display list的设计
 
 
 display list
 CPU更擅长复杂逻辑控制,而GPU得益于大量ALU和并行结构设计,更擅长数学运算。
 display list
 
 48、ContentProvider的权限管理(读写分离,权限控制-精确到表级,URL控制)。
 
 
 ContentProvider的权限管理
 
 
 View
 ContentProvider的权限管理
 
 
 ContentProvider的权限管理
 
 可以在AndroidManifest.xml文件中对节点的属性进行配置
 
 
 AndroidManifest.xiaomi
 
 android:grantUriPermssions:临时许可标志。
android:permission:Provider读写权限。
android:readPermission:Provider的读权限。
android:writePermission:Provider的写权限。
android:enabled:标记允许系统启动Provider。
android:exported:标记允许其他应用程序使用这个Provider。
android:multiProcess:标记允许系统启动Provider相同的进程中调用客户端。
 
 
 gradlew        exported enabled = true
 
 
 android:multiProcess    multiProcess    productFlavors
 
 Provider的写权限。multi
 
 49、Fragment状态保存
 Fragmengt和Fragmengt怎么通信?
 onSaveInstanceState
 saveFragmentInstanceState
 
 Activity onSaveInstanceState FragmentManager的moveToState
 saveAllState
 
 
 onSaveInstanceState
 
 saveAllState
 
 saveFragmentInstanceState
 
 moveToState
 
 34
 moveToState        Activity_CREate
 
 
 FragmentManager的moveToState moveToState
 
 saveFragmentViewState
 
 50、直接在Activity中创建一个thread跟在service中创建一个thread之间的区别?
 
 thread

在Activity中被创建

Service thread

,比较常见的就是:在Service中保持与服务器端的长连接。

51、如何计算一个Bitmap占用内存的大小,怎么保证加载Bitmap不产生内存溢出?

Bitamp    Bitamp(34)

Bitamp 不产生内存溢出


Bitamp 占用内存大小 = 宽度像素 x (inTargetDensity / inDensity) x 高度像素 x (inTargetDensity / inDensity)x 一个像素所占的内存

inTargetDensity = 23

Bitamp 占用内存大小 = 宽度像素 x (inTargetDensity / inDensity) x 高度像素 x (inTargetDensity / inDensity)x 一个像素所占的内存

Bitamp =  inTargetDensity /  inDensity)

inDensity)

注:这里inDensity表示目标图片的dpi(放在哪个资源文件夹下),
inTargetDensity表示目标屏幕的dpi,所以你可以发现inDensity和inTargetDensity会对Bitmap的宽高进行拉伸,
进而改变Bitmap占用内存的大小。


在Bitmap里有两个获取内存占用大小的方法。

Bitamp

getByteCount/45

getAllocationByteCount


getByteCount():API12 加入,代表存储 Bitmap 的像素需要的最少内存。

 getAllocationByteCount():API19 加入,代表在内存中为 Bitmap 分配的内存大小,
 
 代替了 getByteCount() 方法。 在不复用 Bitmap 时,getByteCount() 和 getAllocationByteCount 
 
 返回的结果是一样的。在通过复用 Bitmap 来解码图片时,
 
 那么 getByteCount() 表示新解码图片占用内存的大 小,
 
 getAllocationByteCount() 表示被复用 Bitmap 真实占用的内存大小(即 mBuffer 的长度)。

getAllocationByteCount / getByteCount
 
 
 Bitamp        mBuffer

getAllocationByteCount() 表示被复用 Bitmap 真实占用的内存大小(即 mBuffer 的长度)。

getAllocationByteCount
56
BitmapFactory()=

不复用 bitmap时
getByteCount =  getAllocationByteCount

复用 bitmap时,
,那么 getByteCount() 表示新解码图片占用内存的大小,
getAllocationByteCount() 表示被复用 Bitmap 真实占用的内存大小(即 mBuffer 的长度)。

mBuffer的长度

BitmapFactory

为了保证在加载Bitmap的时候不产生内存溢出,可以使用BitmapFactory进行图片压缩

BitmapFactory.Options.inPreferredConfig:将ARGB_8888改为RGB_565,改变编码方式,节约内存。

改变编码方式  缩放比例

BitmapFactory.Options.inPurgeable:让系统可以内存不足时回收内存。

inPurgeable:让系统可以内存不足时回收内存。

52、对于应用更新这块是如何做的?(灰度,强制更新,分区域更新)\

52、对于应用更新这块是如何做的?灰度 强制更新 分区域更新

1、通过接口获取线上版本号,versionCode 2、比较线上的versionCode 和本地的versionCode,
弹出更新窗口

 3、下载APK文件(文件下载) 4、安装APK

versionCode

 bsdiff:二进制差分工具bsdiff是相应的补丁合成工具
 
 bspatch
 
灰度: (1)找单一渠道投放特别版本。 (2)做升级平台的改造,允许针对部分用户推送升级通知甚至版本强制升级。 (3)开放单独的下载入口。

测试框架负责与服务器端api通信

app        由服务器端控制app上A/B版本的分布

灰度:
灰度,数据监控(常规数据、新特性数据、主要业务数据)还是要做到位

45哪种方法都需要做好版本管理工作,分配特别的版本号以示区别。

34 app    bsdiff:二进制差分工具bsdiff是相应的补丁合成工具

bspatch .patch文件。通过bspatch使旧的apk文件与不定文件合成新的apk。

53、请解释安卓为啥要加签名机制。

bsdiff:二进制差分工具bsdiff是相应的补丁合成工具 

bspatch

53、请解释安卓为啥要加签名机制。

Package Name    Package Name


1、发送者的身份认证 由于开发商可能通过使用相同的 Package Name 来混淆替换已经安装的程序,
以此保证签名不同的包不被替换。


2、保证信息传输的完整性 签名对于包中的每个文件进行处理,以此确保包中内容不被替换778


3、防止交易中的抵赖发生, Market 对56的要求。Mar

Market

54、为什么bindService可以跟Activity生命周期联动?

bindService  =     Activity bindService Activity

ServiceConnection     


bindService  LoadedApk        ServiceConnection(56)

1、bindService 方法执行时,LoadedApk 会记录 ServiceConnection 信息。

BroadcastReceiver 和 Service,

BroadcastReceiver 45

55、如何通过Gradle配置多渠道包?

Gradle        Gradle


android {  
    productFlavors {
        xiaomi {}
        baidu {}
        wandoujia {}
        _360 {}        // 或“"360"{}”,数字需下划线开头或加上双引号
    }
}

android {56
    productFlavors
    productFlavors
    xiaomi baidu{}
}

执行./gradlew assembleRelease ,将会打出所有渠道的release包;
./gradlew assembleRelease

因此,可以结合buildType和productFlavor生成不同的Build Variants,即类型与渠道不同的组合。


buildType productFlavors        Build Variants,即类型与渠道不同的组合。

Build Variants,即类型与渠道不同的组合45

56、activty和Fragmengt之间怎么通信,Fragmengt和Fragmengt怎么通信?

(一)Handler

(二)广播

(三)事件总线:EventBus、RxBus、Otto

(四)接口回调

(五)Bundle和setArguments(bundle)

Bundle和setArguments(bundle)

57、自定义view效率高于xml定义吗?说明理由。

自定义view效率高于xml定义:view

view  xml文件中对节点的属性进行配置 view

ViewGroup View

 
 ViewGroup View();

58、广播注册一般有几种,各有什么优缺点?


第一种是常驻型(静态注册):当应用程序关闭后如果有信息广播来,程序也会被系统调用,自己运行。

第二种不常驻(动态注册):广播会跟随程序的生命周期。


动态注册67
android
59、服务启动一般有几种,服务和activty之间怎么通信,服务和服务之间怎么通信

activty和Fragmengt之间怎么通信,Fragmengt和Fragmengt怎么通信?


onCreate->        onStartCommand(67)

。 开启者不能调用服务里面的方法。


onDestory()

2、bindService:

onCreate() —>onBind()—>onunbind()—>onDestory()

bindService onCreate onBind onunbind onDestory

通信:

1、通过Binder对象。

2、通过broadcast(广播)。

Binder broadcast

60、ddms 和 traceView 的区别?

Binder broadcast

ddms traceView

60、ddms 和 traceView 的区别?
线程和堆栈ddms traceView

Traceview Android
hotspot(瓶颈)。Traceview

startMethodTracing

stopMethodTracing()
/mnt/sdcard/下的一个文件中。

这两个函数运行过程中将采集运行时间内该应用所有线程(注意,只能是 Java线程)

 的函数执行情况, 并将采集数据保存到/mnt/sdcard/下的一个文件中。 
 
开发者然后需要利用 SDK 中的 Traceview工具来分析这些数据。

SDK Traceview() Traceview()    SDK


/mnt/sdcard/下的一个文件中。

61、ListView卡顿原因

ListView卡顿原因()

Adapter56

notifySetDataChanged()

ListView卡顿原因
Adapter getView convertView  setTag getTag

Adapter
getView  convertView

在getView方法里面ViewHolder初始化后的赋值或者是多个控件的显示状态和背景的显示没有优化好,

抑或是里面含有复杂的计算和耗时操作;


getView        ViewHolder

getView     ViewHolder
inflate的row 

Adapter多余或者不合理的notifySetDataChanged

Adapter notifySetDataChanged(45)


listview 被多层嵌套,多次的onMessure导致卡顿,如果多层嵌套无法避免

,建议把listview的高和宽设置为match_parent.

 如果是代码继承的listview,那么也请你别忘记为你的继承类添加上

match_parent
listview  onMeasure
LayoutPrams

LayoutPrams match_parent
45                    67
LayoutPrams match_parent

62、AndroidManifest的作用与理解

AndroidManifest

https://blog.csdn.net/u014644594/article/details/112861591


getView inflate的row()

Adapter多余或者不合理的notifySetDataChanged;
Adapter notifySetDataChanged

listview onMeasure

AndroidManifest.xml文件中对节点的属性进行配置


AndroidManifest.xml文件,也叫清单文件,
来获知应用中是否包含该组件,

如果有会直接启动该组件。

可以理解是一个应用的配置文件。

描述应用的各个组件,包括构成应用的 Activity、服务、广播接收器和内容提供程序。

 诺安成长混合

国投瑞银沪深300金融等基金

为应用的 Java 软件包命名。软件包名称充当应用的唯一标识符。


Activity Service46

contentProvider    contentProvider

确定托管应用组件的进程。

声明应用必须具备哪些权限才能访问 API 中受保护的部分并与其他应用交互。

还声明其他应用与该应用组件交互所需具备的权限

确定托管应用组件的进程。

列出 Instrumentation类,这些类可在应用运行时提供分析和其他信息。

Instrumentation类,这些类可在应用运行时提供分析和其他信息。

声明应用所需的最低 Android API 级别

Android API

63、LaunchMode应用场景

列出应用必须链接到的库

声明应用所需的最低 Android API 级别
列出应用必须链接到的库

LaunchMode应用场景

standard,创建一个新的Activity。 

singleTop适合接收通知启动的内容显示页面。

singleTop,栈顶不是该类型的Activity,创建一个新的Activity。否则,onNewIntent。

onNewIntent
standard,创建一个新的Activity。

singleTask singleTop适合接收通知启动的内容显示页面。

onNewIntent+ClearTop

onNewIntent ClearTop

affinity = 

它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的Task存在

affinity =Taskaffinity Task

如果我们想要设置了"singleTask"启动模式的Activity在新的任务中启动,

就要为它设置一个独立的taskAffinity属性值。

singleTask

, 如果我们想要设置了"singleTask"启动模式的Activity在新的任务中启动,

就要为它设置一个独立的taskAffinity属性值。

taskAffinity  taskAffinity

singleInstance,回退栈中,只有这一个Activity,没有其他Activity。

singleInstance应用场景:()

singleTask
singleInstance应用场景:

说说Activity、Intent、Service 是什么关系


https://blog.csdn.net/u014644594/article/details/112861591


Context ContextWrapper

Activity Service

65、ApplicationContext和ActivityContext的区别


在使用context的时候,小心内存泄露,防止内存泄露,注意一下几个方面:

 

OKHttp请求流程
网络请求缓存处理
连接池


OkHttpClient Builder  build()

RealCall enqueue execute    Dispatcher

RetryAndFollowUpInterceptor    RetryAndFollowUpInterceptor

getResponseWithInterceptorChain

getResponseWithInterceptorChain() = response

originalRequest->response    adapter        pool

如下为使用OKHttp进行Get请求的步骤:

OkHttp Get

getResponseWithInterceptorChain   =  response

originalRequest->response  adapter pool

Request url        method header

CallServerInterceptor()
url = method header body
ConnectInterceptor


Response

CacheInterceptor Cachehit

Cache miss


code message  headers body

connectionSpecs // 传输层版本和连接协议

ConnectionSpec

  @Nullable CertificateChainCleaner certificateChainCleaner;// 验证确认响应证书 适用 HTTPS 请求连接的主机名。

CertificateChainCleaner certificateChainCleaner;

    @Nullable CertificateChainCleaner certificateChainCleaner;
    
      HostnameVerifier hostnameVerifier;// 验证确认响应证书 适用 HTTPS 请求连接的主机名。  

HostnameVerifier hostnameVerifier;

followRedirects() = followSslRedirects

@Nullable InternalCache internalCache;// 内部缓存


    EventListener.Factory eventListenerFactory;
    
    EventListener.Factory eventListenerFactory;
    
    
    Authenticator 

https://juejin.cn/post/6844903631909552135

followRedirects        followRedirects

Dispatcher() Dispatcher

  connectionSpecs = DEFAULT_CONNECTION_SPECS;
connectionSpecs

Response response = client.newCall(request).execute();


client.newCall    request.execute

 Response result = getResponseWithInterceptorChain();

 interceptors.addAll client.interceptors
 
 retryAndFollowUpInterceptor
        retryAndFollowUpInterceptor

  interceptors.add(new BridgeInterceptor(client.cookieJar()));

  interceptors.add(BridgeInterceptor client.cookieJar);

    interceptors.add(new CacheInterceptor(client.internalCache()));
    
    interceptors.add CacheInterceptor client.internalCache();
    
    client.internalCache
  
  client.internalCache
  
     interceptors.addAll(client.networkInterceptors());
     
     interceptors.addAll client.networkInterceptors();
     
      // 使用责任链模式开启链式调用
    return chain.proceed(originalRequest);
    
    chain.proceed originalRequest
    
    https://juejin.cn/post/6844903631909552135
     
  RealInterceptorChain        eventListener
  
  //使用责任链模式开启链式调用
  chain.proceed originalRequest
  
  
  
  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
  RealConnection connection) throws IOException {

Response proceed
  
  
  
 RealInterceptorChain         Interceptor interceptors;.get index
  
  eventListener        
  
  
  
  AA00110002
  
  Deque <AsyncCall>  readyAsyncCalls = new ArrayDeque<>();
  
  readyAsyncCalls AsyncCall = new ArrayDeque
  
  
  onFailure onResponse
  
  Deque RealCall runningAsyncCalls
  
  AsyncCall  Deque<RealCall> runningSyncCalls
  
  Deque RealCallRealCall
  
  promoteAndExecute
  
  readyAsyncCalls
  
        if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
        
        runningCallsForHost asyncCall
        
        if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
        
        asyncCall.executeOn
  
  executorService
  
  
  runningAsyncCalls
  
  executableCalls.add asyncCall
  
  runningAsyncCalls.add asyncCall
  
   return originalRequest.url().host();
  
  
  originalRequest
  
  executorService
  
  
  AsyncCall NamedRunnable 
  
  Callback responseCallback
  
   client.dispatcher().finished(this); // This call is no longer running!
  
  client.dispatcher.finished 
  
  signalledCallback = false
  
  getResponseWithInterceptorChain
  
  
    responseCallback.onResponse(RealCall.this,   response);
  
  
  responseCallback.onResponse RealCall.this,   response
  
       signalledCallback = true;
       
       signalledCallback = true;
       
       client.dispatcher().finished(this);
       
       
       二、网络请求缓存处理之CacheInterceptor
       
       
       
       CacheInterceptor
       
       
       二、网络请求缓存处理之CacheInterceptor
       
       
       cache.get chain.request
       
       
     request->cache->response
       
       
       Android 自定义UI-垂直方向的SeekBar
       https://blog.csdn.net/wangjinyu501/article/details/20456761
       
       
       
       strategy.networkRequest
       strategy.cacheResponse
       
       
           if (cache != null) {
      cache.trackResponse(strategy);
    }
         
       cache.trackResponse strategy
       
       closeQuietly cacheCandidate.body
       
       closeQuietly();
       
           https://juejin.cn/post/6844903631909552135
       
       closeQuietly();
       
       .body Util.EMPTY_RESPONSE
       
       
       receivedResponseAtMillis System.currentTimeMillis
       
       
        if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();

        
         // 调用下一个拦截器,决定从网络上来得到response
        networkResponse = chain.proceed(networkRequest);
        
networkResponse = 
chain.proceed networkRequest

      cacheResponse    
       
       CacheStrategy.isCacheable response,networkRequest
       
       cacheWritingResponse 
       
       
       HttpMethod.invalidatesCache networkRequest,response
       
       .cacheResponse        stripBody cacheResponse
       
            cache.trackConditionalCacheHit();
          cache.update(cacheResponse, response);
          
          cache.trackConditionalCacheHit
          cache.update  
          
          
          trackConditionalCacheHit
          
          .cacheResponse .networkResponse
          
          cacheWritingResponse
          
          HttpMethod.
          invalidatesCache 
       
       
          if (HttpMethod.invalidatesCache(networkRequest.method())) {
          
          HttpMethod.invalidatesCache
          
             cache.remove(networkRequest);
          
       缓存拦截器会根据请求的信息和缓存的响应的信息来判断是否存在缓存可用,
       
       如果有可以使用的缓存,那么就返回该缓存给用户,
       
       否则就继续使用责任链模式来从服务器中获取响应。当获取到响应的时候,又会把响应缓存到磁盘上面。


       三、ConnectInterceptor之连接池
       
       ConnectInterceptor
       
       ConnectInterceptor
       
       doExtensive
       
       RealConnection connection = streamAllocation.connection
       
       onCardResponse 
       
       Request request = realChain.request();
    StreamAllocation streamAllocation = realChain.streamAllocation();

    StreamAllocation streamAllocation = realChain
       
       realChain.proceed  request,streamAllocation,httpCodec,connectTimeout
       
       45
       
        调用 streamAllocation 的 newStream() 方法的时候,最终会经过一系列
       
       pingInterval,
       
       toClose
       releaseIf
       
       toClose
       
       reportedAcquired
       ()
       
              https://juejin.cn/post/6844903631909552135
       
         if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
       
        foundPooledConnection
                
    synchronized (connectionPool) {
       
       com.lzy.imagepicker
       
       com.xys.libzxing
       
       
       com.jeremyfeinstein.slidingmenu.lib
       
       SlidingMenu_library
       
       pingIntervalMillis,
       result.connectionSpecs
       
       connectionRetryEnabled,call,eventListener
       
       connectionRetryEnabled
       
       connection != null

        foundPooledConnection = true
        this.route = route;
       call eventListener
       
       connected result.route
       
         routeDatabase().connected(result.route());
       
       reportedAcquired = true;
       
       connectionPool,result
       
          // 如果同时创建了另一个到同一地址的多路复用连接,
          释放这个连接并获取那个连接
          
    if (result.isMultiplexed()) {
       
       connectionPool,address,this
       
       eventListener.connectionAcquired call, result
       
       
       
      Internal.instance.get(
      ConnectionPool,address);
       ConnectionPool,address);
       
       ConnectionPool.add();
       
       result.isMultiplexed
       socket =Internal.instance.deduplicate
       
       result = connection;
       
       Internal.instance.deduplicate
       
       private final Deque<RealConnection> connections = new ArrayDeque<>();
       
       Deque<RealConnection> connections = 
       
       RealConnection
       
       assert(Thread.holdsLock(this)) {
       }
       
       
       com.bigkoo.pickerview_new
       
       pickerview
       
       https://juejin.cn/post/6844903631909552135
       
          JsonChao 的 2020 年终总结 | 掘金年度征文
          https://juejin.cn/post/6911091834219397134
          
          https://juejin.cn/post/6844903972587716621--深入探索Android稳定性优化
          
          signal信号
          
          PM(Application Performance Manange)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值