AndroidPresentation实现双屏异显
⼀、概述
现在越来越多的Android设备有多个屏幕,双屏异显应⽤场景最多的应该就是类似于收银平台那种设备,在主屏上店员能够对点商品进⾏选择录⼊,副屏则是展⽰给我们的账单详情,但是它只通过了⼀个软件系统就实现了双屏异显这个功能,⽽Presentation正是这其中的关键。
⼆、Presentation分析
1.简述:⾸先从它的继承关系上来看Presentation是继承⾃Dialog的,就是说它其实就是⼀种特殊的Dialog⽤于在第⼆个屏幕上显⽰内容的,它在创建时会和它的⽬标展⽰屏幕相关联,包括它的context和⼀些配置参数等。
2.Context:然⽽这⾥提到的context和它的容器所处的context会有不同,它会⽤⾃⾝的context去加载presentation的布局和相关资源以此来确保在⽬标屏幕上能够展⽰正确的⼤⼩和获取合适的屏幕密度。
3.⾃动移除:虽说presentation和它相关联的Activity的context不同,但是他们也不是完全分离的关系,当和presentation相关联的屏幕被移除后,presentation也会⾃动的被移除,所以当Activity处于pause和resume的状态时Presentation也需要特别注意当前显⽰的内容的状态。
4.屏幕选择:因为有时候我们的Android设备有多个屏幕,所以选择合适的屏幕去展⽰就显得⾮常重要了,所以在我们显⽰Presentation的时候需要去让我们的系统去选择合适的屏幕来进⾏展⽰,以下是两种⽅式去选择⼀个合适的屏幕。
这是我们选择展⽰presentation最简单的⼀种⽅式,media router是⼀种系统层级的服务,它能够追踪到系统当中所有可⽤的⾳频和视屏route,当有路径被选中或取消选中,还有当适合⽤presentation进⾏显⽰的时候的route改变的时候它会发送⼀个通知,然后应⽤本⾝会监控这个通知⾃动的去选择presentation的展⽰或者隐藏,这⾥的推荐使⽤的presentation display其实只是media router推荐的,如果我们的应⽤需要在第⼆个屏幕上进⾏显⽰就使⽤,如果不⽤的话就⽤本地来展⽰内容。
利⽤media router去选择presentation的显⽰屏幕
利⽤display manager去选择persentation的显⽰屏幕
DisplayManager能够监控到我们系统当中的所有连接上的显⽰设备,然⽽不是所有的设备都适⽤于作为副屏来进⾏内容展⽰的,⽐如当⼀个Activity想显⽰⼀个presentation在主屏幕上,其实效果就会相当于在主Activity当中显⽰了⼀个特殊的Dialog,所以当我们选择这种⽅式去选⽤Presentation去显⽰的时候就必须给它绑定⼀个可⽤的display。
三、源码分析
⾸先来看它的构造函数
public Presentation(Context outerContext, Display display, int theme) {
super(createPresentationContext(outerContext, display, theme), theme, false);
mDisplay = display;
mDisplayManager = (DisplayManager)getContext().getSystemService(DISPLAY_SERVICE);
final Window w = getWindow();
final WindowManager.LayoutParams attr = w.getAttributes();
w.setAttributes(attr);
w.setGravity(Gravity.FILL);
w.setType(TYPE_PRESENTATION);
setCanceledOnTouchOutside(false);
}
在它的形参中第⼀个Context参数⾮常重要,这是应⽤正在展⽰presentation的⼀个context,它是Presentation⾃⼰创建的它⾃⼰的⼀个context,基于这个context才能正确的在它所关联的屏幕上展⽰合适的信息。然后代码⾥⾯设置了这个window的相关属性。
接着我们看看它⾃⾝的Context的创建
private static Context createPresentationContext(
简述android概述Context outerContext, Display display, int theme) {
//⾸先判断传⼊的context和display是否为空,为空则抛出异常
if (outerContext == null) {
throw new IllegalArgumentException("outerContext must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
Context displayContext = ateDisplayContext(display);
//这⾥是对它的主题的判断,为0即为默认主题
if (theme == 0) {
TypedValue outValue = new TypedValue();
com.android.internal.R.attr.presentationTheme, outValue, true);
theme = sourceId;
}
/
/ Derive the display's window manager from the outer window manager.
// We do this because the outer window manager have some extra information
// such as the parent window, which is important if the presentation uses
// an application window type.
final WindowManagerImpl outerWindowManager =
(SystemService(WINDOW_SERVICE);
final WindowManagerImpl displayWindowManager =
//因为ContextThemeWrapper的⽗类是我们的Context
//所以这⾥最终返回的就是Presentation给我们创建好的Context
return new ContextThemeWrapper(displayContext, theme) {
/
/在这个⽅法中⼜返回的是Object对象
@Override
public Object getSystemService(String name) {
if (WINDOW_SERVICE.equals(name)) {
return displayWindowManager;
//如果和这个传⼊的name相同的话返回的就是上⾯windowManager创建出来的WindowManager的⼀个具体实现
}
//否则就返回的是Context这个抽象类中的⼀种服务类型
SystemService(name);
}
};
}
接着我们继续看⼀下Presentation对屏幕增加、移除和改变的监听
private final DisplayListener mDisplayListener = new DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {
}
@Override
public void onDisplayRemoved(int displayId) {
if (displayId == DisplayId()) {
handleDisplayRemoved();
}
}
@Override
public void onDisplayChanged(int displayId) {
if (displayId == DisplayId()) {
handleDisplayChanged();
}
}
};
这⾥我们看到它对add并没有进⾏处理,所以我们进⼀步去看⼀下onDisplayRemoved中的关键handlerDisplayRemoved和onDisplayChanged中的核⼼handlerDisplayChanged的实现
handlerDisplayChanged:
private void handleDisplayChanged() {
onDisplayChanged();
// We currently do not support configuration changes for presentations
// (although we could add that feature with a bit more work).
// If the display metrics have changed in any way then the current configuration
// is invalid and the application must recreate the presentation to get
// a new context.
if (!isConfigurationStillValid()) {
Log.i(TAG, "Presentation is being dismissed because the "
+ "display metrics have changed since it was created.");
cancel();
}
在这个⽅法中,我们遗憾的发现Google程序员并没有对当前屏幕配置发⽣改变后做特殊的处理,所以当我们的屏幕尺⼨等信息改变时,我们的presentation必须重新Create去重新获取context,再重新进⾏显⽰。
@Override
protected void onStart() {
// Since we were not watching for display changes until just now, there is a
// chance that the display metrics have changed. If so, we will need to
// dismiss the presentation immediately. This case is expected
// to be rare but surprising, so we'll write a log message about it.
if (!isConfigurationStillValid()) {
Log.i(TAG, "Presentation is being dismissed because the "
+ "display metrics have changed since it was created.");
mHandler.sendEmptyMessage(MSG_CANCEL);
}
}
同时在onStart中我们也能发现,因为它暂时还没有对display change进⾏监听,⽽这⾥⼜是有可能会改变的,所以在这种情况下它是打印了⼀个log去通知⼀下。
handlerDisplayRemoved这个⽅法的话是系统⾃动去发送⼀个消息,然后调⽤后把presentation⾃动取消掉。
四、总结
在基本分析了Presentation之后,主要要注意⼀下它的Context以及和Activity之间绑定的关系,其实从简单来看,它就是⼀个Dialog,不过是可以显⽰在多个屏幕上。当然上述分析深度尚浅,更深⼊的理解和⼀些问题要在后续⼯作中多使⽤再继续观察。
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。