回顾一下基础的细节

博客转移到个人站点:http://www.wangchengmeng.club/2018/02/01/%E5%9B%9E%E9%A1%BE%E4%B8%80%E4%B8%8B%E5%9F%BA%E7%A1%80%E7%9A%84%E7%BB%86%E8%8A%82/

欢迎来吐槽

也许在逐渐的工作中,个人的技术知识在不断的成长,但往往会忽略掉一些基础细节知识,偶尔回顾一下,其实基础反而会更加突出一个人的学习。

layout_weight怎么理解?
    layout_weight的尺寸分配一般是先满足设置尺寸的分配然后剩下的尺寸在进行比例分配的。如果一个view需要设置1:2的比例显示,可以在LinearLayout中设置weightSum进行设置总的比例,然后在设置子View的比例。

LinerLayout:按照基准线对其中有个weightSum表示这个布局总分成多少分,比如2份,即使只有一个子控件weight=1,也只会占一半
weight:是按照比例划分的,先安排好固定大小的值,剩下的按照weight的比例分配
如果含有weight的每个空间都是match_parent,那就按照相反的比例去分配,
layout_gravity和gravity的区别?
首先:所有layout_开头的属性都是交给父容器去设置的。

layout_gravity是根据父布局设置位置的,而gravity是根据自身内容设置位置。
Handler机制是什么?
Handler是Android官方给我们提供的一套更新UI线程的机制,也是一套消息处理机制,可以通过Handler来处理消息,更新UI等。

然后Handler机制大约是这样的:首先Handler发送一个消息MessageQueue里面,然后通过Looper的loop方法进行无限循环,如果产生了一个新消息,那么就调用handler的handlermessage方法进行余下的操作。之所以这样做的原因是因为避免多线程并发更新UI线程所产生的问题的,如果我们允许其他子线程都可以更新界面,那么势必会造成界面的错乱(因为没有加锁机制),如果我们加锁,又会影响速度,所以,只能在主线程即UI线程里面更新界面。
只能在UI线程里面更新界面吗?
只能在主线程中更新UI,我相信是很多开发者信口拈来的一句话,但真的是这样?为什么要这样呢?

其实在子线程中也可以更新UI,翻翻ViewRootImp的源码就知道,之所以子线程不能更新界面,是因为Android在线程的方法里面采用checkThread进行判断是否是主线程,而这个方法是在ViewRootImpl中的,这个类是在onResume里面才生成的,因此,如果这个时候子线程在onCreate方法里面生成更新UI,而且没有做阻塞,就是耗时多的操作,还是可以更新UI的。
Android子线程更新UI的方式有几种?
一般情况下,我们都采用Handler的方式进行更新UI,当然,代码层的实现有不同的方法,比如可以使用Handler的post方法进行更新UI,或者用Handler的sendMessage方法进行更新UI,或者通过View的post方法进行更新,还有一个是runOnUIThread也是可以进行更新的。但这些本质上还是通过Handler进行子线程的更新。

当然,现在这种异步操作方式很多,AyncTsk、Rxjava等都屏蔽了内部消息机制的通信和处理,异步操作起来更加方便,特别是Rxjava这种响应式,异步处理更加方便。
使用Handler的时候一般会遇到什么问题?
比如说子线程更新UI,是因为触发了checkThread方法检查是否在主线程更新UI,还有就是子线程中没有Looper,这个原因是因为Handler的机制引起的,因为Handler发送Message的时候,需要将Message放到MessageQueue里面,而这个时候如果没有Looper的话,就无法循环输出MessageQueue了,这个时候就会报Looper为空的错误。可以在子线程中主动调用   Looper.myLooper()该方法,那样在子线程中就可以获取到轮训器了。详情可以仔细看一下[Handler源码分析](http://blog.csdn.net/xiaohuanqi/article/details/48899985)
HandlerThread是什么?
HandlerThread是Android官方给我们提供好的一套子线程的Handler,也就是异步处理机制,它是为了避免线程切换导致空指针异常的错误。
怎么在主线程中通知子线程?这样做有什么好处?
可以利用HandlerThread进行生成一个子线程的Handler,并且实现handlerMessage方法,然后在主线程里面也生成一个Handler,然后通过调用sendMessage方法进行通知子线程。同样,子线程里面也可以调用sendMessage方法进行通知主线程。这样做的好处比如有些图片的加载啊,网络的访问啊可能会比较耗时,所以放到子线程里面做是比较合适的。
Android中有几种布局?
Android中一般有五种布局,首先比较常用的两种布局是LinearLayout和RelativeLayout,就是线性布局和相对布局,线性布局的话一般是指定方向,然后从左往右或者从上往下排列的,相对布局的话是依赖与父控件或者其他View进行确定位置的。然后还有FrameLayout,TableLayout和AbsoluteLayout,其中FrameLayout就是一层一层的叠加的,TableLayout有点类似与HTML的表格,然后AbsoluteLayout的话是通过坐标确定位置的,因为Android屏幕多种多样,所以一般都不推荐用绝对布局。
说下Activity的生命周期
Activity的生命周期是这样的,首先当用户启动一个Activity的时候,就会调用onCreate的方法,这个时候一般把要初始化的东西都放到这里,接着就会调用onStart方法,这个时候如果需要监听UI的变化或者数据的变化,一般可以放到这里,然后执行onResume方法,这个时候界面就已经显示好了。然后如果这个时候按了home键的话,就会调用onPause方法,接着是执行onStop方法,这个时候可以取消或停止刚才监听的UI或数据变化的监听器,接着如果这个时候你返回到刚才的Activity的话,可能产生两种情况,一种就是因为系统回收了你的Activity,这个时候就重新执行onCreate onStart onResume,如果系统没有回收你的Activity的话,就执行onRestart onResume方法,如果这个时候又不想回去,刚好内存不够了,就会执行onDestory方法进行销毁。
Activity的启动模式有几种?
有四种启动模式,首先默认的启动模式是standard,就是没创建一个Activity就会将其压入任务栈栈顶,不管是否存在,一种是singleTop,就是如果任务栈栈顶刚好是要显示的Activity,它就不会创建一个新的Activity,并调用onNewIntent()方法,如果不是,就会重新创建一个新的Activity,一种是singleTask,如果Activiy 已经存在,不管是栈顶还是栈中,它就会移除该 Activity上面所有的任务使该Activity位于栈顶,并调用onNewIntent()方法。一种是singleInstance,使该启动模式的Acitivity位于一个单独开启的栈中。
Activity的缓存方法是怎么样的?
可以在onSaveInstanceState中将要保存的数据保存起来,可以通过Bundle进行临时保存,然后在onCreate中的Bundle中取出来进行恢复,这样就可以避免Activity被销毁的时候数据的清空。因为onSaveInstanceState在Activity销毁之前必然会调用,所以可以在这里做缓存操作。记住,这个是系统未经你同意的时候就销毁的时候才会的。
Fragment的生命周期是怎么样的,跟Activity有什么关系?
Fragment是Activity的一个组件片段,也就是说他的生命周期是依赖于Activity的,但是它比Activity多了几个生命步骤,首先onAttach当fragment加入Activity的时候调用,然后是onCreate进行启动Activity,接着是onCreateView进行绘制View,一般的View就是这里绘制的,然后是onActivityCreated,接着跟Activity的生命周期差不多,调用onStart和onResume,然后是onPause,onStop,如果这个时候需要回收Fragment的时候,就会调用,接着是onDestoryView销毁布局,然后是onDestory和onDetach完成。
为什么在Service中创建子线程而不是Activity中?
因为假如在Activity中创建子线程的话,当Activity销毁的时候,这个时候重新再调用该Activity就会重新走新的生命周期,这个时候就无法再重新获取到刚才的子线程,而且如果在一个Activity中创建子线程,另一个Activity也无法操作该子线程,但是Service就不一样,所有的Activity都可以和Service关联,即使是Activity被销毁了,只要再重新建立联系就好了,所以,一般后台任务都是通过Service去控制的。此外,如果在Activity中创建的子线程当Activity销毁的时候子线程任务还没完成,那么会出现内存泄漏。
Intent可以传递哪些数据?怎么传递?
Intent可以传递String类型的,基本类型,还有对象,如果是基本类型,可以通过Intent的方法直接传递就好了,如果是对象的话,一般可以通过Bundle进行传递,有些对象需要进行序列化和包裹化。
怎么启动Service?
有两种启动方式:一种是通过startService进行启动,这个时候Service跟启动的Activity没有关联,只有当调用stopService的时候才会结束Service,他的生命周期是:onCreate->onStartCommand->Service Run ->stopService->onDestory();

如果是通过bindService启动的,那么这个Service就跟启动他的进程有关了,这个时候如果启动他的进程销毁了,那么这个Service也紧跟着销毁了或者直接调用unBindService,生命周期是:onCreate->onBindService->Service Run->unBindService->onDestory.
广播的动态注册和静态注册有什么区别?
静态注册:在AndroidManifest.xml文件中进行注册,当App退出后,Receiver仍然可以接收到广播并且进行相应的处理

动态注册:在代码中动态注册,当App退出后,也就没办法再接受广播了。
URI的格式和意义。
URI叫做统一资源标识符,主要分四部分,第一部分是协议名称,可以是官方的,也可以自定义,第二部分是是URI的授权部分,是唯一标识符,用来定位ContentProvider。格式一般是自定义ContentProvider类的完全限定名称,注册时需要用到,如:com.alexzhou.provider.NoteProvider第三部分部分和第四部分部分:是每个ContentProvider内部的路径部分,C和D部分称为路径片段,C部分指向一个对象集合,一般用表的名字,如:/notes表示一个笔记集合;D部分指向特定的记录,如:/notes/1表示id为1的笔记,如果没有指定D部分,则返回全部记录。
Android存储形式有几种?
1.SQLite方式,SQLite是一个轻量级的数据库, 支持基础的SQL语法,官方提供了一个SQLiteDatabase的类,并提供一些api。
2.SharedPreference:存储简单的参数信息,本质上是xml.
3.File:文件存储,常用来存储大数据量的数据,但是更新麻烦。
4.ContentProvide,一般情况下数据在各个应用中是私密的,但是因为它也是可以用来存储分享数据。
5.网络存储,将数据放到网络云里面,然后通过网络进行访问。
如何判断应用被强制杀死?以及如何解决应用被强制杀死?
可以在Application中定义一个static常量,赋值为-1,然后在欢迎页面修改值为0,如果被强杀,Application被重新初始化,这个时候如果父Activity判断该常量是多少。

如果在每一个Activity的onCreate里判断是否被强杀,冗余了,封装到Activity的父类中,如果被强杀,跳转回主界面,如果没有被强杀,执行Activity的初始化操作,给主界面传递intent参数,主界面会调用onNewIntent方法,在onNewIntent跳转到欢迎页面,重新来一遍流程。
Json有什么优势?
JSON格式简单,兼容性高,易于读写,并且传输的带宽小,方便解析,并且服务端容易生成。
动画有哪些类型,动画的区别?
 在Android3.0以前,动画有两种类型,一种是补间动画,即tween,他指的是通过自身的变形达到的效果,比如说透明度的变化,放大缩小等,还有一种是帧动画,即Frame,是通过一针一针的对图片进行连贯起来播放的,Android3.0的时候定义了一个属性动画,即PropertyAnimation,指的是控件的真实移动,就是不断的改变某些属性的值进行的。具体可以通过实现ValueAnimator等类进行实现。
Asset和res目录的区别?
Asset不会在R文件里面生成一个ID,所以它不能直接用R文件来调用,这就说明要读取Asset目录下的文件需要指定文件的目录,可以通过AssetManager类来访问。res会自动在R文件里面生成id,直接可以用R.的方式进行访问资源。
Android怎么优化启动速度?
因为Android启动应用程序一般分为两种,一种是冷启动,就是要启动的应用程序没有后台进程的启动,这个时候需要重新分配一个进程给他,所以这个时候会先初始化Application类,再创建和初始化MainAcitvity 类,最后显示到界面上,还有一种是热启动,就是后台还有该应用的进程,比如说按下的home键或者返回键,虽然表面上退出了,但是在任务栈里面仍然还存在的,这个时候就不需要再初始化Application类了,只要重新初始化MainActivity了。因为大多数应用的启动都是冷启动(用户习惯将应用程序在任务栈中删除),所以这个时候可以采取这几个步骤,比如尽量不在Application的构造器,attachBaseContext方法和onCreaete方法中做过多的耗时操作,将一些数据预取放在异步线程中,可以采Callback的方式。优化MainActivity,尽量不要在MainActivity的onCreate,onStart和onResume等方法里面做过多的耗时操作。
Android怎么加快Activity的显示速度?
首先因为Activiy的显示是在这几个生命周期之间的,onCreate,onStart,和onResume,这个时候我们需要将我们需要初始化的数据分类,比如说我们将一些只需要初始化的一次的数据放到onCreate中,尽量不要在onCreate中做耗时的操作,然后将需要加载比较长时间的数据放到onResume中,可以利用handler的机制进行更新UI,或者放到AsyncTask逐个显示,然后可以设置一些动画进行显示,如果这个时候有许多数据都是一次显示的, 那么可以在onCreate里面进行标记,并且在onResume里面判断是否需要初始化,初始化完成以后就立刻false掉,这样就可以避免多次初始化了,也可以提升Activity的显示速度。
Android内存泄漏可以引发什么问题?
可能使程序造成卡顿的现象,或者莫名的消失,因为内存过大,系统就更可能的回收这一块的内存,或者直接崩溃。
产生Android内存泄漏的原因有什么?
handler等生命周期较长的匿名内部类,因为这些匿名内部类可能会持有外部的引用,从而导致短期内就算Activity退出而一些资源没有被回收,数据结构未优化,图片没有优化,没有注意到对象的生命周期,造成许多对象没有被回收,过多的使用Service,单例的过多使用,无效的资源等等。
怎么处理Android内存泄漏?
可以使用更加轻量的数据结构,比如ArrayMap而不是HashMap,避免在Android里面使用enum,减小Bitmap对象的内存占用,可以采用缩放比例,或者使用缓存缩略图的方式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值