Android面经-基础篇(持续更新...)

前言:顺序是按照郭霖先生<第二行代码>的书籍目录进行的,可以前往图灵社区购买正版支持,但如果觉得还贵一点,可以百度搜索下载盗版看的(但都希望哥们可以支持正版,毕竟电子版跟纸质版也不贵)

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.Activity的生命周期 - CSDN博客
4.Android中Activity数据的保存和恢复 - 简书
5.Android-Activity所应该了解的大概就这样。(上) - 简书

关于第四篇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中添加如下代码就可以将临时数据进行保存:
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    String tempData = "Something you just typed";
    outState.putString("data_key", tempData);
}

/*数据是已经保存下来了,那么我们应该在哪里进行恢复呢?细心的你
也许早就发现,我们一直使用的onCreate()方法其实也有一个Bundle类型的
参数。这个参数在一般情况下都是null,但是如果在活动被系统回收之前有通
过onSaveInstanceState()方法来保存数据的话,这个参数就会带有之前所
保存的全部数据,我们只需要再通过相应的取值方法将数据取出即可。
修改MainActivity的onCreate()方法,如下所示:*/
@Override
protected 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.对于操作特别频繁的广播事件,比如屏幕的解锁屏,电池电量的变化,必须使用动态注册才得(即不可以在清单文件注册)


数据存储方案


运行时权限(危险权限)

在这里,我建议去Github寻找那些已经封装好的类直接使用即可,毕竟那些代码真的很多,而且很容易忘记


ContentProvider

1.ContentProvider从入门到精通 - 简书
2.Android 进阶11:进程通信之 ContentProvider 内容提供者 - CSDN博客

这里感觉初级复习应该好好回去看通信录以及短信备份更有效,如果是进阶的话,建议从设计模式的角度去看这个组件更好(ContentProvider跟BroadcastReceiver好像都是观察者模式)

丰富你的程序

使用通知

拍照或者从相册选择照片

Android开发之调用摄像头拍照 - 小朵八的博客 - CSDN博客

播放视频或者音频

网络技术

WebView

Android多线程编程


服务

服务的生命周期

这里写图片描述

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没有什么意义。

混合开启服务

一般混合服务的需求都是:既想让服务在后台长期运行又想调用服务里面的办法(即与服务实现交互)
一般顺序:
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)



————-我是低调的分割线————————–

如果对你有帮助,可以点击“推荐”哦`(*∩_∩*)′

本文链接: Android面经-提升篇(持续更新…) - CSDN博客 ,在此说明本人可能用到很多博客的链接以及话语引用没有说明,请相关的博主莫怪,本人也没有想过靠这些来进行吸引来达到盈利的目的,纯碎是为了保存好这些自己觉得写得很好的博文

猜你喜欢

转载自blog.csdn.net/simplebam/article/details/77989675