Android知识点基础篇(二)

索引:

  1. Binder机制,共享内存实现原理
  2. ActivityThread工作原理
  3. 嵌套滑动实现原理
  4. View的绘制原理,自定义View,自定义ViewGroup
  5. View、SurfaceView 与 TextureView
  6. 主线程Looper.loop为什么不会造成死循环
  7. ViewPager的原理
  8. BroadcastReceiver使用总结
  9. AndroidP新特性
  10. Asset目录与res目录的区别

11. Binder机制,共享内存实现原理   Binder是跨进程通信(IPC)的一种解决方案。Binder中文即粘合剂,意思是粘合两个不同的进程。从定义来讲Binder是一种Android中实现跨进程的方式;也是一种虚拟的物理设备驱动,连接Service进程、Client进程和ServiceManager进程;而对于Android代码来说,Binder是一个类,实现了IBinder接口,将Binder机制模型以代码的形式具体实现的Android中。   一个进程空间分为用户空间和内和空间,进程间用户空间数据不可共享而内核空间是可以共享的,因为所有进程共用一个内核空间。用户空间可以和内核空间通过系统调用交互,从而实现内存共享。 copy_from_user():将用户空间的数据拷贝到内核空间 copy_to_user():将内核空间的数据拷贝到用户空间

12. ActivityThread工作原理   ActivityThread是Android应用程序的主线程(UI线程)。理解ActivityThread类似理解Android线程管理的关键。   从源码我们可以看到ActivityThred在main函数中创建了Looper,这也是为什么我们再主线程使用Handler不需要自己构建Looper的原因。然后main()通过thread.attach(false)绑定应用进程。   主线程的消息机制还是又Handler去执行的。Looper的loop()方法则是起点和和兴。首先通过myLooper()方法获取Looper对象,取出Looper持有的MessageQueue。然后从MessageQueue取出Message,如果为null,说明线程正在推出。Message不为空,则调用Message的target handler对该Meeage分发,处理完毕后调用recycle()方法进行回收。

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        AndroidKeyStoreProvider.install();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

13. 嵌套滑动实现原理   嵌套滑动的实现与传统的事件分发不同,嵌套滑动式从子View传递给父View,从下到上的一个顺序。实现嵌套滑动,需要我们外层父布局实现NestedScrollingParent,内层子View实现NestedScrollingChild。   NestedScrollingParent接口需要涉及两个方法。首先是onStartNestedScroll(View child, View target, int nestedScrollAxes):nestedChild想要进行嵌套滚动时,会调用nestedParent的这个方法。这个芳法用于指示是否支持嵌套滚动。第二个是onNestedPreScroll(View target, int dx, int dy, int[] consumed):当我们滚动nestedChild时,nestedChild进行实际的滚动前,会先调用nestParent的这个方法。nestedParent在这个方法中可以把子View想要滚动的距离消耗掉一部分或是全部消耗。   关于原理,事实上,是nestedChild的onTouchEvent()方法中会对发生的Touch事件进行判断,若为DOWN事件则会调用startNestedScroll()方法;若为MOVE事件则会调用dispatchNestedPreScroll()方法。 参考文章:十分钟Android中的嵌套滚动机制

14. View的绘制原理,自定义View,自定义ViewGroup   View的绘制主要分为View的绘制和ViewGroup的绘制。对于单一View的绘制,在draw方法中,依次绘制背景、内容、装饰。而我们经常重写的onDraw方法其实就是绘制内容。而ViewGroup的绘制会扫尾复杂一些,首先还是绘制自身,依次是背景、内容、子View、装饰。绘制子View的时候ViewGroup会遍历子View,然后挨个绘制。整个绘制自上而下,树形结构循环。

15. View、SurfaceView 与 TextureView   SurfaceView与TextrueView是View的子类,特点是能够在独立线程中绘制和渲染,在专用的GPU线程中大大提高渲染的性能。 SurfaceView:可以通过SurfaceHolder.addCallBack在子线程中更新UI,由于SurfaceHolder的双缓冲功能,可以是画面更加流畅的运行,但是由于holder的存在导致画面更新存在间隔,并且同样因为holder导致SurfaceView不能进行像View一样setAlpha和setRotation。比较适用于类似坦克大战等需要不断告诉画布更新的游戏。 TextrueView:可以通过TextureView.setSurfaceTextureListener在子线程更新UI。适用于音视频播放器或相机应用的开发。

16. 主线程Looper.loop为什么不会造成死循环   首先,结论是主线程确实阻塞了,但是主线程在初始化过程中由ActivityThread的main()方法中会创建一套消息循环组件包括Looper,MessageQueue,Handler,然后由MessageQueue中的next()调用底层MessageQueue,通过epoll进行阻塞,有主线程消息的时候通过发送消息激活主线程。主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗,也就不会造成ANR。

17. ViewPager的原理   ViewPager实现视图左右滑动,原理在于创建了三个视图,屏幕中间展示的是中间的视图,而屏幕两侧隐藏着的则是预加载的视图,当左右滑动时,将预加载的视图显示出来,并且缓存当前视图。

18. BroadcastReceiver使用总结   首先自定义MyBroadcastReceiver继承BroadcastReceiver,作为接收者。并且注册需要接收的Intent意图,即广播。

public class MyBroadcastReceiver extends BroadcastReceiver {
    public static final String TAG = "MyBroadcastReceiver";
    public static int m = 1;

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.w(TAG, "intent:" + intent);
        String name = intent.getStringExtra("name");
        Log.w(TAG, "name:" + name + " m=" + m);
        m++;
        
        Bundle bundle = intent.getExtras();
        
    }
}

  其次,广播分为静态注册和动态注册。当接受有序广播时,在权限值相同时,动态注册的接收者优先接收广播。

//静态注册
<receiver android:name=".MyBroadcastReceiver" >
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

//动态注册
mBroadcastReceiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BROADCAST_ACTION);
registerReceiver(mBroadcastReceiver, intentFilter);

  最后通过sendBoradcast(Inteng i)方法发送广播的就可以了,如果要发送有序广播,则调用sendOrderedBroadcast(intent, receiverPermission, ...)

19. AndroidP新特性 1 室内WIFI定位 。该功能API在android.net.wifi.rtt下 2 刘海平的支持。能够通过windowInsets.getDisplayCutout()获取一些不应该绘制的部分屏幕。 3 增加了多许多通知的支持,优化了通知渠道。 4 新的图片解码类ImageDecoder 5 Android P引入了一个新的AnimatedImageDrawable类来绘制和显示GIF和WebP动画图像。

20. Asset目录与res目录的区别

asset与res.png ** 注意: ** 1 assets目录下的资源文件不会在R.java自动生成ID,所以读取assets目录下的文件必须指定文件的路径。可以通过AssetManager类来访问这些文件。比如要读取assets目录下的background.png:

Bitmap bgImg = getImageFromAssetFile( "background.png" );    
  
/**   
 * 从assets中读取图片   
 */    
private Bitmap getImageFromAssetsFile(String fileName)    
  {    
      Bitmap image = null;    
      AssetManager am = getResources().getAssets();    
      try    
      {    
          InputStream is = am.open(fileName);    
          image = BitmapFactory.decodeStream(is);    
          is.close();    
      }    
      catch (IOException e)    
      {    
          e.printStackTrace();    
      }     
      return image;    
  }    

2 如果在res/drawable目录下建了一个名为ppt的子目录,则通过 R.drawable.ppt.xxx 是获取不到ppt目录下的xxx文件的,会报 "R.layout.ppt cannot be resolved" 的错误。若在assets目录下建立一个名为ppt的子目录,并将background.png放入其中,则代码 Bitmap bgImg = getImageFromAssetFile( "ppt/background.png" ); 可正常运行。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏牛客网

百词斩Java一面面经

20210
来自专栏芋道源码1024

Redis 从入门到起飞(上)

1. Redis 介绍1.1 NoSQL 基本概念1.2 NoSQL 分类1.3 Redis 基本概念1.4 发展历史1.5 应用场景2. Redis 安装2....

22140
来自专栏Jackson0714

架构必经之路2 - 熔断机制

项目中要做一个熔断机制,预防对第三方的接口调用压力太大。下面我介绍下项目中用到的熔断机制。

19020
来自专栏coder修行路

关于python协程中aiorwlock 使用问题

最近工作中多个项目都开始用asyncio aiohttp aiomysql aioredis ,其实也是更好的用python的协程,但是使用的过程中也是遇到了很...

9320
来自专栏芋道源码1024

Redis 从入门到放飞(下)

Redis在实际使用过程中更多的用作缓存,然而缓存的数据一般都是需要设置生存时间的,即:到期后数据销毁。

12110
来自专栏高性能服务器开发

从“成都-go-戒炸鸡”的面试题开始说起

今天晚上“高性能服务器开发”QQ群(群号:49114021,有兴趣的读者可以加一下)里面一名叫“成都-go-戒炸鸡”的群友提出了他最近面试的一些面试题,面试题内...

27330
来自专栏Java3y

《阿里巴巴 Java开发手册》读后感

前一阵子一直在学Redis,结果在黄金段位被虐了,暂时升不了段位了,每天都拿不到首胜(好烦)。

17030
来自专栏zhisheng

Guava Cache 用法介绍

Guava Cache是在内存中缓存数据,相比较于数据库或redis存储,访问内存中的数据会更加高效。Guava官网介绍,下面的这几种情况可以考虑使用Guava...

11220
来自专栏java思维导图

从一笔金币充值去思考分布式事务

考虑支付重构的时候,自然想到原本属于一个本地事务中的处理,现在要跨应用了要怎么处理。拿充值订单举个栗子吧,假设:原本订单模块和账户模块是放在一起的,现在需要做服...

12340
来自专栏芋道源码1024

扒一扒我遇见过哪些厌恶的技术面试官

想必多半程序员都有过面试,或者被面试的经历,最近我观察了团队中两位团队长(小张与小李)的面试特点,让我想起了曾经的一些厌恶经历。

11520

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励