Android面经-基础篇(持续更新...)
来源:互联网 发布:机械手模拟软件 编辑:程序博客网 时间:2024/05/19 19:58
前言:顺序是按照郭霖先生<第二行代码>的书籍目录进行的,可以前往图灵社区购买正版支持,但如果觉得还贵一点,可以百度搜索下载盗版看的(但都希望哥们可以支持正版,毕竟电子版跟纸质版也不贵)
Activity A启动Activity B经历的生命周期顺序
探究的源码:关于探究Avctivity与Fragment的生命周期源码-CSDN下载
开启的方法
btClick.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, SecondActivity.class); Log.i("xx","intent执行前前前前"); startActivity(intent); Log.i("xx","intent执行之后"); } });
加上finish()方法
Button btClick = (Button) findViewById(R.id.bt_click); btClick.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, SecondActivity.class); Log.i("xx","intent执行前前前前"); startActivity(intent); finish(); Log.i("xx","intent执行之后"); // finish();放来这里也是一样的,finish()不是立刻执行的,都是按照生命周期走的 } });
关于Activity的几篇好文章:
1.深入理解Activity的生命周期 - 简书
2.Android开发:5分钟解析Activity&Fragment生命周期 - 简书
3.Android中Activity数据的保存和恢复 - 简书
4.Android-Activity所应该了解的大概就这样。(上) - 简书
5.你应该知道的Activity状态的保存与恢复 - ithuangqing - CSDN博客
关于第三篇Activity中的作者观点
当我还没有自学Android时,玩着一些APP就会产生一个疑问,比如我在一个输入框中输入了大量文字没有提交或者保存。此时来了一个电话,如果退回的时候,输入框里面的文字消失了,那我可能会砸了电话,所以这个保存数据的操作,是Android开发者做的吗?
然而是不需要的,因为Android的View本身自己就实现了onSaveInstanceState方法,这些控件自己就具有保存临时数据和恢复临时数据的能力。
作者:MeloDev
來源链接:http://www.jianshu.com/p/6622434511f7
个人理解:
其实就是EditText等View控件具有暂时保存临时数据的功能(其中视频中的是Home返回桌面,并非是我们按返回键返回的)-这里对于没有走onDestroy()方法而言的,如果走onDestroy()方法就需要自己保存数据了
在这里,总结一下个人对数据存取的理解:
- 临时数据使用onSaveInstanceState保存恢复,永久性数据使用onPause方法保存。
- 1.由于EditText以及TextView等View组件内部都实现了onSaveInstanceState()方法,具备一些临时的、非永久数据存储并进行恢复.不需要考虑不走onDestroy()方法,,比如Home回到桌面再回来以及接个电话再回来的情况(这里先排除由于内存不够被杀死的情况,下面会提及),View组件都会保存数据的
2.针对由于内存不够被杀死的情况(在onPause()或者onStop()方法就被杀死,即非正常死亡),这样的话系统就会调用Activity的onSaveInstanceState()方法,那么我们就需要在此重写这个方法进行保存数据,然后在onCreate()方法进行恢复
PS:Activity的onSaveInstanceState(Bundle)方法在按Home键以及屏幕锁屏时候会走(注意该方法名字onSaveInstanceState(Bundle,PersistableBundle)不会走,其实我个人觉得就是怕内存不够被杀死才会使用onSaveInstanceState(Bundle)这个方法的
//在MainActivity中添加如下代码就可以将临时数据进行保存:@Overrideprotected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); String tempData = "Something you just typed"; outState.putString("data_key", tempData);}/*数据是已经保存下来了,那么我们应该在哪里进行恢复呢?细心的你也许早就发现,我们一直使用的onCreate()方法其实也有一个Bundle类型的参数。这个参数在一般情况下都是null,但是如果在活动被系统回收之前有通过onSaveInstanceState()方法来保存数据的话,这个参数就会带有之前所保存的全部数据,我们只需要再通过相应的取值方法将数据取出即可。修改MainActivity的onCreate()方法,如下所示:*/@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "onCreate"); setContentView(R.layout.activity_main); if (savedInstanceState != null) { String tempData = savedInstanceState.getString("data_key"); Log.d(TAG, tempData); } ...}
- 3.永久性数据使用onPause方法保存,我们可以进行一些轻量级的存储数据和去初始化的工作,不能太耗时,因为在跳转Activity时只有当一个Activity执行完了onPause方法后另一个Activity才会启动,而且android中指定如果onPause在500ms即0.5秒内没有执行完毕的话就会强制关闭Activity。
- 4.对于重量级的暂时还没有找到很好的合适办法!!!
Activity中启动Fragment的生命周期顺序
源码:关于探究Avctivity与Fragment的生命周期源码-CSDN下载
1.在MainActivity中定义的fragment
<fragment android:id="@+id/top_fragment" android:name="com.example.yueyue.myapplication.RightFragment" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/>
执行的生命周期如下
PS:这里值得注意的是最后两个方法:
I/xx: RightFragment onStart…
I/xx: MainActivity onStart
I/xx: MainActivity onResume
I/xx: RightFragment onResume…
2.在动态添加frament
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i("xx",TAG+" onCreate"); initView(); } //在MainActivity中onCreate调用initView方法的 private void initView() { fr_container = (FrameLayout) findViewById(R.id.fr_container); bt_click = (Button) findViewById(R.id.bt_click); bt_click.setOnClickListener(this); //MainActivity走了onResume,RightFragment才走onResume relaceFrgment(new RightFragment()); } //开启一个Fragment private void relaceFrgment(Fragment fragment) { FragmentManager fm = getSupportFragmentManager(); FragmentTransaction tr = fm.beginTransaction(); tr.replace(R.id.fr_container, fragment);// tr.commitAllowingStateLoss(); tr.commit(); }
PS:这里值得注意的是最后两个方法(这里的方法不值得参照,只想引出下面的小总结而已):
小总结:无论动态添加还是静态xml添加的fragment,顺序都是
RightFragment onStart -> MainActivity onStart -> MainActivity onResume -> RightFragment onResume
3.Frgament替换Frgament的生命周期方法
private static int type = 0; @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_click://使用Button开启Fragment relaceFrgment(type++); break; } } private void relaceFrgment(int type) { if (type % 2 == 0) { relaceFrgment(new RightFragment()); } else { relaceFrgment(new AnotherRightFragment()); } } private void relaceFrgment(Fragment fragment) { FragmentManager fm = getSupportFragmentManager(); FragmentTransaction tr = fm.beginTransaction(); tr.replace(R.id.fr_container, fragment);// tr.commitAllowingStateLoss(); tr.commit(); }
I/xx: RightFragment 构造方法走了…
I/xx: RightFragment onAttach走了…
I/xx: RightFragment onCreate走了…
I/xx: RightFragment onCreateView走了…
I/xx: RightFragment onActivityCreated…
I/xx: RightFragment onStart…
I/xx: RightFragment onResume…
I/xx: AnotherRightFragment 构造方法走了…
I/xx: AnotherRightFragment onAttach走了…
I/xx: AnotherRightFragment onCreate走了…
I/xx: RightFragment onPause…
I/xx: RightFragment onStop…
I/xx: RightFragment onDestroyView…
I/xx: RightFragment onDestroy…
I/xx: RightFragment onDetach…
I/xx: AnotherRightFragment onCreateView走了…
I/xx: AnotherRightFragment onActivityCreated…
I/xx: AnotherRightFragment onStart…
I/xx: AnotherRightFragment onResume…
PS: Frgament替换Frgament跟Activity开启另外一个Activity执行的有点出入
4.Activity退出的时候,依附在Activity的fragment的生命周期
I/xx: AnotherRightFragment onPause…
I/xx: MainActivity onPause
I/xx: AnotherRightFragment onStop…
I/xx: MainActivity onStop
I/xx: AnotherRightFragment onDestroyView…
I/xx: AnotherRightFragment onDestroy…
I/xx: AnotherRightFragment onDetach…
I/xx: MainActivity onDestroy
5.当事务加入addToBackStack(null);的时候
private void relaceFrgment(Fragment fragment) { FragmentManager fm = getSupportFragmentManager(); FragmentTransaction tr = fm.beginTransaction(); tr.replace(R.id.fr_container, fragment); tr.addToBackStack(null);//点击可以返回上一个Fragment tr.commit(); }
I/xx: RightFragment 构造方法走了…
I/xx: RightFragment onAttach走了…
I/xx: RightFragment onCreate走了…
I/xx: RightFragment onCreateView走了…
I/xx: RightFragment onActivityCreated…
I/xx: RightFragment onStart…
I/xx: RightFragment onResume…
这里执行了替换操作————————–
I/xx: AnotherRightFragment 构造方法走了…
I/xx: AnotherRightFragment onAttach走了…
I/xx: AnotherRightFragment onCreate走了…
I/xx: RightFragment onPause…
I/xx: RightFragment onStop…
I/xx: RightFragment onDestroyView…
I/xx: AnotherRightFragment onCreateView走了…
I/xx: AnotherRightFragment onActivityCreated…
I/xx: AnotherRightFragment onStart…
I/xx: AnotherRightFragment onResume…
小总结:从这里看出,事物加入了addToBackStack(null)之后,如果在替换的时候加入了addToBackStack()方法,此时RightFragment就不会走onDestroy()方法以及onDetach()方法()方法
当点击返回键之后
I/xx: AnotherRightFragment onCreateView走了…
I/xx: AnotherRightFragment onActivityCreated…
I/xx: AnotherRightFragment onStart…
I/xx: AnotherRightFragment onResume…
这里执行了返回键操作————————–
I/xx: AnotherRightFragment onPause…
I/xx: AnotherRightFragment onStop…
I/xx: AnotherRightFragment onDestroyView…
I/xx: AnotherRightFragment onDestroy…
I/xx: AnotherRightFragment onDetach…
I/xx: RightFragment onCreateView走了…
I/xx: RightFragment onActivityCreated…
I/xx: RightFragment onStart…
I/xx: RightFragment onResume…
可以看出,返回键是执行销毁当前Fragment的,所以会走 ,但上一个Fragment由于addToBackStack()方法就不需要不执行onAttach()方法以及onCreate()方法(因为它被替换的时候也不执行onDestroy()方法以及onDetach()方法()方法)
这里还有几篇特别好的文章:
1.实现Activity和Fragment之前通信 - CSDN博客
2.死磕 Fragment 的生命周期 - MeloDev的博客 - CSDN博客 ,这里的源码框架很不错:itsMelo/BuzzerBeater: 迈出开源的第一步,初心为鉴,时间为证。–这里实现的懒加载不是很正确,看下面的[1][2][3][4]会对你有所启发
[1] android fragment onHiddenChanged的使用 - CSDN博客 ,这里是为了解释第二篇博文准备的
[2] Fragment的setUserVisibleHint方法实现懒加载,但setUserVisibleHint 不起作用? - Leevey·L - 博客园 ,这里是为了解释第二篇博文准备的
[3] TabLayout使用详解 - 简书 ,这里是为了解释第二篇博文准备的
[4] 套在ViewPagerz中的Fragment在各种状态下的生命周期 - 格物穷理 - CSDN博客
3.Android – Fragment 基本用法、生命周期与细节注意 - 简书
4.Fragment全解析系列(一):那些年踩过的坑 - 简书
关于BroadcastReceiver
1.Android中广播的使用(动态、静态注册的区别,有序无序广播的使用) - OONullPointerAlex的博客 - CSDN博客
2.Android四大组件:BroadcastReceiver史上最全面解析 - 简书
PS:
1.广播不可以进行任何的耗时操作,通常用来打开一个程序的其他组件(创建一条状态栏通知或者启动一个服务)
2.本地LocalBroadcastReceiver是无法通过静态注册的方式来接收的
3.对于操作特别频繁的广播事件,比如屏幕的解锁屏,电池电量的变化,必须使用动态注册才得(即不可以在清单文件注册)
数据存储方案
Android 数据存储五种方式使用与总结 - CSDN博客
运行时权限(危险权限)
- Runtime Permissions(郭霖CSDN公开课) - 简书
- Android6.0运行时权限解决方案 - 简书
在这里,我建议去Github寻找那些已经封装好的类直接使用即可,毕竟那些代码真的很多,而且很容易忘记
ContentProvider
1.ContentProvider从入门到精通 - 简书
2.Android 进阶11:进程通信之 ContentProvider 内容提供者 - CSDN博客
这里感觉初级复习应该好好回去看通信录以及短信备份更有效,如果是进阶的话,建议从设计模式的角度去看这个组件更好(ContentProvider跟BroadcastReceiver好像都是观察者模式)
丰富你的程序
使用通知
- Android 中通知的基本使用 - 简书
- Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它) - 未来之路 的专栏 - CSDN博客
- 你真的了解Android Notification吗? - CSDN博客
拍照或者从相册选择照片
Android开发之调用摄像头拍照 - 小朵八的博客 - CSDN博客
播放视频或者音频
- Android多媒体编程——MediaPlayer播放音乐 - CSDN博客
网络技术
WebView
- Android开发:最全面、最易懂的Webview使用详解 - 简书
- 最全面总结 Android WebView与 JS 的交互方式 - 简书
Android多线程编程
- android: 多线程编程基础 - dodo-yufan - 博客园
- android: 使用 AsyncTask - dodo-yufan - 博客园
- Java多线程系列目录(共43篇) - 如果天空不死 - 博客园
服务
Android Service完全解析,关于服务你所需知道的一切(上) - 郭霖的专栏 - CSDN博客
Android Service完全解析,关于服务你所需知道的一切(下) - 郭霖的专栏 - CSDN博客
服务的生命周期
1.继承一个服务
public class MyService extends Service { private static final String TAG=MyService.class.getSimpleName(); public MyService() { Log.i(TAG,"MyService构造方法走了...."); } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. Log.i(TAG,"onBind"); return new MyBinder(); } @Override public void onCreate() { super.onCreate(); Log.i(TAG,"onCreate"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG,"onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public boolean onUnbind(Intent intent) { Log.i(TAG,"onUnbind"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.i(TAG,"onDestroy"); super.onDestroy(); } //这里是BindService使用的 class MyBinder extends Binder{ public void startDownload() { Log.i(TAG,"startDownload"); } public void stopDownload() { Log.i(TAG,"stopDownload......."); } }}
2.开启服务或者销毁服务(测试的普通Service)
@Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_click1: //开启服务 Intent intent=new Intent(MainActivity.this,MyService.class); startService(intent); break; case R.id.bt_click2: //销毁服务 Intent intent1=new Intent(MainActivity.this,MyService.class); stopService(intent1); break; } }
当你点的第一次的时候,服务走的生命周期
当你点多几次,只走onStartCommand()方法
当你点击停止服务(之后点击多次不会走任何方法,也不会报错)
当你再点击开启服务的时候
3.开启或者关闭bindService
@Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_click1: //开启服务 Intent intent = new Intent(MainActivity.this, MyService.class); if (mConn==null) { mConn = new MyConn(); } bindService(intent, mConn, BIND_AUTO_CREATE); break; case R.id.bt_click2: //销毁服务,bindService只可以点击一次(多次点击会报错) //报错:java.lang.IllegalArgumentException: Service not registered if (mConn != null) { unbindService(mConn); mConn = null; } break; } } class MyConn implements ServiceConnection { /** * MyService中的onBind()方法不为null才会走这方法onServiceConnected */ @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mMyBinder = (MyService.MyBinder) iBinder; mMyBinder.startDownload(); Log.i("MyService", "onServiceConnected...........componentName" + componentName); } @Override public void onServiceDisconnected(ComponentName componentName) { mMyBinder.stopDownload(); Log.i("MyService", "onServiceDisconnected...........componentName" + componentName); } }
点击进行绑定:
多次点击绑定按钮:
if (mConn==null) { mConn = new MyConn(); }
换成这样的代码就不同了
// if (mConn==null) {//这样点击停止服务,无法执行onUnbind()以及onDestroy()进行销毁,下面探究1讲解 mConn = new MyConn();// }
PS:每点击一次就走一个onServiceConnected()方法,但Service相关方法不走了…
点击停止服务(点击一次):
点击多次停止服务
所以代码要这样写:
if (mConn != null) { unbindService(mConn); //这里一定要置为空,方便上边的条件mConn != null成立 mConn = null; }
探究1:
public void onClick(View v) { switch (v.getId()) { case R.id.bt_click1: //开启服务 Intent intent = new Intent(MainActivity.this, MyService.class); //if (mConn==null) { mConn = new MyConn(); //} Log.i(MyService.class.getSimpleName(), "新创建的mConn:" + mConn); bindService(intent, mConn, BIND_AUTO_CREATE); break; case R.id.bt_click2: //销毁服务,bindService只可以点击一次(多次点击会报错) //报错:java.lang.IllegalArgumentException: Service not registered //if (mConn != null) { Log.i(MyService.class.getSimpleName(), "销毁的时候mConn:" + mConn); unbindService(mConn); //mConn = null; //} break; } }
第一次点击绑定服务:新创建的mConn:com.example.yueyue.myapplication.MainActivity$MyConn@fe84028第二次点击绑定服务:新创建的mConn:com.example.yueyue.myapplication.MainActivity$MyConn@a0676e6第一次点击解绑服务:销毁的时候mConn:com.example.yueyue.myapplication.MainActivity$MyConn@a0676e6第二次点击解绑服务:销毁的时候mConn:com.example.yueyue.myapplication.MainActivity$MyConn@a0676e6(报异常 java.lang.IllegalArgumentException: Service not registered)
个人见解:因为 bindService()中的第三个参数flags中的BIND_AUTO_CREATE表示当收到绑定请求时,如果服务尚未创建,则即刻创建,在系统内存不足,需要先销毁优先级组件来释放内存,且只有驻留该服务的进程成为被销毁对象时,服务才可被销毁;所以因为之前已经创建该服务了,所以就不会再创建了,服务的任何方法都不会再走,但由于每次都是new Conn(Conn是实现了ServiceConnection接口),所以都会回调一次onServiceConnected方法(这里我水平问题:猜测是Conn相当于一条桥梁,当调用者(比如Activity)与MyService每搭桥一次成功,然后Conn就会回调一次ServiceConnection方法)
注意:调用者(比如Activity)与MyService可以搭载多座桥(捆绑服务bindService开启的情况下)
为什么销毁的时候会不走呢?这里不是不走,这里需要注意一点:当所有连接MyService的Conn都unBind的时候,MyService才会走onUnbind以及onDestroy方法
证明代码(使用一个sMyConnList来管理):
private static List<MyConn> sMyConnList = new ArrayList<>(); @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_click1: //开启服务 Intent intent = new Intent(MainActivity.this, MyService.class); mConn = new MyConn(); sMyConnList.add(mConn); Log.i(MyService.class.getSimpleName(), "新创建的mConn:" + mConn); bindService(intent, mConn, BIND_AUTO_CREATE); break; case R.id.bt_click2: //销毁服务,bindService只可以点击一次(多次点击会报错) for (MyConn myConn:sMyConnList) { Log.i(MyService.class.getSimpleName(), "销毁的时候mConn:" + mConn); unbindService(myConn); } break; } }
Service小总结:
- start方式开启服务的特点:
- 第一次点击开启服务按钮,服务就会走构造方法MyService()->onCreate()->onStartCommand()
- 服务中的onStartCommand()跟Activity中的onStart()方法只是名字不同,但作用是一样的
- 第二次点击开启服务的时候(之前没有销毁),服务只走onStartCommand()方法
- 服务一旦被开启,服务就会在后台长期运行,直到用户手动停止
- bindService开启服务的特别:
- 第一次点击按钮,会执行 构造方法MyService()->onCreate()->onBind()方法
- 当onBind()方法返回null的时候,onServiceConnected()是不执行的
- 第二次点击开启服务,服务没有走任何的方法
- 这种服务不求同时生,但求同时死(这里指的是调用者(比如Activity)与服务之间的关系)
- 服务不可以多次解绑,多次解绑会导致报异常
- 通过bindService方法开启服务,服务不能在设置页面找到,相当于一个隐形的服务
- 类ServiceConnection中的onServiceDisconnected()方法在正常情况下是不被调用的,它的调用时机是当Service服务被异外销毁时,例如内存的资源不足时这个方法才被自动调用。
- Service.onBind如果返回null,则调用 bindService 会启动 Service,但不会连接上 Service,因此 ServiceConnection.onServiceConnected不会被调用,但你任然需要使用unbindService 函数断开它,这样Service 才会停止。
- 实际上服务都只会存在一个实例
- 只有Activity,Service,和ContentProvider可以绑定到一个service—你不能从一个BroadcastReceiver绑定到service.BroadcastReceiver的context生命周期很短暂,bindService没有什么意义。
混合开启服务
- 混合使用startService,bindService,以及tartForegroud方法使用总结 - pugongying1988的专栏 - CSDN博客
- Android里Service的bindService()和startService()混合使用深入分析 - CSDN博客
- 如何提升 service 等级,不被kill(整合) - 晕菜一员 - 博客园
- Android:进程(process)优先级、startForeground - 天空没有痕迹但我飞过 - 51CTO技术博客
一般混合服务的需求都是:既想让服务在后台长期运行又想调用服务里面的办法(即与服务实现交互)
一般顺序:
1.先调用startService方法开启服务,保证服务能够在后台长期运行(MyService构造方法->onCreate->onStartCommand)
2.调用bindService方法,去获取中间对象(这时候走onBind以及类ServiceConnection中的onServiceConnected)
3.调用unBindService解绑服务(走onUnbind方法,但没有走onDestroy方法)
4.调用stopService(走onDestroy方法)
但如果是另外一种顺序:
1.bindService(MyService构造方法->onCreate->onBind以及类ServiceConnection中的onServiceConnected)
2.startService(只走onStartCommand)
3.stopService(什么办法都不会走)
4.unBindService(onUnbind->onDestroy)
但还有一种顺序:
1.bindService(MyService构造方法->onCreate->onBind以及类ServiceConnection中的onServiceConnected)
2.startService(只走onStartCommand)
3.unBindService(onUnbind)
4.stopService(onDestroy)
Material Design(质感设计)
- CardView:CardView在API 21以下的圆角效果处理 - 简书
- TabLayout:Design库-TabLayout属性详解 - 简书
自定义View
- Android LayoutInflater原理分析,带你一步步深入了解View(一) - 郭霖的专栏 - CSDN博客 -三篇
- Android View 事件分发机制 源码解析 (上) - Hongyang - CSDN博客 -几篇
- Android绘图机制(一)——自定义View的基础属性和方法 - 刘桂林的博客 - CSDN博客-三篇
- Android学习Scroller(五)——详解Scroller调用过程以及View的重绘 - CSDN博客
- scrollTo与scrollBy用法以及TouchSlop与VelocityTracker解析 - zejian的博客 - CSDN博客 -两篇
- 自定义控件三部曲之动画篇(四)——ValueAnimator基本使用 - 启舰 - CSDN博客 -他写的东西都很广很全容易理解
- 你真的会用OnTouchListener、OnClickListener、OnLongClickListener监听事件么? - thuai - 博客园
探讨:加载布局inflate(int resource, ViewGroup root, boolean attachToRoot)
- 如果root为null,attachToRoot将失去作用,设置任何值都没有意义。
- 如果root不为null,attachToRoot设为true,则会给加载的布局文件的指定一个父布局,即root。
- 如果root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。
- 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true。
郭霖先生的博客讲解到:Android LayoutInflater原理分析,带你一步步深入了解View(一) - 郭霖的专栏 - CSDN博客
验证代码:
1.activity_main.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:id="@+id/lyo_content" android:layout_width="200dp" android:layout_height="200dp" android:background="#ff0" android:orientation="vertical"/></LinearLayout>
2.button_layout.xml:
<?xml version="1.0" encoding="utf-8"?><Button xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="300dp" android:layout_height="80dp" android:text="Button"></Button>
3.button_layout1.xml:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:layout_width="300dp" android:layout_height="80dp" android:text="Button"/></RelativeLayout>
4.
mainLayout = (LinearLayout) findViewById(R.id.main_layout); lyo_content = (LinearLayout) findViewById(R.id.lyo_content); LayoutInflater layoutInflater = LayoutInflater.from(this); View buttonLayout0 = layoutInflater.inflate(R.layout.button_layout, null); mainLayout.addView(buttonLayout0); View buttonLayout00 = layoutInflater.inflate(R.layout.button_layout, null); lyo_content.addView(buttonLayout00); View buttonLayout1 = layoutInflater.inflate(R.layout.button_layout, mainLayout, true); //mainLayout.addView(buttonLayout);不可以再设置父布局buttonLayout1,因为它有了父布局 View buttonLayout2 = layoutInflater.inflate(R.layout.button_layout, mainLayout, false); mainLayout.addView(buttonLayout2); View buttonLayout22 = layoutInflater.inflate(R.layout.button_layout, mainLayout, false); lyo_content.addView(buttonLayout22); View buttonLayout3 = layoutInflater.inflate(R.layout.button_layout1, null); mainLayout.addView(buttonLayout3);
结果:
解释:当一个view加载的时候没有父布局(没有xml中设置以及代码加载时候没有指定),设置的layout_width跟layout_height都是无用的,一个布局有且仅有绑定在一个布局(只可以绑定一次),一旦绑定必须解绑才可以绑定到其他布局去
这里有两个有趣的问题:
1.如下面代码所示,两个加载布局都是用mainLayout属性属性进行加载的(当时都没有绑定),之后一个绑定在mainLayout,一个绑定在lyo_content上,造成了上面截图的结果
View buttonLayout2 = layoutInflater.inflate(R.layout.button_layout, mainLayout, false); mainLayout.addView(buttonLayout2); View buttonLayout22 = layoutInflater.inflate(R.layout.button_layout, mainLayout, false); lyo_content.addView(buttonLayout22);
2.为什么activity_main布局的第一层是有效的
因为它预先加载了一个id为content的FrameLayout来装载activity_main这个布局
3.关于B拦截了子视图C的Move事件B本身不消费,是否上交给上司处理呢? - CSDN博客
4.Android关于触摸事件跟点击事件两个方法的关系 - CSDN博客
5.Android中事件分发机制 - qq97206858的博客 - CSDN博客
打包
- Android Studio 默认keystore 以及自定义keystore - CSDN博客
- Android之Keystore文件签名 | Doublemine
Android面经
- Android开发细节–查漏补缺(二):易忘难懂 - 简书
- Java面试相关(一)– Java类加载全过程 - 简书
- 真正的深入浅出“设计模式” - 最易懂的设计模式解析 - 简书
- Android 面试 | 全站式导航 - Android - 掘金
- hadyang/interview: Java / Android 笔试、面试 知识整理
- [干货]2017已来,最全面试总结——这些Android面试题你一定需要 - 简书
- Android工程师之Android面试大纲
如果对你有帮助,可以点击“推荐”哦`(*∩_∩*)′
本文链接: Android面经-提升篇(持续更新…) - CSDN博客 ,在此说明本人可能用到很多博客的链接以及话语引用没有说明,请相关的博主莫怪,本人也没有想过靠这些来进行吸引来达到盈利的目的,纯碎是为了保存好这些自己觉得写得很好的博文
- Android面经-基础篇(持续更新...)
- Android面经-提升篇(持续更新...)
- Android系统基础面试笔试题积累,持续更新。。。。
- Android 面试题,持续更新!
- ...基础篇(持续更新)
- 最全Android面试题大集合(Android、Java、计算机基础、设计模式)持续更新
- Android面试题总结 (持续更新)
- Tripadvisor 面经解答 -持续更新ing
- iOS 面试题归纳整理—基础篇(持续更新中)
- Java面试题和基础总结(持续更新中…
- Android 一天一个面试题(持续更新)
- Android 面试题总结(持续更新中)
- 背包专辑-基础篇(持续更新中)
- 基础概念扫盲篇【记录】(持续更新)
- vue.js基础篇(持续更新)
- 基础概念扫盲篇【记录】(持续更新)
- 网络基础,持续更新
- Lua基础[持续更新]
- 给 Android 开发者的 RxJava 详解
- VS2008--VS2013 各种版本官方下载地址
- 曲周!曲周!!!
- Android软键盘弹出时把布局顶上去的解决方法
- 基于jQuery的移动轮播图(支持手机触屏)
- Android面经-基础篇(持续更新...)
- 不要过度依赖JQuery(三)
- nginx——反向代理
- 5种服务器网络编程模型讲解
- 谈谈你对MVC的理解
- solr安装和部署
- 虚拟机上面的LINUX 无法和宿主WIN上面的时间同步问题
- 利用 FFmpeg 在 Android 上做视频编辑
- BZOJ1232 安慰奶牛cheer (洛谷2916)