说LocalBroadcastManager
有点冷落,一个是不多人知道而且合理使用广播,不少人要么使用的是系统的全局广播BraoadCastRecever
,要么使用EventBus
或RxAndroid
等等其余观察者模式的三方库,慢慢的就失宠了。然鹅,并不仅是这样,当如今你的项目迁移到Androidx时,会发现官方竟然把它废弃了,随后官方明确指出最适合的替代品LiveData
和reactive streams
,见如下描述 (官方传送门)html
LocalBroadcastManager
顾名思义就是本地广播,也是基于观察者模式的事件总线,用于应用内通讯,比较安全和高效,虽然迁移到androidx后,在1.1.0
高版本LocalBroadcastManager
被标记过期,可是它的用处仍是蛮大的,相比系统的广播,本地广播有着没法比拟的优越性,并且很是高效,相比第三方观察者模式库,知足条件下我宁愿使用1.0.0
版本的LocalBroadcastManager
。java
LocalBroadcastManager
为本地广播,只能接受自身App发送的广播,只能用于应用内之间的通讯,范围相对较小;而系统的BraoadCastRecever
能够实现跨进程通信,范围更大。LocalBroadcastManager
通讯核心是Handler
,因此只能用于应用内通讯,安全和效率都很高;而系统的BraoadCastRecever
通讯核心是Binder
机制, 实现跨进程通讯,范围更广,致使运行效率稍微逊一点。LocalBroadcastManager
因为核心是Handler
,并且只能动态注册,只能用于app内通讯,安全上更加的有保障;而系统的BraoadCastRecever
容易被利用,安全上相对较弱一点。注册广播:react
IntentFilter filter = new IntentFilter();
filter.addAction(“你的Action”);
LocalBroadcastManager.getInstance(Context context).registerReceiver(BroadcastReceiver receiver, filter);
复制代码
发送广播:android
LocalBroadcastManager.getInstance(Context context).sendBroadcast(Intent intent);
复制代码
取消注册:数据库
LocalBroadcastManager.getInstance(this).unregisterReceiver(BroadcastReceiver receiver);
复制代码
接收广播:数组
final class MyBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if(intent!=null && “你的Action”.equals(intent.getAction())){
// 处理逻辑
}
}
}
复制代码
在《阿里巴巴Android开发手册(正式版)_v1.0.0》中有明确指出关于广播的使用规范问题,如下规范等级为强制,因此咱们应用合理正确的使用广播,遵循绿色公约,避免信息泄露和拦截意图的风险,如下为规范描述:安全
若是广播仅限于应用内,则可使用
LocalBroadcastManager#sendBroadcast()
实现,避免敏感信息外泄和 Intent 拦截的风险。性能优化
@NonNull
public static LocalBroadcastManager getInstance(@NonNull Context context) {
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
private LocalBroadcastManager(Context context) {
mAppContext = context;
mHandler = new Handler(context.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_EXEC_PENDING_BROADCASTS:
executePendingBroadcasts();
break;
default:
super.handleMessage(msg);
}
}
};
}
复制代码
初始化上LocalBroadcastManager
明显采起的是懒汉模式的单例模式,而且初始化的时候建立了一个Handler
对象,在主线程上进行工做,用于处理发送的广播,这就是和系统BroadCastReciver
的最大区别,系统广播则是经过Binder
机制进行通讯的,而本地广播采起的是Handler
机制进行通讯。bash
private final HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>> mReceivers = new HashMap<>();
private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();
private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<>();
public void registerReceiver(@NonNull BroadcastReceiver receiver,
@NonNull IntentFilter filter) {
synchronized (mReceivers) {
ReceiverRecord entry = new ReceiverRecord(filter, receiver);
ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
if (filters == null) {
filters = new ArrayList<>(1);
mReceivers.put(receiver, filters);
}
filters.add(entry);
for (int i=0; i<filter.countActions(); i++) {
String action = filter.getAction(i);
ArrayList<ReceiverRecord> entries = mActions.get(action);
if (entries == null) {
entries = new ArrayList<ReceiverRecord>(1);
mActions.put(action, entries);
}
entries.add(entry);
}
}
}
复制代码
注册广播则明显可以看出是经过2个Map嵌套集合mReceivers
和mActions
来进行协调运做的,而mReceivers
则是以receiver
做为key,存储的是一个接收记录ReceiverRecord
集合,而ReceiverRecord
是用来存储筛选器IntentFilter
与广播接收器BroadcastReceiver
及广播运行状态的,可是因为LocalBroadcastManager
是单例模式,能够存放多个广播接收器BroadcastReceiver
故采用的集合嵌套,同理mActions
是以筛选器中的action
做为key,存储的也是ReceiverRecord
集合。网络
public boolean sendBroadcast(@NonNull Intent intent) {
synchronized (mReceivers) {
final String action = intent.getAction();
final String type = intent.resolveTypeIfNeeded(
mAppContext.getContentResolver());
final Uri data = intent.getData();
final String scheme = intent.getScheme();
final Set<String> categories = intent.getCategories();
==========================省略部分===================
if (receivers != null) {
for (int i=0; i<receivers.size(); i++) {
receivers.get(i).broadcasting = false;
}
mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
}
return true;
}
}
}
return false;
}
复制代码
明显看出本地广播是经过Handler
进行发送消息的,检查排队队列是否有未发布的MSG_EXEC_PENDING_BROADCASTS
,没有的话发送消息。
void executePendingBroadcasts() {
while (true) {
final BroadcastRecord[] brs;
synchronized (mReceivers) {
final int N = mPendingBroadcasts.size();
if (N <= 0) {
return;
}
brs = new BroadcastRecord[N];
mPendingBroadcasts.toArray(brs);
mPendingBroadcasts.clear();
}
for (int i=0; i<brs.length; i++) {
final BroadcastRecord br = brs[i];
final int nbr = br.receivers.size();
for (int j=0; j<nbr; j++) {
final ReceiverRecord rec = br.receivers.get(j);
if (!rec.dead) {
rec.receiver.onReceive(mAppContext, br.intent);
}
}
}
}
}
复制代码
当工做线程接收到Handler
发送的消息时候,会执行executePendingBroadcasts()
方法,发送广播的时候mPendingBroadcasts
来存储Intent
意图与广播接收器ReceiverRecord
,当处理广播的时候,从mPendingBroadcasts
中取出信息存放到广播接收器数组BroadcastRecord[]
中,经过循环调用广播接收的抽象方法onReceive(Context context,Intent intent)
进行消息发送到前台主线程,就这样完成了应用内通讯。
LiveData是官方架构组件,是Jetpack众多组件的一个,它是一个可观察的数据持有者类。与常规的可观察对象不一样,LiveData是生命周期感知的,这意味着它尊重其余应用程序组件的生命周期,好比activities
、fragments
或者services
。这种意识确保LiveData只更新处于活动生命周期状态的应用程序组件观察者。
LiveData认为,若是一个观察者的生命周期处于STARTED
或RESUMED
状态,那么这个观察者(由observer类表示)就处于活动状态。LiveData只将更新通知活动观察者。注册为监视LiveData对象的非活动观察者不会收到有关更改的通知。
您能够注册一个与实现LifecycleOwner
接口的对象配对的观察者。当相应的生命周期对象的状态更改成DESTROYED
时,此关系容许删除观察者。这对于活动和片断特别有用,由于它们能够安全地观察LiveData对象,而不用担忧泄漏——当activities
和fragments
的生命周期被破坏时,它们会当即取消订阅。
UI界面与数据实时保证一致
LiveData遵循观察者模式。当生命周期状态发生变化时,LiveData通知观察者Observer
对象。您能够合并代码来更新这些观察者对象中的UI。您的观察者能够在每次发生更改时更新UI,而不是每次应用程序数据更改时都更新UI
不会形成内存泄漏
观察者被绑定到生命周期Lifecycle
对象,并在其关联的生命周期被destroyed
后进行清理。
当界面销毁或者中止活动不会形成崩溃
若是观察者的生命周期是不活动的,例如在后堆栈中的活动,那么它不会接收任何LiveData事件。
不须要手动处理生命周期
UI组件只观察相关数据,不中止或恢复观察。LiveData自动管理全部这些,由于它在观察过程当中知道相关的生命周期状态变化。
老是保证最新的数据
若是一个生命周期变为不活动的,它将在再次活动时接收最新的数据。例如,在后台的活动在返回到前台后当即接收最新的数据。
适当的配置更改
若是某个activitys
或fragments
因为配置更改(如设备旋转)而从新建立,它将当即接收最新可用数据。
共享资源和数据
您可使用singleton模式扩展LiveData对象来包装系统服务,以便在您的应用程序中共享它们。LiveData对象链接到系统服务一次,而后任何须要该资源的观察者均可以查看LiveData对象。有关更多信息,请参见Extend LiveData。
返回类型 | 方法 | 说明 |
---|---|---|
T | getValue() | 返回T类型的对象值 |
boolean | hasActiveObservers() | 当前是否有活动的观察者observers |
boolean | hasObservers() | 当前是否有观察者observers |
void | observe(LifecycleOwner owner, Observer<? super T> observer) | 添加观察者对象到列表,配合生命周期 |
void | observeForever(Observer<? super T> observer) | 添加观察者对象到列表,无生命周期 |
void | removeObserver(Observer<? super T> observer) | 从观察者列表中移除给定的观察者 |
void | removeObservers(LifecycleOwner owner) | 删除与给定生命周期全部者绑定的全部观察者 |
void | onActive() | 当活动观察者的数量从0变为1时调用 |
void | onInactive() | 当活动观察者的数量从1变为0时调用 |
void | postValue(T value) | 将任务发布到主线程以设置给定值 |
void | setValue(T value) | 设置更新数据源 |
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:1.1.1"
// just ViewModel
implementation "android.arch.lifecycle:viewmodel:1.1.1"
// just LiveData
implementation "android.arch.lifecycle:livedata:1.1.1"
复制代码
ViewModel
一块儿使用,也能够单独使用。public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> currentName;
public MutableLiveData<String> getCurrentName() {
if (currentName == null) {
currentName = new MutableLiveData<String>();
}
return currentName;
}
// Rest of the ViewModel...
}
复制代码
注意:确保将更新UI的LiveData对象存储在ViewModel对象中,而不是存储在Activity或Fragment中,缘由以下: 以免膨胀的Activity和Fragment。如今这些UI控制器负责显示数据,而不是保存数据状态。 将LiveData实例与特定的Activity或Fragment实例解耦,并容许LiveData对象在配置更改后仍然存在。
Observer
,该对象定义onChanged()
方法,该方法控制LiveData对象持有的数据更改时发生的状况。一般在UI控制器中建立一个观察者对象,例如一个Activity
或者fragment
。public class NameActivity extends AppCompatActivity {
private NameViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Other code to setup the activity...
// Get the ViewModel.
model = ViewModelProviders.of(this).get(NameViewModel.class);
// Create the observer which updates the UI.
final Observer<String> nameObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
// Update the UI, in this case, a TextView.
nameTextView.setText(newName);
}
};
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.getCurrentName().observe(this, nameObserver);
}
}
复制代码
在大多数状况下,应用程序组件的onCreate()方法是开始观察LiveData对象的合适位置,缘由以下: 以确保系统不会从活动或fragment的onResume()方法发出冗余调用。 确保活动或片断具备数据,能够在活动时当即显示这些数据。一旦应用程序组件处于启动状态,它就会从它所观察的LiveData对象接收到最近的值。只有在设置了要观察的LiveData对象时才会发生这种状况。 一般,LiveData只在数据发生更改时提供更新,而且只向活动观察者提供更新。这种行为的一个例外是,当观察者从非活动状态更改成活动状态时,也会收到更新。此外,若是观察者第二次从非活动状态更改成活动状态,则只有当值自上次活动以来发生更改时,才会接收到更新。
LifecycleOwner
对象。这订阅观察者对象到LiveData对象,以便在发生更改时通知它。一般将观察者对象附加到UI控制器中,例如Activity
或Fragment
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.getCurrentName().observe(this, nameObserver);
复制代码
您可使用observeForever(observer)方法注册一个没有关联LifecycleOwner对象的观察者。在这种状况下,观察者老是被认为是活跃的,所以老是被通知修改。您能够删除调用removeObserver(Observer)方法的这些观察者。
public class StockLiveData extends LiveData<BigDecimal> {
private StockManager stockManager;
private SimplePriceListener listener = new SimplePriceListener() {
@Override
public void onPriceChanged(BigDecimal price) {
setValue(price);
}
};
public StockLiveData(String symbol) {
stockManager = new StockManager(symbol);
}
@Override
protected void onActive() {
stockManager.requestPriceUpdates(listener);
}
@Override
protected void onInactive() {
stockManager.removeUpdates(listener);
}
}
复制代码
当LiveData对象具备活动观察者时,将调用onActive()方法。这意味着您须要开始从该方法观察股票价格更新。
当LiveData对象没有任何活动的观察者时,将调用onInactive()方法。由于没有观察者在听,因此没有理由保持与StockManager服务的链接。
setValue(T)方法更新LiveData实例的值,并将更改通知任何活动的观察者。
public class MyFragment extends Fragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LiveData<BigDecimal> myPriceListener = ...;
myPriceListener.observe(this, price -> {
// Update the UI.
});
}
}
复制代码
方法将fragment(它是LifecycleOwner的一个实例)做为第一个参数传递。这样作意味着这个观察者被绑定到与全部者关联的Lifecycle对象上,这意味着:
若是Lifecycle对象没有处于活动状态,那么即便值发生了更改,也不会调用观察者 销毁生命周期对象后,将自动删除观察者。
LiveData对象是生命周期感知的,这意味着您能够在多个Activitys
、Fragments
和service
之间共享它们。为了保持示例的简单性,能够将LiveData类实现为单例,以下所示:
public class StockLiveData extends LiveData<BigDecimal> {
private static StockLiveData sInstance;
private StockManager stockManager;
private SimplePriceListener listener = new SimplePriceListener() {
@Override
public void onPriceChanged(BigDecimal price) {
setValue(price);
}
};
@MainThread
public static StockLiveData get(String symbol) {
if (sInstance == null) {
sInstance = new StockLiveData(symbol);
}
return sInstance;
}
private StockLiveData(String symbol) {
stockManager = new StockManager(symbol);
}
@Override
protected void onActive() {
stockManager.requestPriceUpdates(listener);
}
@Override
protected void onInactive() {
stockManager.removeUpdates(listener);
}
}
复制代码
在Activity
、Fragment
、Service
中能够这么调用,经过单例实现共享数据
public class MyFragment extends Fragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
StockLiveData.get(symbol).observe(this, price -> {
// Update the UI.
});
}
}
复制代码
在将LiveData对象发送给观察者以前,您可能但愿更改存储在LiveData对象中的值,或者您可能须要根据另外一个LiveData实例的值返回另外一个LiveData实例。生命周期包提供转换类,该类包含支持这些场景的helper方法。
Transformations.map ()
对存储在LiveData对象中的值应用函数,并将结果向下传播
LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
user.name + " " + user.lastName
});
复制代码
Transformations.switchMap()
与map()相似,将函数应用于存储在LiveData对象中的值,并将结果解包并向下分派。传递给switchMap()的函数必须返回LiveData对象,以下例所示:
private LiveData<User> getUser(String id) {
...;
}
LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
复制代码
您可使用转换方法在观察者的生命周期中携带信息。除非观察者正在观察返回的LiveData对象,不然不会计算转换。由于转换是延迟计算的,因此与生命周期相关的行为是隐式传递的,不须要额外的显式调用或依赖关系。
若是您认为在ViewModel对象中须要一个生命周期对象,那么转换多是一个更好的解决方案。例如,假设您有一个UI组件,它接受一个地址并返回该地址的邮政编码。您能够为这个组件实现简单的视图模型,以下面的示例代码所示:
class MyViewModel extends ViewModel {
private final PostalCodeRepository repository;
public MyViewModel(PostalCodeRepository repository) {
this.repository = repository;
}
private LiveData<String> getPostalCode(String address) {
// DON'T DO THIS,不推荐 return repository.getPostCode(address); } } 复制代码
而后,UI组件须要从之前的LiveData对象注销注册,并在每次调用getPostalCode()
时注册到新实例。此外,若是从新建立UI组件,它将触发对repository.getPostCode()
方法的另外一个调用,而不是使用前一个调用的结果。
相反,您能够将邮政编码查询实现为地址输入的转换,以下面的示例所示:
class MyViewModel extends ViewModel {
private final PostalCodeRepository repository;
private final MutableLiveData<String> addressInput = new MutableLiveData();
public final LiveData<String> postalCode =
Transformations.switchMap(addressInput, (address) -> {
return repository.getPostCode(address);
});
public MyViewModel(PostalCodeRepository repository) {
this.repository = repository
}
private void setInput(String address) {
addressInput.setValue(address);
}
}
复制代码
在这种状况下,该postalCode字段被定义为转换addressInput。只要您的应用程序具备与该postalCode字段关联的活动观察者,就会在addressInput更改时从新计算并检索字段的值 。
此机制容许较低级别的应用程序建立LiveData按需延迟计算的对象。甲ViewModel对象能够容易地得到以引用LiveData的对象,而后在它们的顶部限定的变换规则。
有十几种不一样的特定转换可能对您的应用有用,但默认状况下不提供。要实现本身的转换,您可使用MediatorLiveData该类,该类侦听其余LiveData对象并处理它们发出的事件。MediatorLiveData正确地将其状态传播到源LiveData对象。要了解有关此模式的更多信息,请参阅Transformations 该类的参考文档 。
MediatorLiveData
是一个子类LiveData,容许您合并多个LiveData源。MediatorLiveData
只要任何原始LiveData源对象发生更改,就会触发对象的观察者。
例如,若是LiveDataUI中有一个能够从本地数据库或网络更新的对象,则能够将如下源添加到该 MediatorLiveData
对象:
LiveData与存储在数据库中的数据关联的对象。
LiveData与从网络访问的数据关联的对象。
LiveData liveData1 = ...;
LiveData liveData2 = ...;
MediatorLiveData liveDataMerger = new MediatorLiveData<>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
复制代码
读到这里,是否是发现LiveData
即有点像EventBus
,又有点像Rxjava
,这正是他的强大之处,另外它还可以结合组件的生命周期使用,不只可以共享资源与数据,并且UI与数据同步也是很是实时的,正如官方对Jetpack组件的描述,不只可以提升开发效率,并且让应用变得更加优质,若是你还未体验过,赶忙试一下吧。