首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Android知识点基础篇(二)

Android知识点基础篇(二)

作者头像
饮水思源为名
发布2019-01-07 13:34:39
发布2019-01-07 13:34:39
1.1K0
举报
文章被收录于专栏:Android小菜鸡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()方法进行回收。

代码语言:javascript
复制
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意图,即广播。

代码语言:javascript
复制
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();
        
    }
}

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

代码语言:javascript
复制
//静态注册
<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:

代码语言:javascript
复制
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" ); 可正常运行。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019.01.03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档