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>

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);

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()
   }
}

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操作

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()

     }
}

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") 
     }
}

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>

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);

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()
   }
}

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操作

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()

     }
}

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") 
     }
}

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>

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);

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()
   }
}

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操作

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()

     }
}

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") 
     }
}

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

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

3 Service 必会必知

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

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

3.1启动方式与生命周期:

android kotlin学习_第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()
  }
}
  • AndroidManifest.xml完成Service注册
<application>
     <service android:name=".components.TestService1">        
     service>
application>
  • 在Avtivity中StartService启动服务
val intent = Intent(this.TestService::class.java);
startService(intent)

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" />

服务兼容写法

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)
  }
}

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()
      }
    }
  }
}

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时反注册,否则会内存泄漏
    }
}

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

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>

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)

使用LocalBoardcastManager 来发送应用内广播

LocalBroadcastManager.getInstance(this).sendBroadcast(intent)

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
成功安装APK Intent.ACTION_PACKAGE_ADDED
成功删除APK Intent.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"/>

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

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

example:

class PermissionActivity:AppCompatActivity() {

}

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

display_name: 用户名
Data1:手机号

通信录插入联系人

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

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()
  }
}
  • AndroidManifest.xml完成S6/s8rviceeg)]

3.1738)(./service注册

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

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" />

服务兼容写法

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)
  }
}

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()
      }
    }
  }
}

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时反注册,否则会内存泄漏
    }
}

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

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>

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)

使用LocalBoardcastManager 来发送应用内广播

LocalBroadcastManager.getInstance(this).sendBroadcast(intent)

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
成功安装APK Intent.ACTION_PACKAGE_ADDED
成功删除APK Intent.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"/>

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

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

example:

class PermissionActivity:AppCompatActivity() {

}

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

display_name: 用户名
Data1:手机号

通信录插入联系人

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

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()
  }
}
  • AndroidManifest.xml完成Service注册
<application>
     <service android:name=".components.TestService1">        
     service>
application>
  • 在Avtivity中StartService启动服务
val intent = Intent(this.TestService::class.java);
startService(intent)

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" />

服务兼容写法

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)
  }
}

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()
      }
    }
  }
}

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时反注册,否则会内存泄漏
    }
}

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

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>

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)

使用LocalBoardcastManager 来发送应用内广播

LocalBroadcastManager.getInstance(this).sendBroadcast(intent)

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
成功安装APK Intent.ACTION_PACKAGE_ADDED
成功删除APK Intent.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"/>

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

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

example:

class PermissionActivity:AppCompatActivity() {

}

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

display_name: 用户名
Data1:手机号

通信录插入联系人

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

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 短信具体内容

你可能感兴趣的:(android,android,kotlin,学习)