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("");

        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();
        
    }
}

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

//静态注册

    
        
    
    
        
    


//动态注册
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目录的区别

Android知识点基础篇(二)_第1张图片
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" ); 可正常运行。

End

笔者的Github Blog,希望各位大大提意见,点个star,谢谢
传送门:WusyBlog

求互粉互赞,互赞所有文章可以私聊我。哈哈,希望我们的原创文章能让更多朋友看到,一起变强。

笔者新开通了微信公众号——饮水思源|wusy 计划持续运营,每日为您分享Android干货、原创文章。微信扫描下方的二维码关注我,开发学习路上不迷路。谢谢各位


饮水思源|wusy.jpg

你可能感兴趣的:(Android知识点基础篇(二))