消息广播

四大组件之一,用于响应来自其它应用程序或者系统的广播消息。这些消息被称为事件或意图。广播可以被一个以上的应用程序接收,也可以不被任何程序接收。

使用场景

  1. 同一app内同一组件内的消息通信(单个或多个线程);
  2. 同一app内部的不同组件之间的消息通信(单个进程);
  3. 同一app具有多个进程的不同组件之间的消息通信;
  4. 不同app之间的组件之间消息通信;
  5. Android系统在特定情况下与App之间的消息通信。

三要素

广播

用于发送广播,是一种运用在应用程序之间的传递消息的机制。

广播接收器(过滤)

用于接收广播,是对发出来的广播进行过滤、接收、响应的组件。

意图内容

用于保存广播相关信息。

使用方法

  1. 设置意图(Intent)
1
2
3
4
Intent intent = new Intent();
intent.setAction("abc");
//设置数据,将需要广播出去的内容保存到intent中
intent.putExtra("key","values");//或者使用putExtras结合Bundle

系统产生的事件被定义为类Intent中的静态常量值。下面的表格列举了重要的系统事件

image-20221112100856331

新版本Android,发送静态广播,必须是定向广播,否则收不到。

需要设置Package

1
intent.setPackage("com.example.app");   //这是在代码中的设置,加在sendBroadcast之前
  1. 发送广播
1
sendBroadcast(intent); //使用sendBroadcast方法发送广播内容
  1. 创建广播接收器

New—Other—Broadcast Receiver

注意不是创建Activity而是Broadcast Receiver

编写一个继承BroadcastReceiver的广播接收器,并重写onReceive方法

1
2
3
4
5
6
7
class BCReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent)
{
/*接收到广播后做出响应的代码*/
}
}
  1. 注册广播接收器

在AndroidManifest.xml中注册广播接受类(系统会自动完成这个过程,默认静态注册)。

(1)静态注册

直接在AndroidManifest.xml文件中进行注册。规则如下:

1
2
3
4
5
6
7
8
9
<receiver android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
. . .
</receiver>

属性介绍

  • android:name:此broadcastReceiver的类名
  • android:enabled:是否可以被系统实例化,默认为 true。为true时服务才会被激活,否则不会激活
  • android:exported:此broadcastReceiver能否接收其他App的发出的广播,其默认值是由receiver中有无
  • intent-filter决定的,如果有intent-filter,默认值为true,否则为false
  • android:permission:如果设置,具有相应权限的广播发送方发送的广播才能被此broadcastReceiver所接收;
  • intent-filter:指定此广播接收器将用于接收特定的广播类型

(2)动态注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected void onCreate(Bundle savedInstanceState) {
……
//实例化IntentFilter对象
IntentFilter filter = new IntentFilter();
filter.addAction(“abc");
dynamicReceiver = new DynamicReceiver();
//注册广播接收
registerReceiver(dynamicReceiver,filter);
}
class DynamicReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//TODO
}
}
  1. 销毁广播接收器

在一定时间后销毁

动态注册

  1. 注销

系统服务

Android有许多标准系统服务(SystemService),如窗口管理服务WindowManager,通知管理服务NotificationManager、振动管理服务Vibrator、电池管理服务BatteryManager等。

系统服务实际上可以看作一个对象,通过Activity 的getSystemService() 方法可以获得指定对象(系统服务)。

接下来介绍两个常见的系统服务

通知管理服务

常说的通知栏

Notification是一种具有全局效果的通知,在手机的通知栏显示。当应用程序向系统发出通知时,它先以图标的形式显示在通知栏中,用户下拉通知栏可以查看通知的详细信息。

状态栏通知用到两个类:NotificationManagerNotification

Notification

是具体的状态栏通知对象,可以设置icon、文字、提示声音、振动等等参数。

Notification主要涉及 Notification.Builder()方法

1
2
3
4
5
6
小图标:必须提供,通过 setSmallIcon() 进行设置。
应用名称:由系统提供。
时间戳:由系统提供,但您可以使用 setWhen() 替换它或者使用 setShowWhen(false) 隐藏它。
大图标:可选内容(通常仅用于联系人照片,请勿将其用于应用图标),通过 setLargeIcon() 进行设置。
标题:可选内容,通过 setContentTitle() 进行设置。
文本:可选内容,通过 setContentText() 进行设置。

NotificationManager

状态栏通知的管理类,负责发通知、清除通知等。

NotificationManager是一个系统Service,必须通过getSystemService()方法来获取。

1
NotificationManager nm=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);

调用NotificationManager对象的notify() 方法把通知发送到状态栏。

1
nm.notify();

创建通知

首先,您需要使用 NotificationCompat.Builder 对象设置通知内容和渠道。以下示例显示了如何创建包含下列内容的通知:

  • 小图标,通过 setSmallIcon() 设置。这是所必需的唯一用户可见内容。
  • 标题,通过 setContentTitle() 设置。
  • 正文文本,通过 setContentText() 设置。
  • 通知优先级,通过 setPriority() 设置。优先级确定通知在 Android 7.1 和更低版本上的干扰程度。(对于 Android 8.0 和更高版本,必须设置渠道重要性,如下一节中所示。)
1
2
3
4
5
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(textTitle)
.setContentText(textContent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);

请注意,NotificationCompat.Builder 构造函数要求您提供渠道 ID。这是兼容 Android 8.0(API 级别 26)及更高版本所必需的,但会被较旧版本忽略。

默认情况下,通知的文本内容会被截断以放在一行。如果您想要更长的通知,可以使用 setStyle() 添加样式模板来启用可展开的通知。例如,以下代码会创建更大的文本区域

1
2
3
4
5
6
7
8
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Much longer text that cannot fit one line...")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Much longer text that cannot fit one line..."))
.setPriority(NotificationCompat.PRIORITY_DEFAULT);

创建渠道并设置重要性

必须先通过向 createNotificationChannel() 传递 NotificationChannel 的实例在系统中注册应用的通知渠道,然后才能在 Android 8.0 及更高版本上提供通知。因此以下代码会被 SDK_INT 版本上的条件阻止:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.channel_name); //渠道的名字,使用了软链接
String description = getString(R.string.channel_description); //渠道描述信息
int importance = NotificationManager.IMPORTANCE_DEFAULT; //渠道的重要性
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description); //设置渠道描述
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}

由于您必须先创建通知渠道,然后才能在 Android 8.0 及更高版本上发布任何通知,因此应在应用启动时立即执行这段代码。反复调用这段代码是安全的,因为创建现有通知渠道不会执行任何操作。

请注意,NotificationChannel 构造函数需要一个 importance,它会使用 NotificationManager 类中的一个常量。此参数确定出现任何属于此渠道的通知时如何打断用户,但您还必须使用 setPriority() 设置优先级,才能支持 Android 7.1 和更低版本(如上所示)。

虽然必须按本文所示设置通知重要性/优先级,但系统不能保证您会获得提醒行为。在某些情况下,系统可能会根据其他因素更改重要性级别,并且用户始终可以重新定义指定渠道适用的重要性级别。

如需详细了解不同级别的含义,请参阅通知重要性级别

设置通知的点按操作

每个通知都应该对点按操作做出响应,通常是在应用中打开对应于该通知的 Activity。为此,您必须指定通过 PendingIntent 对象定义的内容 Intent,并将其传递给 setContentIntent()

以下代码段展示了如何创建基本 Intent,以在用户点按通知时打开 Activity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Create an explicit intent for an Activity in your app
Intent intent = new Intent(this, AlertDetails.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
.setAutoCancel(true);

请注意,此代码会调用 setAutoCancel(),它会在用户点按通知后自动移除通知

以上所示的 setFlags() 方法可帮助保留用户在通过通知打开应用后的预期导航体验。但您是否要使用这一方法取决于您要启动的 Activity 类型,类型可能包括:

  • 专用于响应通知的 Activity。用户在正常使用应用时不会无缘无故想导航到这个 Activity,因此该 Activity 会启动一个新任务,而不是添加到应用的现有任务和返回堆栈。这就是以上示例中创建的 Intent 类型。
  • 应用的常规应用流程中存在的 Activity。在这种情况下,启动 Activity 时应创建返回堆栈,以便保留用户对返回和向上按钮的预期。

如需详细了解配置通知 Intent 的不同方法,请参阅从通知启动 Activity

显示通知

如需显示通知,请调用 NotificationManagerCompat.notify(),并将通知的唯一 ID 和 NotificationCompat.Builder.build() 的结果传递给它。例如:

1
2
3
4
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);

// notificationId is a unique int for each notification that you must define
notificationManager.notify(notificationId, builder.build());

请记得保存您传递到 NotificationManagerCompat.notify() 的通知 ID,因为如果之后您想要更新移除通知,将需要使用这个 ID。

注意:从 Android 8.1(API 级别 27)开始,应用每秒最多只能发出一次通知提示音。如果应用在一秒内发出了多条通知,这些通知都会按预期显示,但是每秒中只有第一条通知发出提示音。

区分渠道优先级和通知优先度

区分渠道id通知id

@NonNull String channelId The constructed Notification will be posted on this NotificationChannel.
int id the ID of the notification. The pair (tag, id) must be unique within your app.

系统定时服务

注:Android对时间的控制模式会影响定时效果

后台服务

Service是一种类似Activity的组件,但Service没有用户操作界面,也不能自己启动。需要通过特殊指令才能终止。

创建Service子类

  • 重写onClick方法
  • 重写onStartCommand方法
  • 重写onDestory方法

创建Activity

  1. 新建Intent对象,建立Activity 与Service的关联。
  2. 调用Activity的 startSevice(Intent) 方法启动 Service 后合服务;
  3. 调用Activity 的 stopService(lntent) 方法关闭 Service 后台服务。

修改配置文件AndroidManifest.xml

在<application>标签中添加以下代码

1
<service android:enabled="true" android:name=".后台服务程序" />

数据存储

文件存储

文件读写

Java的输入输出流

Json数据格式

JSON是一种轻量级的数据交换格式,与xml一样,也是基于纯文本的
数据格式。

对象结构JSONObject

JSON对象可以包括多个键值对,要求在大括号“{ }”中书写。

数组结构JSONArray

JSON数组可以包含多个JSON对象做元素,每个元素之间用逗号“, ”分隔,最外面用方括号“ [ ] ”。JSON数组是SON对象的有序集合。

JSON的使用

创建json

1
2
JSONObject jsonObject=new JSONObject();
JSONArray jsonArray=new JSONArray();

放入键值对

1
2
3
json.put("key","value")	;
//数组对象
json.put(object) ;

assets目录

assets目录是Android的一种特殊目录,用于放置APP所需的固定文件,
且该文件被打包到APK中时,不会被编码到二进制文件。

assets和raw的区别

  1. assets不会映射到R,而res/raw会映射到R,即可以使用R.raw或getResource()方法获取资源,;assets必须通过AssetManager进行操作。
  2. assets可以存在多级目录,raw不可以
  3. 在AssertManager中不能处理单个超过1MB的文件,不然会报异常,raw没这个限制。

轻量级存储SharedPerferences

SharedPreferences 是 Android 平台为应用开发者提供的一个轻量级的存储辅助类,用来保存应用的一些常用配置。

采用键值对的形式组织和管理数据,其数据存储在XML格式的文件中。在应用中通常做一些简单数据的持久化存储。

类似电脑上的Cookie,用于在一段时间内保存数据。

具体步骤

  1. 获取SharedPerference对象

首先声明一个sp对象,然后获取sp对象。

1
2
3
4
5
6
//声明SharePerference对象
private SharedPreferences sp;
//获取SharedPreferenced对象,getSharedPerference(String,int)
sp = getSharedPreferences("filename", Context.MODE_PRIVATE);
//第一个参数用于指定存储文件的名称
//第二个参数指定文件的操作模式。一般用MODE_PRIVATE私有方式存储,其它 应用无法访问。
  1. 设置参数

必须通过一个SharedPreference.Editor对象。存储键值对。只能存
放Boolean,Float,Int,Long,String 等类型(对应代码中的Xxx)。

1
2
SharedPreference.Editor editor = sp.edit();
editor.putXxx("key","value")
  1. 提交数据与清除数据

通过editor.commit()提交数据。也可以通过clean(),remove()清除。

1
2
3
editor.commit();
editor.clean();
editor.remove()

获得对象

三种获得sp对象的方法

  1. Context类中的getSharedPreferences()方法
1
//此方法接受两个参数,第一个是指定SharedPreferences的文件名称,第二个参数是操作模式,目前只有MODE_PRIVATE这一种模式可选,表示只有当前文件可以对这个文件进行读写。
  1. Activity类中的getPreferences()方法
1
//只接受操作模式这一个参数(目前只有MODE_PRIVATE这一种模式可选),使用这个方法的活动类名会作为SharedPreferences的文件名
  1. PreferenceManager类中的getDefaultSharedPreferences()方法
1
//只接受一个context参数,使用这个方法的包名会作为SharedPreferences的文件名。

访问数据

可以使用getXxx()方法获取对应的键值对,第一个参数为key名,第二个参数为不存在key名时的默认值。(Xxx指Boolean,Float,Int,Long,String 等类型)

1
sp.getString();

回调方法

在布局文件中绑定回调函数

xml

1
android:onClick="function"

java

1
2
3
public void function(View view){
//To do
}

SQLite轻量数据库