• android kotlin学习


    android 四大组件
    参考教程

    Activity: 负责用户界面展示和交互,学习Activity就要学习Fragment,且必须要和Activity一起使用,常用于模块开发, 一个APP有多个Activity

    Service服务: 不需要交互,负责后台任务,如播放音乐,socket长连接

    BroadcastReceiver广播接收者: 负责页面间通信,系统和APP通信,APP间通信,如网络变化监听

    ContentProvier 内容提供者: 负责数据存取,常用于APP进程数据共享, 跨进程数据存取,如读取相册联系人

    1.1 Activity生命周期

    7个方法:
    onCreate() 第一次创建时调用, 用于初始化操作
    OnStart() 不可见变可见时调用,还不可以交互
    onResume() 已经启动完成,可以交互
    onPause() 系统准备去启动另一个Activity时调用, 可以释放系统资源,停止动画,不宜做耗时操作
    onStop() Activity不可见时回调,可以释放用户用不到的资源
    onDestroy() Activity即将被销毁,需要主动释放所有资源
    onRestart() Activity由停止变为运行状态前调用[先onStop,再onRestart]

    1.2 组件注册
    四大组件需要在AndroidManifest注册才能使用

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        intent-filter>
    activity>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    android:name是对应Activity的类名称
    android:label是Activity标题栏显示的内容. 现已不推荐使用
    intent-filter 是意图过滤器. 常用语隐式跳转
    action 是动作名称,是指intent要执行的动作
    category 是过滤器的类别 一般情况下,每个 中都要显示指定一个默认的类别名称,即

    1.3 Activity启动与参数传递
    1 显示启动, 通过包名启动
    携带参数启动新Activity

    val intent = Intent(MainActivity.this,SecondActivity.class)
    intent.putExtra("extra_data", "extra_data")
    intent.putExtra("extra_int_data", 100)
    startActivity(intent);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2 隐式启动
    通过指定 action 和 category 的信息,让系统去分析这个 Intent,并找出合适的 Activity 去启动。

    1.4 系统给我们提供的一些常见的Activtiy
    如拨打电话,发送短信,打开浏览器, 多媒体播放,拍照, 选图剪切,进入无线设置

    1.5 Activity四种启动模式
    standard 默认值, 多实例模式, 每启动一次, 会创建一个Activity实例
    启动周期:
    onCreate() - onStart() - onResume()

    singleTop 栈顶复用模式
    栈顶有需要启动的目标Activity ?
    直接启动【onPause() ->onNewIntent()->onResume()】 :
    创建新实例 【onCreate()->onStart()->onResume()】

    singleTask 栈内复用模式: 一个任务栈只能有一个实例
    启动的Activity目标任务栈存在 ?
    切换到Activity所在的任务栈:
    启动Activity为根Activity创建目标任务栈,并切换到前面

    singleInstance 单例模式
    单例模式的“保护措施”是将其单独放到一个任务栈中

    1.6 Intent FLag设定启动模式
    可以在manifest中设置Activity的启动模式,也可以通过设置Intent的flag标识来设定Activity的启动模式。
    Intent的flag标识 如:
    FLAG_ACTIVITY_NEW_TASK: 启动Activity时,如果不存在Activity的实例,则会以此Activity为根Activity创建新的任务栈,如果存在的话则直接切换到对应的Activity实例,并回调onNewIntent()方法。相当于“singleTask”启动模式。

    FLAG_ACTIVITY_SINGLE_TOP:相当于“singleTop”模式
    FLAG_ACTIVITY_CLEAR_TOP:设置此标识的Activity在启动时,如果当前的任务栈内存在此Activity实例,则跳转到此实例,并清除掉在此实例上面的所有Activity实例,此时此Activity实例位于任务栈的栈顶

    2 Fragment必知必会
    2.1 Fragment出现的背景

    初衷: Fragment是Android3.0后引入的一个新的API,他出现的初衷是为了适应大屏幕的平板电脑, 当然现在他仍然是平板APP UI设计的宠儿。

    现状:现在我们普通APP开发也经常会用到Fragment,如果一个界面很复杂,我们把所有代码都写在一个Activity里面,页面布局都写在同一个xml文件中。过不了多久我们就会发现写不动了,一个Activity上万行代码,非常难以维护,后续如果有变动,更是无从下手。而使用Fragment 我们可以把页面结构划分成几块,每块使用一个Fragment来管理。这样我们可以更加方便的在运行过程中动态地更新Activity中的用户界面,日后迭代更新、维护也是更加方便。

    注意: Fragment并不能单独使用,他需要嵌套在Activity 中使用

    2.2 生命周期
    ①Activity加载Fragment的时候,依次调用下面的方法: onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart ->onResume

    ②当我们启动一个新的页面, 此时Fragment所在的Activity不可见,会执行 onPause

    ③当新页面返回后,当前Activity和Fragment又可见了,会再次执行onStart和 onResume

    ⑥退出了Activity的话,那么Fragment将会被完全结束, Fragment会进入销毁状态 onPause -> onStop -> onDestoryView -> onDestory -> onDetach

    2.3 Fragment的动态添加与数据传递
    2.3.1 动态添加Fragment

    // 定义StudyFragment需要继承自Fragment,并且绑定布局文件
    class StudyFragment : Fragment(R.layout.fragment_study,container) {
    
    }// 在Activity中使用supportFragmentManager管理Fragment,添加到界面上
    class MainActivity:AppCompactActivity{
       override fun onCreate(savedInstanceState: Bundle?) {
            val studyFragment =  StudyFragment();
            val bundle = Bundle()
            bundle.putInt()
            studyFragment.argments= Bundle
            supportFragmentManager.beginTransaction()
               .add(R.id.container, studyFragment).commitAllowingStateLoss()
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.3.2 Fragment常见的操作

    val fragment = StudyFragment()
    val ft = supportFragmentManager.beginTransaction()
    
    if(!fragment.isAdded()){
      ft.add(R.id.container,fragment) //把fragment添加到事务中,当且仅当该fragment未被添加过
    }
    ft.show(fragment) //显示出fragment的视图
    ft.hide(fragment) //隐藏fragment,使得它的视图不可见
    ft.remove(fragment)//移除fragment
    ft.replace(R.id.container,fragment)//替换fragment,之前添加过的fragment都会被暂时移除,把当前这个fragment添加到事务中
    
    ft.commitAllowingStateLoss()提交事务,执行对fragment的add、replace、show、hide操作
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.3.3给Fragment传递数据

    class MainActivity:AppcompactActivity{
    
         override fun onCreate(savedInstanceState: Bundle?){
    
           val studyFragment =  StudyFragment();
    
           // 创建bundle对象、并填充数据赋值给fragment的argments字段
           val bundle = Bundle()
           bundle.putInt("key_int",100)
           bundle.putString("key_string","key_string_value")
           studyFragment.argments= Bundle
    
           supportFragmentManager.beginTransaction().add(R.id.container,    studyFragment).commitAllowingStateLoss()
    
         }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    class StudyFragment : Fragment(R.layout.fragment_study) {
         override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
              // 取出参数
              val intArgument = argments?.getInt("key_int")
              val stringArgument = argments?.getInt("key_string") 
         }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.4 实践:设计并实现底部导航栏页面结构

    2.4.1 Activity 布局
    2.4.2 监听选中事件
    2.4.3 导航栏切换动态切换显示的fragment

    3 Service 必会必知

    Service服务是Android四大组件之一,是Android提供的一种的 不需要和用户交互,且需要长期运行任务的解决方案。

    Service启动后默认是运行在主线程中,在执行具体耗时任务过程中要手动开启子线程,应用程序进程被杀死,所有依赖该进程的Service服务也会停止运行。

    3.1启动方式与生命周期:

    android 四大组件
    参考教程

    Activity: 负责用户界面展示和交互,学习Activity就要学习Fragment,且必须要和Activity一起使用,常用于模块开发, 一个APP有多个Activity

    Service服务: 不需要交互,负责后台任务,如播放音乐,socket长连接

    BroadcastReceiver广播接收者: 负责页面间通信,系统和APP通信,APP间通信,如网络变化监听

    ContentProvier 内容提供者: 负责数据存取,常用于APP进程数据共享, 跨进程数据存取,如读取相册联系人

    1.1 Activity生命周期

    7个方法:
    onCreate() 第一次创建时调用, 用于初始化操作
    OnStart() 不可见变可见时调用,还不可以交互
    onResume() 已经启动完成,可以交互
    onPause() 系统准备去启动另一个Activity时调用, 可以释放系统资源,停止动画,不宜做耗时操作
    onStop() Activity不可见时回调,可以释放用户用不到的资源
    onDestroy() Activity即将被销毁,需要主动释放所有资源
    onRestart() Activity由停止变为运行状态前调用[先onStop,再onRestart]

    1.2 组件注册
    四大组件需要在AndroidManifest注册才能使用

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        intent-filter>
    activity>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    android:name是对应Activity的类名称
    android:label是Activity标题栏显示的内容. 现已不推荐使用
    是意图过滤器. 常用语隐式跳转
    是动作名称,是指intent要执行的动作
    是过滤器的类别 一般情况下,每个 中都要显示指定一个默认的类别名称,即

    1.3 Activity启动与参数传递
    1 显示启动, 通过包名启动
    携带参数启动新Activity

    val intent = Intent(MainActivity.this,SecondActivity.class)
    intent.putExtra("extra_data", "extra_data")
    intent.putExtra("extra_int_data", 100)
    startActivity(intent);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2 隐式启动
    通过指定 action 和 category 的信息,让系统去分析这个 Intent,并找出合适的 Activity 去启动。

    1.4 系统给我们提供的一些常见的Activtiy
    如拨打电话,发送短信,打开浏览器, 多媒体播放,拍照, 选图剪切,进入无线设置

    1.5 Activity四种启动模式
    standard 默认值, 多实例模式, 每启动一次, 会创建一个Activity实例
    启动周期:
    onCreate() - onStart() - onResume()

    singleTop 栈顶复用模式
    栈顶有需要启动的目标Activity ?
    直接启动【onPause() ->onNewIntent()->onResume()】 :
    创建新实例 【onCreate()->onStart()->onResume()】

    singleTask 栈内复用模式: 一个任务栈只能有一个实例
    启动的Activity目标任务栈存在 ?
    切换到Activity所在的任务栈:
    启动Activity为根Activity创建目标任务栈,并切换到前面

    singleInstance 单例模式
    单例模式的“保护措施”是将其单独放到一个任务栈中

    1.6 Intent FLag设定启动模式
    可以在manifest中设置Activity的启动模式,也可以通过设置Intent的flag标识来设定Activity的启动模式。
    Intent的flag标识 如:
    FLAG_ACTIVITY_NEW_TASK: 启动Activity时,如果不存在Activity的实例,则会以此Activity为根Activity创建新的任务栈,如果存在的话则直接切换到对应的Activity实例,并回调onNewIntent()方法。相当于“singleTask”启动模式。

    FLAG_ACTIVITY_SINGLE_TOP:相当于“singleTop”模式
    FLAG_ACTIVITY_CLEAR_TOP:设置此标识的Activity在启动时,如果当前的任务栈内存在此Activity实例,则跳转到此实例,并清除掉在此实例上面的所有Activity实例,此时此Activity实例位于任务栈的栈顶

    2 Fragment必知必会
    2.1 Fragment出现的背景

    初衷: Fragment是Android3.0后引入的一个新的API,他出现的初衷是为了适应大屏幕的平板电脑, 当然现在他仍然是平板APP UI设计的宠儿。

    现状:现在我们普通APP开发也经常会用到Fragment,如果一个界面很复杂,我们把所有代码都写在一个Activity里面,页面布局都写在同一个xml文件中。过不了多久我们就会发现写不动了,一个Activity上万行代码,非常难以维护,后续如果有变动,更是无从下手。而使用Fragment 我们可以把页面结构划分成几块,每块使用一个Fragment来管理。这样我们可以更加方便的在运行过程中动态地更新Activity中的用户界面,日后迭代更新、维护也是更加方便。

    注意: Fragment并不能单独使用,他需要嵌套在Activity 中使用

    2.2 生命周期
    ①Activity加载Fragment的时候,依次调用下面的方法: onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart ->onResume

    ②当我们启动一个新的页面, 此时Fragment所在的Activity不可见,会执行 onPause

    ③当新页面返回后,当前Activity和Fragment又可见了,会再次执行onStart和 onResume

    ⑥退出了Activity的话,那么Fragment将会被完全结束, Fragment会进入销毁状态 onPause -> onStop -> onDestoryView -> onDestory -> onDetach

    2.3 Fragment的动态添加与数据传递
    2.3.1 动态添加Fragment

    // 定义StudyFragment需要继承自Fragment,并且绑定布局文件
    class StudyFragment : Fragment(R.layout.fragment_study,container) {
    
    }// 在Activity中使用supportFragmentManager管理Fragment,添加到界面上
    class MainActivity:AppCompactActivity{
       override fun onCreate(savedInstanceState: Bundle?) {
            val studyFragment =  StudyFragment();
            val bundle = Bundle()
            bundle.putInt()
            studyFragment.argments= Bundle
            supportFragmentManager.beginTransaction()
               .add(R.id.container, studyFragment).commitAllowingStateLoss()
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.3.2 Fragment常见的操作

    val fragment = StudyFragment()
    val ft = supportFragmentManager.beginTransaction()
    
    if(!fragment.isAdded()){
      ft.add(R.id.container,fragment) //把fragment添加到事务中,当且仅当该fragment未被添加过
    }
    ft.show(fragment) //显示出fragment的视图
    ft.hide(fragment) //隐藏fragment,使得它的视图不可见
    ft.remove(fragment)//移除fragment
    ft.replace(R.id.container,fragment)//替换fragment,之前添加过的fragment都会被暂时移除,把当前这个fragment添加到事务中
    
    ft.commitAllowingStateLoss()提交事务,执行对fragment的add、replace、show、hide操作
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.3.3给Fragment传递数据

    class MainActivity:AppcompactActivity{
    
         override fun onCreate(savedInstanceState: Bundle?){
    
           val studyFragment =  StudyFragment();
    
           // 创建bundle对象、并填充数据赋值给fragment的argments字段
           val bundle = Bundle()
           bundle.putInt("key_int",100)
           bundle.putString("key_string","key_string_value")
           studyFragment.argments= Bundle
    
           supportFragmentManager.beginTransaction().add(R.id.container,    studyFragment).commitAllowingStateLoss()
    
         }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    class StudyFragment : Fragment(R.layout.fragment_study) {
         override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
              // 取出参数
              val intArgument = argments?.getInt("key_int")
              val stringArgument = argments?.getInt("key_string") 
         }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.4 实践:设计并实现底部导航栏页面结构

    2.4.1 Activity 布局
    2.4.2 监听选中事件
    2.4.3 导航栏切换动态切换显示的fragment

    3 Service 必会必知

    Service服务是Android四大组件之一,是Android提供的一种的 不需要和用户交互,且需要长期运行任务的解决方案。

    Service启动后默认是运行在主线程中,在执行具体耗时任务过程中要手动开启子线程,应用程序进程被杀死,所有依赖该进程的Service服务也会停止运行。

    3.1启动方式与生命周期:

    [外链图片转存中…(img-laW4nE7d-166781128261.272)]
    android 四大组件
    参考教程

    Activity: 负责用户界面展示和交互,学习Activity就要学习Fragment,且必须要和Activity一起使用,常用于模块开发, 一个APP有多个Activity

    Service服务: 不需要交互,负责后台任务,如播放音乐,socket长连接

    BroadcastReceiver广播接收者: 负责页面间通信,系统和APP通信,APP间通信,如网络变化监听

    ContentProvier 内容提供者: 负责数据存取,常用于APP进程数据共享, 跨进程数据存取,如读取相册联系人

    1.1 Activity生命周期

    7个方法:
    onCreate() 第一次创建时调用, 用于初始化操作
    OnStart() 不可见变可见时调用,还不可以交互
    onResume() 已经启动完成,可以交互
    onPause() 系统准备去启动另一个Activity时调用, 可以释放系统资源,停止动画,不宜做耗时操作
    onStop() Activity不可见时回调,可以释放用户用不到的资源
    onDestroy() Activity即将被销毁,需要主动释放所有资源
    onRestart() Activity由停止变为运行状态前调用[先onStop,再onRestart]

    1.2 组件注册
    四大组件需要在AndroidManifest注册才能使用

    <activity
        android:name=".MainActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        intent-filter>
    activity>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    android:name是对应Activity的类名称
    android:label是Activity标题栏显示的内容. 现已不推荐使用
    是意图过滤器. 常用语隐式跳转
    是动作名称,是指intent要执行的动作
    是过滤器的类别 一般情况下,每个 中都要显示指定一个默认的类别名称,即

    1.3 Activity启动与参数传递
    1 显示启动, 通过包名启动
    携带参数启动新Activity

    val intent = Intent(MainActivity.this,SecondActivity.class)
    intent.putExtra("extra_data", "extra_data")
    intent.putExtra("extra_int_data", 100)
    startActivity(intent);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2 隐式启动
    通过指定 action 和 category 的信息,让系统去分析这个 Intent,并找出合适的 Activity 去启动。

    1.4 系统给我们提供的一些常见的Activtiy
    如拨打电话,发送短信,打开浏览器, 多媒体播放,拍照, 选图剪切,进入无线设置

    1.5 Activity四种启动模式
    standard 默认值, 多实例模式, 每启动一次, 会创建一个Activity实例
    启动周期:
    onCreate() - onStart() - onResume()

    singleTop 栈顶复用模式
    栈顶有需要启动的目标Activity ?
    直接启动【onPause() ->onNewIntent()->onResume()】 :
    创建新实例 【onCreate()->onStart()->onResume()】

    singleTask 栈内复用模式: 一个任务栈只能有一个实例
    启动的Activity目标任务栈存在 ?
    切换到Activity所在的任务栈:
    启动Activity为根Activity创建目标任务栈,并切换到前面

    singleInstance 单例模式
    单例模式的“保护措施”是将其单独放到一个任务栈中

    1.6 Intent FLag设定启动模式
    可以在manifest中设置Activity的启动模式,也可以通过设置Intent的flag标识来设定Activity的启动模式。
    Intent的flag标识 如:
    FLAG_ACTIVITY_NEW_TASK: 启动Activity时,如果不存在Activity的实例,则会以此Activity为根Activity创建新的任务栈,如果存在的话则直接切换到对应的Activity实例,并回调onNewIntent()方法。相当于“singleTask”启动模式。

    FLAG_ACTIVITY_SINGLE_TOP:相当于“singleTop”模式
    FLAG_ACTIVITY_CLEAR_TOP:设置此标识的Activity在启动时,如果当前的任务栈内存在此Activity实例,则跳转到此实例,并清除掉在此实例上面的所有Activity实例,此时此Activity实例位于任务栈的栈顶

    2 Fragment必知必会
    2.1 Fragment出现的背景

    初衷: Fragment是Android3.0后引入的一个新的API,他出现的初衷是为了适应大屏幕的平板电脑, 当然现在他仍然是平板APP UI设计的宠儿。

    现状:现在我们普通APP开发也经常会用到Fragment,如果一个界面很复杂,我们把所有代码都写在一个Activity里面,页面布局都写在同一个xml文件中。过不了多久我们就会发现写不动了,一个Activity上万行代码,非常难以维护,后续如果有变动,更是无从下手。而使用Fragment 我们可以把页面结构划分成几块,每块使用一个Fragment来管理。这样我们可以更加方便的在运行过程中动态地更新Activity中的用户界面,日后迭代更新、维护也是更加方便。

    注意: Fragment并不能单独使用,他需要嵌套在Activity 中使用

    2.2 生命周期
    ①Activity加载Fragment的时候,依次调用下面的方法: onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart ->onResume

    ②当我们启动一个新的页面, 此时Fragment所在的Activity不可见,会执行 onPause

    ③当新页面返回后,当前Activity和Fragment又可见了,会再次执行onStart和 onResume

    ⑥退出了Activity的话,那么Fragment将会被完全结束, Fragment会进入销毁状态 onPause -> onStop -> onDestoryView -> onDestory -> onDetach

    2.3 Fragment的动态添加与数据传递
    2.3.1 动态添加Fragment

    // 定义StudyFragment需要继承自Fragment,并且绑定布局文件
    class StudyFragment : Fragment(R.layout.fragment_study,container) {
    
    }// 在Activity中使用supportFragmentManager管理Fragment,添加到界面上
    class MainActivity:AppCompactActivity{
       override fun onCreate(savedInstanceState: Bundle?) {
            val studyFragment =  StudyFragment();
            val bundle = Bundle()
            bundle.putInt()
            studyFragment.argments= Bundle
            supportFragmentManager.beginTransaction()
               .add(R.id.container, studyFragment).commitAllowingStateLoss()
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.3.2 Fragment常见的操作

    val fragment = StudyFragment()
    val ft = supportFragmentManager.beginTransaction()
    
    if(!fragment.isAdded()){
      ft.add(R.id.container,fragment) //把fragment添加到事务中,当且仅当该fragment未被添加过
    }
    ft.show(fragment) //显示出fragment的视图
    ft.hide(fragment) //隐藏fragment,使得它的视图不可见
    ft.remove(fragment)//移除fragment
    ft.replace(R.id.container,fragment)//替换fragment,之前添加过的fragment都会被暂时移除,把当前这个fragment添加到事务中
    
    ft.commitAllowingStateLoss()提交事务,执行对fragment的add、replace、show、hide操作
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.3.3给Fragment传递数据

    class MainActivity:AppcompactActivity{
    
         override fun onCreate(savedInstanceState: Bundle?){
    
           val studyFragment =  StudyFragment();
    
           // 创建bundle对象、并填充数据赋值给fragment的argments字段
           val bundle = Bundle()
           bundle.putInt("key_int",100)
           bundle.putString("key_string","key_string_value")
           studyFragment.argments= Bundle
    
           supportFragmentManager.beginTransaction().add(R.id.container,    studyFragment).commitAllowingStateLoss()
    
         }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    class StudyFragment : Fragment(R.layout.fragment_study) {
         override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
              // 取出参数
              val intArgument = argments?.getInt("key_int")
              val stringArgument = argments?.getInt("key_string") 
         }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.4 实践:设计并实现底部导航栏页面结构

    2.4.1 Activity 布局
    2.4.2 监听选中事件
    2.4.3 导航栏切换动态切换显示的fragment

    3 Service 必会必知

    Service服务是Android四大组件之一,是Android提供的一种的 不需要和用户交互,且需要长期运行任务的解决方案。

    Service启动后默认是运行在主线程中,在执行具体耗时任务过程中要手动开启子线程,应用程序进程被杀死,所有依赖该进程的Service服务也会停止运行。

    3.1启动方式与生命周期:

    在这里插入图片描述

    3.1.1 普通启动 startService

    1 Service实例,依次调用onCreate()和onStartCommand()方法,此时Service 进入运行状态

    2 再次调用StartService启动Service,将不会再创建新的Service对象, 系统会直接复用前面创建的Service对象,调用它的onStartCommand()方法!

    3 这样的Service与它的调用者无必然的联系,就是说当调用者结束了自己的生命周期, 但是只要不调用stopService,那么Service还是会继续运行的!

    4 无论启动了多少次Service,只需调用一次StopService即可停掉Service

    3.1.2 定义Service服务

    class TestService : Service() {
      private val TAG = "TestService1 "
      // 必须实现的方法
      override fun onBind(intent: Intent?): IBinder? {
        Log.e(TAG, "onBind方法被调用")
        return null
      }
    
      //Service被创建时调用  
      override fun onCreate() {
          Log.e(TAG, "onCreate方法被调用!")
          super.onCreate()
      }
    
      //Service被启动时调用  
      override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
          Log.e(TAG, "onStartCommand方法被调用!")
          return super.onStartCommand(intent, flags, startId)
      }
    
      //Service被关闭之前回调  
      override fun onDestroy() {
          Log.e(TAG, "onDestory方法被调用!")
          super.onDestroy()
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • AndroidManifest.xml完成Service注册
    <application>
         <service android:name=".components.TestService1">        
         service>
    application>
    
    • 1
    • 2
    • 3
    • 4
    • 在Avtivity中StartService启动服务
    val intent = Intent(this.TestService::class.java);
    startService(intent)
    
    • 1
    • 2

    onBind()方法并没有被调用,另外多次点击启动Service,只会重复地调用onStartCommand 方法!无论我们启动多少次Service,一个stopService就会停止Service!

    3.1.2 绑定启动 bindService

    ①当首次使用bindService()启动一个Service时,系统会实例化一个Service实例,并调用其onCreate()和onBind()方法,然后调用者就可以通过返回的IBinder对象和Service进行交互了,此后如果我们再次使用bindService绑定Service,系统不会创建新的Sevice实例,也不会再调用onBind()方法,只会直接把IBinder对象返回给调用方

    ②如果我们解除与服务的绑定,只需调用unbindService(),此时onUnbind和onDestory方法将会被调用

    ③bindService启动的Service服务是与调用者(Activity)相互关联的,可以理解为 “一条绳子上的蚂蚱”,要死一起死,在bindService后,一旦调用者(Activity)销毁,那么Service也立即终止

    • 定义Service服务
    • AndroidManifest.xml中注册服务
    • 在Activity中bindService启动服务
    • 日志输出与结果分析

    使用BindService绑定Service,依次调用onCreate(),onBind()方法, 我们可以在onBind()方法中返回自定义的IBinder对象;再接着调用的是 ServiceConnection的onServiceConnected()方法该方法中可以获得 IBinder对象,从而进行相关操作;当Service解除绑定后会自动调用 onUnbind和onDestroyed方法,当然绑定多客户端情况需要解除所有 的绑定才会调用onDestoryed方法进行销毁哦

    3.2 Android 8.0及以上不允许后台启动Service服务

    8.0系统杀服务杀的很频繁
    为了保活,我们使用了俩Service互保的方式

    AndroidManifest.xml声明权限

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    
    • 1

    服务兼容写法

    if (Build.VERSION.SDK_INT >= 26) {
        context.startForegroundService(intent);
    } else {
        // Pre-O behavior.
        context.startService(intent);
    }
    
    
    class TestService:Service(){
      // 发送一个前台通知
      override fun onCreate(){
           val notification: Notification =Notification.Builder(applicationContext, "channel_id").build()
           startForeground( 1, notification)
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4 BroadcastReceiver广播接收者

    BroadcastReceiver广播接收者Android四大组件之一,是Android系统提供的一种通讯方式。
    类似于村口大喇叭
    涉及到两个角色,一个是广播发送者,一个是广播接收者。

    应用场景:
    Android不同组件间的通信(含 :应用内 / 不同应用之间)
    多线程通信
    与 Android 系统在特定情况下的通信

    4.1 两种广播类型

    标准广播:发出广播后,该广播事件的接收者,几乎会在同一时刻收到通知,都可以响应或不响应该事件

    有序广播:发出广播后,同一时刻,只有一个广播接收者能收到、一个接收者处理完后之后,可以选择继续向下传递给其它接收者,也可以拦截掉广播。[不常用、不推荐使用了]

    4.2 监听系统网络连接变化

    4.2.1 定义一个接受者:

    class TestBroadcastReceiver : BroadcastReceiver() {
      override fun onReceive(context: Conext>, intent: Intent?) {
        if (intent?.action?.equals(ConnectivityManager.CONNECTIVITY_ACTION) == true) {
          val connectivityManager: ConnectivityManager = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    
          val info = connectivityManager.activeNetworkInfo
          if (info != null && info.isAvailable) {
            val typeName = info.typeName
            Toast.makeText(context, "当前网络名称:${typeName}", Toast.LENGTH_LONG).show()
          } else {
            Toast.makeText(context, "当前无网络连接", Toast.LENGTH_LONG).show()
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.2.2 运行时动态注册广播接收事件

    class TestBroadcastRecevierActivity :AppCompatActivity(){
        private lateinit var myReceiver: TestBroadcastReceiver
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            myReceiver = TestBroadcastReceiver()
            // 创建广播过滤器,指定只接收android.net.conn.CONNECTIVITY_CHANGE的广播事件
            val intentFilter = IntentFilter() 
            intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED)
            registerReceiver(myReceiver, intentFilter)
        }
    
        override fun onDestroy() {
            super.onDestroy()
            unregisterReceiver(myReceiver)   // 必须要在onDestroy时反注册,否则会内存泄漏
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    不要在广播后进行耗时操作,因为广播不允许开辟线程

    onReceiver 运行超过10秒会报错(ANR)

    4.2.3 静态注册广播

    从android 8.0(API26)开始,对清单文件中静态注册广播接收者增加了限制,建议大家不要在清单文件中静态注册广播接收者。

    AndroidManifest.xml 注册广播

    <receiver android:name=".components.TestBroadcastReceiver">
         <intent-filter >
              <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
         intent-filter>
    receiver>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.2.4 解决静态注册广播接收者收不到事件的问题

    4.3 发送自定义事件广播

    4.3.1 全局发送广播

    全局发送广播,如果别人家App也注册了该事件监听,也能收到,比较不合理。

    sendBroadcast(new Intent(“com.example.firstapp.component.TEST_BROADCAST_RECEVIER”));

    4.3.2 应用内发送广播

    1 局部广播,发送和接受同属于一个APP
    2 优势: 安全, 高效

    使用LocalBroadcastManager 注册应用内广播

    LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, itFilter)
    
    
    • 1
    • 2

    使用LocalBoardcastManager 来发送应用内广播

    LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
    
    • 1

    4.3.2 系统广播(system boardcast)

    只要涉及到手机基本操作: (网络变化, 拍照,开机等), 会发出相应广播

    每个广播有特定的intent-filter


    系统操作action
    监听网络变化android.net.conn.CONNECTIVITY_CHANGE
    关闭或打开飞行模式Intent.ACTION_AIRPLANE_MODE_CHANGED
    充电时或电量发生变化Intent.ACTION_BATTERY_CHANGED
    电池电量低Intent.ACTION_BATTERY_LOW
    电池电量充足(即从电量低变化到饱满时会发出广播Intent.ACTION_BATTERY_OKAY
    系统启动完成后(仅广播一次)Intent.ACTION_BOOT_COMPLETED
    按下照相时的拍照按键(硬件按键)时Intent.ACTION_CAMERA_BUTTON
    屏幕锁屏Intent.ACTION_CLOSE_SYSTEM_DIALOGS
    设备当前设置被改变时(界面语言、设备方向等)Intent.ACTION_CONFIGURATION_CHANGED
    插入耳机时Intent.ACTION_HEADSET_PLUG
    未正确移除SD卡但已取出来时(正确移除方法:设置–SD卡和设备内存–卸载SD卡)Intent.ACTION_MEDIA_BAD_REMOVAL
    插入外部储存装置(如SD卡)Intent.ACTION_MEDIA_CHECKING
    成功安装APKIntent.ACTION_PACKAGE_ADDED
    成功删除APKIntent.ACTION_PACKAGE_REMOVED
    重启设备Intent.ACTION_REBOOT
    屏幕被关闭Intent.ACTION_SCREEN_OFF
    屏幕被打开Intent.ACTION_SCREEN_ON
    关闭系统时Intent.ACTION_SHUTDOWN
    重启设备Intent.ACTION_REBOOT

    5.ContentProvider(内容提供者)

    应用:

    1. 我们想在自己的应用中访问别的程序, 或者说一些ContentProvider暴露给我们一些数据,如手机联系人,短信,相册,对数据读写
    2. 我们自己的应用, 想暴露出去,避免私有数据泄露

    5.1 权限申请

    6.0开始,凡是涉及隐私的权限(短信, 联系人,相片,录音等)运行时申请,不授权无法工作

    5.1.1 在Androidmanifest.xml 声明读取短信权限

    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    
    • 1

    运行时动态申请权限,请求用户授权

    • ActivityCompat.checkSelfPremission(): 检查权限是否已授权,如果没有则需要向用户申请
    • ActivityCompat.requestPremissions(): 发起权限申请,弹出对话框
    • ActivityCompat.shouldShowRequsetPremissionRationale(): 检查用户是否永久拒绝,如果是,需要自己弹窗引导用户开启
    • onRequestPermissionRequset: 处理授权结果

    example:

    class PermissionActivity:AppCompatActivity() {
    
    }
    
    • 1
    • 2
    • 3

    通信录读取联系人
    content://com.android.contacts/data/phones

    display_name: 用户名
    Data1:手机号

    通信录插入联系人

    • AndroidManifest.xml声明权限
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
    
    • 1

    content://com.android.contacts/data/data 插入联系人的表的名字
    content://com.android.contacts/data/raw_contacts 插入联系人的原始表的名字

    更新联系人信息
    删除联系人

    • 根据姓名删除联系人
    • 根据手机号删除联系人

    读取收件箱所有短信

    字段 说明
    address 发件人地址,即手机号,如+8613811810000
    person 发件人地址,即手机号,如+8613811810000
    date 日期,long型,如1256539465022,可以对日期显示格式进行设置
    protocol 协议0 :SMS_RPOTO短信,1:MMS_PROTO彩信
    read 是否阅读0:未读,1:已读
    type 短信类型1: 接收到的短信,2:发出的短信
    body 短信具体内容

    3.1 普通启动 startService

    1 Service实例,依次调用onCreate()和onStartCommand()方法,此时Service 进入运行状态

    2 再次调用StartService启动Service,将不会再创建新的Service对象, 系统会直接复用前面创建的Service对象,调用它的onStartCommand()方法!

    3 这样的Service与它的调用者无必然的联系,就是说当调用者结束了自己的生命周期, 但是只要不调用stopService,那么Service还是会继续运行的!

    4 无论启动了多少次Service,只需调用一次StopService即可停掉Service

    .1.2 定义Service服务

    class TestService : Service() {
      private val TAG = "TestService1 "
      // 必须实现的方法
      override fun onBind(intent: Intent?): IBinder? {
        Log.e(TAG, "onBind方法被调用")
        return null
      }
    
      //Service被创建时调用  
      override fun onCreate() {
          Log.e(TAG, "onCreate方法被调用!")
          super.onCreate()
      }
    
      //Service被启动时调用  
      override fun onStartCommand(intent: Intent?, flags: Int, startId: Int6: Int {
          Log.e1TAG, "onStartCommand方法被调用!")
          return super8onStartCommand(intent, flags, startId)
      }
    
      ./Service被关闭之前回调  
      override fun onDe0troy() {
          Log.e(TAG, "onDestory方法被调用!")
          super.onDestroy()
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • AndroidManifest.xml完成S6/s8rviceeg)]

    3.1738)(./service注册

    <application>
         <service android:name=".components.TestService1">        
         service>
    application>
    
    • 1
    • 2
    • 3
    • 4
    • 在Avtivity中StartService启动服务
    val intent = Intent(this.TestService::class.java);
    startService(intent)
    
    • 1
    • 2

    onBind()方法并没有被调用,另外多次点击启动Service,只会重复地调用onStartCommand 方法!无论我们启动多少次Service,一个stopService就会停止Service!

    3.1.2 绑定启动 bindService

    ①当首次使用bindService()启动一个Service时,系统会实例化一个Service实例,并调用其onCreate()和onBind()方法,然后调用者就可以通过返回的IBinder对象和Service进行交互了,此后如果我们再次使用bindService绑定Service,系统不会创建新的Sevice实例,也不会再调用onBind()方法,只会直接把IBinder对象返回给调用方

    ②如果我们解除与服务的绑定,只需调用unbindService(),此时onUnbind和onDestory方法将会被调用

    ③bindService启动的Service服务是与调用者(Activity)相互关联的,可以理解为 “一条绳子上的蚂蚱”,要死一起死,在bindService后,一旦调用者(Activity)销毁,那么Service也立即终止

    • 定义Service服务
    • AndroidManifest.xml中注册服务
    • 在Activity中bindService启动服务
    • 日志输出与结果分析

    使用BindService绑定Service,依次调用onCreate(),onBind()方法, 我们可以在onBind()方法中返回自定义的IBinder对象;再接着调用的是 ServiceConnection的onServiceConnected()方法该方法中可以获得 IBinder对象,从而进行相关操作;当Service解除绑定后会自动调用 onUnbind和onDestroyed方法,当然绑定多客户端情况需要解除所有 的绑定才会调用onDestoryed方法进行销毁哦

    3.2 Android 8.0及以上不允许后台启动Service服务

    8.0系统杀服务杀的很频繁
    为了保活,我们使用了俩Service互保的方式

    AndroidManifest.xml声明权限

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    
    • 1

    服务兼容写法

    if (Build.VERSION.SDK_INT >= 26) {
        context.startForegroundService(intent);
    } else {
        // Pre-O behavior.
        context.startService(intent);
    }
    
    
    class TestService:Service(){
      // 发送一个前台通知
      override fun onCreate(){
           val notification: Notification =Notification.Builder(applicationContext, "channel_id").build()
           startForeground( 1, notification)
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4 BroadcastReceiver广播接收者

    BroadcastReceiver广播接收者Android四大组件之一,是Android系统提供的一种通讯方式。
    类似于村口大喇叭
    涉及到两个角色,一个是广播发送者,一个是广播接收者。

    应用场景:
    Android不同组件间的通信(含 :应用内 / 不同应用之间)
    多线程通信
    与 Android 系统在特定情况下的通信

    4.1 两种广播类型

    标准广播:发出广播后,该广播事件的接收者,几乎会在同一时刻收到通知,都可以响应或不响应该事件

    有序广播:发出广播后,同一时刻,只有一个广播接收者能收到、一个接收者处理完后之后,可以选择继续向下传递给其它接收者,也可以拦截掉广播。[不常用、不推荐使用了]

    4.2 监听系统网络连接变化

    4.2.1 定义一个接受者:

    class TestBroadcastReceiver : BroadcastReceiver() {
      override fun onReceive(context: Conext>, intent: Intent?) {
        if (intent?.action?.equals(ConnectivityManager.CONNECTIVITY_ACTION) == true) {
          val connectivityManager: ConnectivityManager = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    
          val info = connectivityManager.activeNetworkInfo
          if (info != null && info.isAvailable) {
            val typeName = info.typeName
            Toast.makeText(context, "当前网络名称:${typeName}", Toast.LENGTH_LONG).show()
          } else {
            Toast.makeText(context, "当前无网络连接", Toast.LENGTH_LONG).show()
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.2.2 运行时动态注册广播接收事件

    class TestBroadcastRecevierActivity :AppCompatActivity(){
        private lateinit var myReceiver: TestBroadcastReceiver
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            myReceiver = TestBroadcastReceiver()
            // 创建广播过滤器,指定只接收android.net.conn.CONNECTIVITY_CHANGE的广播事件
            val intentFilter = IntentFilter() 
            intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED)
            registerReceiver(myReceiver, intentFilter)
        }
    
        override fun onDestroy() {
            super.onDestroy()
            unregisterReceiver(myReceiver)   // 必须要在onDestroy时反注册,否则会内存泄漏
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    不要在广播后进行耗时操作,因为广播不允许开辟线程

    onReceiver 运行超过10秒会报错(ANR)

    4.2.3 静态注册广播

    从android 8.0(API26)开始,对清单文件中静态注册广播接收者增加了限制,建议大家不要在清单文件中静态注册广播接收者。

    AndroidManifest.xml 注册广播

    <receiver android:name=".components.TestBroadcastReceiver">
         <intent-filter >
              <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
         intent-filter>
    receiver>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.2.4 解决静态注册广播接收者收不到事件的问题

    4.3 发送自定义事件广播

    4.3.1 全局发送广播

    全局发送广播,如果别人家App也注册了该事件监听,也能收到,比较不合理。

    sendBroadcast(new Intent(“com.example.firstapp.component.TEST_BROADCAST_RECEVIER”));

    4.3.2 应用内发送广播

    1 局部广播,发送和接受同属于一个APP
    2 优势: 安全, 高效

    使用LocalBroadcastManager 注册应用内广播

    LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, itFilter)
    
    
    • 1
    • 2

    使用LocalBoardcastManager 来发送应用内广播

    LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
    
    • 1

    4.3.2 系统广播(system boardcast)

    只要涉及到手机基本操作: (网络变化, 拍照,开机等), 会发出相应广播

    每个广播有特定的intent-filter


    系统操作action
    监听网络变化android.net.conn.CONNECTIVITY_CHANGE
    关闭或打开飞行模式Intent.ACTION_AIRPLANE_MODE_CHANGED
    充电时或电量发生变化Intent.ACTION_BATTERY_CHANGED
    电池电量低Intent.ACTION_BATTERY_LOW
    电池电量充足(即从电量低变化到饱满时会发出广播Intent.ACTION_BATTERY_OKAY
    系统启动完成后(仅广播一次)Intent.ACTION_BOOT_COMPLETED
    按下照相时的拍照按键(硬件按键)时Intent.ACTION_CAMERA_BUTTON
    屏幕锁屏Intent.ACTION_CLOSE_SYSTEM_DIALOGS
    设备当前设置被改变时(界面语言、设备方向等)Intent.ACTION_CONFIGURATION_CHANGED
    插入耳机时Intent.ACTION_HEADSET_PLUG
    未正确移除SD卡但已取出来时(正确移除方法:设置–SD卡和设备内存–卸载SD卡)Intent.ACTION_MEDIA_BAD_REMOVAL
    插入外部储存装置(如SD卡)Intent.ACTION_MEDIA_CHECKING
    成功安装APKIntent.ACTION_PACKAGE_ADDED
    成功删除APKIntent.ACTION_PACKAGE_REMOVED
    重启设备Intent.ACTION_REBOOT
    屏幕被关闭Intent.ACTION_SCREEN_OFF
    屏幕被打开Intent.ACTION_SCREEN_ON
    关闭系统时Intent.ACTION_SHUTDOWN
    重启设备Intent.ACTION_REBOOT

    5.ContentProvider(内容提供者)

    应用:

    1. 我们想在自己的应用中访问别的程序, 或者说一些ContentProvider暴露给我们一些数据,如手机联系人,短信,相册,对数据读写
    2. 我们自己的应用, 想暴露出去,避免私有数据泄露

    5.1 权限申请

    6.0开始,凡是涉及隐私的权限(短信, 联系人,相片,录音等)运行时申请,不授权无法工作

    5.1.1 在Androidmanifest.xml 声明读取短信权限

    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    
    • 1

    运行时动态申请权限,请求用户授权

    • ActivityCompat.checkSelfPremission(): 检查权限是否已授权,如果没有则需要向用户申请
    • ActivityCompat.requestPremissions(): 发起权限申请,弹出对话框
    • ActivityCompat.shouldShowRequsetPremissionRationale(): 检查用户是否永久拒绝,如果是,需要自己弹窗引导用户开启
    • onRequestPermissionRequset: 处理授权结果

    example:

    class PermissionActivity:AppCompatActivity() {
    
    }
    
    • 1
    • 2
    • 3

    通信录读取联系人
    content://com.android.contacts/data/phones

    display_name: 用户名
    Data1:手机号

    通信录插入联系人

    • AndroidManifest.xml声明权限
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
    
    • 1

    content://com.android.contacts/data/data 插入联系人的表的名字
    content://com.android.contacts/data/raw_contacts 插入联系人的原始表的名字

    更新联系人信息
    删除联系人

    • 根据姓名删除联系人
    • 根据手机号删除联系人

    读取收件箱所有短信

    字段 说明
    address 发件人地址,即手机号,如+8613811810000
    person 发件人地址,即手机号,如+8613811810000
    date 日期,long型,如1256539465022,可以对日期显示格式进行设置
    protocol 协议0 :SMS_RPOTO短信,1:MMS_PROTO彩信
    read 是否阅读0:未读,1:已读
    type 短信类型1: 接收到的短信,2:发出的短信
    body 短信具体内容

    3.1.1 普通启动 startService

    1 Service实例,依次调用onCreate()和onStartCommand()方法,此时Service 进入运行状态

    2 再次调用StartService启动Service,将不会再创建新的Service对象, 系统会直接复用前面创建的Service对象,调用它的onStartCommand()方法!

    3 这样的Service与它的调用者无必然的联系,就是说当调用者结束了自己的生命周期, 但是只要不调用stopService,那么Service还是会继续运行的!

    4 无论启动了多少次Service,只需调用一次StopService即可停掉Service

    3.1.2 定义Service服务

    class TestService : Service() {
      private val TAG = "TestService1 "
      // 必须实现的方法
      override fun onBind(intent: Intent?): IBinder? {
        Log.e(TAG, "onBind方法被调用")
        return null
      }
    
      //Service被创建时调用  
      override fun onCreate() {
          Log.e(TAG, "onCreate方法被调用!")
          super.onCreate()
      }
    
      //Service被启动时调用  
      override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
          Log.e(TAG, "onStartCommand方法被调用!")
          return super.onStartCommand(intent, flags, startId)
      }
    
      //Service被关闭之前回调  
      override fun onDestroy() {
          Log.e(TAG, "onDestory方法被调用!")
          super.onDestroy()
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • AndroidManifest.xml完成Service注册
    <application>
         <service android:name=".components.TestService1">        
         service>
    application>
    
    • 1
    • 2
    • 3
    • 4
    • 在Avtivity中StartService启动服务
    val intent = Intent(this.TestService::class.java);
    startService(intent)
    
    • 1
    • 2

    onBind()方法并没有被调用,另外多次点击启动Service,只会重复地调用onStartCommand 方法!无论我们启动多少次Service,一个stopService就会停止Service!

    3.1.2 绑定启动 bindService

    ①当首次使用bindService()启动一个Service时,系统会实例化一个Service实例,并调用其onCreate()和onBind()方法,然后调用者就可以通过返回的IBinder对象和Service进行交互了,此后如果我们再次使用bindService绑定Service,系统不会创建新的Sevice实例,也不会再调用onBind()方法,只会直接把IBinder对象返回给调用方

    ②如果我们解除与服务的绑定,只需调用unbindService(),此时onUnbind和onDestory方法将会被调用

    ③bindService启动的Service服务是与调用者(Activity)相互关联的,可以理解为 “一条绳子上的蚂蚱”,要死一起死,在bindService后,一旦调用者(Activity)销毁,那么Service也立即终止

    • 定义Service服务
    • AndroidManifest.xml中注册服务
    • 在Activity中bindService启动服务
    • 日志输出与结果分析

    使用BindService绑定Service,依次调用onCreate(),onBind()方法, 我们可以在onBind()方法中返回自定义的IBinder对象;再接着调用的是 ServiceConnection的onServiceConnected()方法该方法中可以获得 IBinder对象,从而进行相关操作;当Service解除绑定后会自动调用 onUnbind和onDestroyed方法,当然绑定多客户端情况需要解除所有 的绑定才会调用onDestoryed方法进行销毁哦

    3.2 Android 8.0及以上不允许后台启动Service服务

    8.0系统杀服务杀的很频繁
    为了保活,我们使用了俩Service互保的方式

    AndroidManifest.xml声明权限

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    
    • 1

    服务兼容写法

    if (Build.VERSION.SDK_INT >= 26) {
        context.startForegroundService(intent);
    } else {
        // Pre-O behavior.
        context.startService(intent);
    }
    
    
    class TestService:Service(){
      // 发送一个前台通知
      override fun onCreate(){
           val notification: Notification =Notification.Builder(applicationContext, "channel_id").build()
           startForeground( 1, notification)
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4 BroadcastReceiver广播接收者

    BroadcastReceiver广播接收者Android四大组件之一,是Android系统提供的一种通讯方式。
    类似于村口大喇叭
    涉及到两个角色,一个是广播发送者,一个是广播接收者。

    应用场景:
    Android不同组件间的通信(含 :应用内 / 不同应用之间)
    多线程通信
    与 Android 系统在特定情况下的通信

    4.1 两种广播类型

    标准广播:发出广播后,该广播事件的接收者,几乎会在同一时刻收到通知,都可以响应或不响应该事件

    有序广播:发出广播后,同一时刻,只有一个广播接收者能收到、一个接收者处理完后之后,可以选择继续向下传递给其它接收者,也可以拦截掉广播。[不常用、不推荐使用了]

    4.2 监听系统网络连接变化

    4.2.1 定义一个接受者:

    class TestBroadcastReceiver : BroadcastReceiver() {
      override fun onReceive(context: Conext>, intent: Intent?) {
        if (intent?.action?.equals(ConnectivityManager.CONNECTIVITY_ACTION) == true) {
          val connectivityManager: ConnectivityManager = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    
          val info = connectivityManager.activeNetworkInfo
          if (info != null && info.isAvailable) {
            val typeName = info.typeName
            Toast.makeText(context, "当前网络名称:${typeName}", Toast.LENGTH_LONG).show()
          } else {
            Toast.makeText(context, "当前无网络连接", Toast.LENGTH_LONG).show()
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.2.2 运行时动态注册广播接收事件

    class TestBroadcastRecevierActivity :AppCompatActivity(){
        private lateinit var myReceiver: TestBroadcastReceiver
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            myReceiver = TestBroadcastReceiver()
            // 创建广播过滤器,指定只接收android.net.conn.CONNECTIVITY_CHANGE的广播事件
            val intentFilter = IntentFilter() 
            intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED)
            registerReceiver(myReceiver, intentFilter)
        }
    
        override fun onDestroy() {
            super.onDestroy()
            unregisterReceiver(myReceiver)   // 必须要在onDestroy时反注册,否则会内存泄漏
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    不要在广播后进行耗时操作,因为广播不允许开辟线程

    onReceiver 运行超过10秒会报错(ANR)

    4.2.3 静态注册广播

    从android 8.0(API26)开始,对清单文件中静态注册广播接收者增加了限制,建议大家不要在清单文件中静态注册广播接收者。

    AndroidManifest.xml 注册广播

    <receiver android:name=".components.TestBroadcastReceiver">
         <intent-filter >
              <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
         intent-filter>
    receiver>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.2.4 解决静态注册广播接收者收不到事件的问题

    4.3 发送自定义事件广播

    4.3.1 全局发送广播

    全局发送广播,如果别人家App也注册了该事件监听,也能收到,比较不合理。

    sendBroadcast(new Intent(“com.example.firstapp.component.TEST_BROADCAST_RECEVIER”));

    4.3.2 应用内发送广播

    1 局部广播,发送和接受同属于一个APP
    2 优势: 安全, 高效

    使用LocalBroadcastManager 注册应用内广播

    LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, itFilter)
    
    
    • 1
    • 2

    使用LocalBoardcastManager 来发送应用内广播

    LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
    
    • 1

    4.3.2 系统广播(system boardcast)

    只要涉及到手机基本操作: (网络变化, 拍照,开机等), 会发出相应广播

    每个广播有特定的intent-filter


    系统操作action
    监听网络变化android.net.conn.CONNECTIVITY_CHANGE
    关闭或打开飞行模式Intent.ACTION_AIRPLANE_MODE_CHANGED
    充电时或电量发生变化Intent.ACTION_BATTERY_CHANGED
    电池电量低Intent.ACTION_BATTERY_LOW
    电池电量充足(即从电量低变化到饱满时会发出广播Intent.ACTION_BATTERY_OKAY
    系统启动完成后(仅广播一次)Intent.ACTION_BOOT_COMPLETED
    按下照相时的拍照按键(硬件按键)时Intent.ACTION_CAMERA_BUTTON
    屏幕锁屏Intent.ACTION_CLOSE_SYSTEM_DIALOGS
    设备当前设置被改变时(界面语言、设备方向等)Intent.ACTION_CONFIGURATION_CHANGED
    插入耳机时Intent.ACTION_HEADSET_PLUG
    未正确移除SD卡但已取出来时(正确移除方法:设置–SD卡和设备内存–卸载SD卡)Intent.ACTION_MEDIA_BAD_REMOVAL
    插入外部储存装置(如SD卡)Intent.ACTION_MEDIA_CHECKING
    成功安装APKIntent.ACTION_PACKAGE_ADDED
    成功删除APKIntent.ACTION_PACKAGE_REMOVED
    重启设备Intent.ACTION_REBOOT
    屏幕被关闭Intent.ACTION_SCREEN_OFF
    屏幕被打开Intent.ACTION_SCREEN_ON
    关闭系统时Intent.ACTION_SHUTDOWN
    重启设备Intent.ACTION_REBOOT

    5.ContentProvider(内容提供者)

    应用:

    1. 我们想在自己的应用中访问别的程序, 或者说一些ContentProvider暴露给我们一些数据,如手机联系人,短信,相册,对数据读写
    2. 我们自己的应用, 想暴露出去,避免私有数据泄露

    5.1 权限申请

    6.0开始,凡是涉及隐私的权限(短信, 联系人,相片,录音等)运行时申请,不授权无法工作

    5.1.1 在Androidmanifest.xml 声明读取短信权限

    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    
    • 1

    运行时动态申请权限,请求用户授权

    • ActivityCompat.checkSelfPremission(): 检查权限是否已授权,如果没有则需要向用户申请
    • ActivityCompat.requestPremissions(): 发起权限申请,弹出对话框
    • ActivityCompat.shouldShowRequsetPremissionRationale(): 检查用户是否永久拒绝,如果是,需要自己弹窗引导用户开启
    • onRequestPermissionRequset: 处理授权结果

    example:

    class PermissionActivity:AppCompatActivity() {
    
    }
    
    • 1
    • 2
    • 3

    通信录读取联系人
    content://com.android.contacts/data/phones

    display_name: 用户名
    Data1:手机号

    通信录插入联系人

    • AndroidManifest.xml声明权限
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
    
    • 1

    content://com.android.contacts/data/data 插入联系人的表的名字
    content://com.android.contacts/data/raw_contacts 插入联系人的原始表的名字

    更新联系人信息
    删除联系人

    • 根据姓名删除联系人
    • 根据手机号删除联系人

    读取收件箱所有短信

    字段 说明
    address 发件人地址,即手机号,如+8613811810000
    person 发件人地址,即手机号,如+8613811810000
    date 日期,long型,如1256539465022,可以对日期显示格式进行设置
    protocol 协议0 :SMS_RPOTO短信,1:MMS_PROTO彩信
    read 是否阅读0:未读,1:已读
    type 短信类型1: 接收到的短信,2:发出的短信
    body 短信具体内容

  • 相关阅读:
    老杨说运维 | 证券行业运维数字化和智能化转型实践探索
    上海计算机学会 2024年4月月赛 丙组T1 最大公约数
    MACOS降级
    端口映射的几种常见应用场景
    蓝桥杯 第 1 场算法双周赛 第三题 分组【算法赛】c++ 贪心+双指针
    [机器学习]-4 Transformer介绍和ChatGPT本质
    LeetCode 面试题 16.06. 最小差
    vscode中编码错误
    智能感测型静电消除器通常具备哪些特点
    上云容灾如何实现碳中和-万博智云受邀参加1024程序员节数据技术论坛并发表演讲
  • 原文地址:https://blog.csdn.net/change_fate/article/details/125276371