这个demo主要演示presentation的用法,presentation是一种特殊的对话框,主要用于在另外一块屏幕上显示内容。值得注意的是在创建presentation前必须把presentation与它的目标屏幕相关联。所以在使用它之前必须为它选择一个Display。
选择display的方法主要有两种
一是利用MediaRouter
二是利用DisplayManager,
本例演示的是后一种方法
创建主布局文件:activity_main.xml
主要是一个用于控制显示所有屏幕的复选框和一个显示所有屏幕的列表框
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text=" Tish demostrates how to use a presentation and the DisplayManger to show content on other display
try connecting a second display and watch what happenes selecting a display and will open a presentatio on it."/>
<CheckBox
android:id="@+id/show_all_presentation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示所有pressentation"/>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent">
ListView>
LinearLayout>
编写MainActivity
public class MainActivity extends Activity implements OnCheckedChangeListener {
private static final String PRESENTATION_KEY = "presentation";
private DisplayManager displayManager;
private CheckBox show_all_displays;
private DisplayListAdapter displayAdapter;
private ListView listView;
// 定义存储photo的数组
private int[] photos = new int[] { R.drawable.guild1, R.drawable.guild2,
R.drawable.guild3, R.drawable.ic_launcher, R.drawable.puzzle,
R.drawable.test };
// 记录下一张照片的Id
private int nextPhotoNumber = 0;
/*
* 利用SparseArray存储所有屏幕的prsentation上显示的内容(尤其是当屏幕不止一个时数组的作用更大)
* SparseArray:稀疏数组,在存储数据不多的情况下可以大大地节省空间,此时可以代替hasmap使用
*/
SparseArray mSavedPresentationContents;
// 根据displayId记录当前显示的presentation
SparseArray mActivePresentations = new SparseArray();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 首先检查是否存在需要恢复的状态信息
if (savedInstanceState != null) {
mSavedPresentationContents = savedInstanceState
.getSparseParcelableArray(PRESENTATION_KEY);
} else {
mSavedPresentationContents = new SparseArray();
}
displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
show_all_displays = (CheckBox) findViewById(R.id.show_all_presentation);
show_all_displays.setOnCheckedChangeListener(this);
listView = (ListView) findViewById(R.id.listView);
displayAdapter = new DisplayListAdapter(this);
listView.setAdapter(displayAdapter);
}
/**
* 定义listView的适配器,用于显示所有的屏幕信息
*
* @author aaaa
*
*/
private class DisplayListAdapter extends ArrayAdapter<Display> {
private Context mContext;
// 构造函数,布局文件为R.layout.list_item
public DisplayListAdapter(Context context) {
super(context, R.layout.list_item);
mContext = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = null;
if (convertView == null) {
v = LayoutInflater.from(mContext).inflate(R.layout.list_item,
null);
} else {
v = convertView;
}
// 找到各个组件
CheckBox cb_display_presentation = (CheckBox) v
.findViewById(R.id.cb_presentation);
TextView tv_showId = (TextView) v.findViewById(R.id.tv_displayId);
Button bt_info = (Button) v.findViewById(R.id.bt_info);
Display display = getItem(position);
String text = "Display#" + display.getDisplayId()
+ display.getName();
tv_showId.setText(text);
// 将dispaly设置为复选框的标志位,将dispaly与复选框绑定在一起,找到复选框时就可以找到display了
cb_display_presentation.setTag(display);
// 如果当前presentation可见(存在于mActivePresentations中)或者mSavedPresentationContents中保存了
// 当前presentation显示的内容,则复选框为选中状态,否则为非选中状态
cb_display_presentation.setChecked(mActivePresentations
.indexOfKey(display.getDisplayId()) >= 0
|| mSavedPresentationContents.indexOfKey(display
.getDisplayId()) >= 0);
cb_display_presentation
.setOnCheckedChangeListener(MainActivity.this);
bt_info.setTag(display);
bt_info.setOnClickListener(mInfoClickListener);
return v;
}
/**
* 更新listVIew的显示信息
*/
public void updateListView() {
// 清空一下数据
clear();
String displayCategory = getDisplayCategory();
if (displayCategory == null) {
System.out.println("displayCategory is null");
}
Display[] displays = displayManager.getDisplays(displayCategory);
// 将所有的屏幕添加到数组中
addAll(displays);
}
/**
* 当复选框处于选中状态时列出所有的屏幕信息 处于非选中状态时只列出presentation屏幕信息
*
* @return
*/
private String getDisplayCategory() {
System.out.println(show_all_displays.isChecked());
return show_all_displays.isChecked() ? null
: DisplayManager.DISPLAY_CATEGORY_PRESENTATION;
}
}
private OnClickListener mInfoClickListener = new OnClickListener() {
/**
* 点击时创建一个对话框,用于显示dispaly的信息
*/
@Override
public void onClick(View v) {
Context context = v.getContext();
AlertDialog.Builder builder = new Builder(context);
Display display = (Display) v.getTag();
String title = "Dispaly #" + display.getDisplayId() + "Info";
builder.setTitle(title).setMessage(display.toString())
.setNeutralButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.show();
}
};
/**
* 同时为两个复选框提供监听服务
*/
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView == show_all_displays) {
// 更新列表框
displayAdapter.updateListView();
} else {
// 从复选框中取出Display
Display display = (Display) buttonView.getTag();
if (isChecked) {
// 显示下一张图片
PresentationContents contents = new PresentationContents(
getNextPhoto());
showPresentation(display, contents);
} else {
hidePresentation(display);
}
}
}
private int getNextPhoto() {
int nextPhoto = photos[nextPhotoNumber];
nextPhotoNumber = (nextPhotoNumber + 1) % photos.length;
return nextPhoto;
}
private void showPresentation(Display display, PresentationContents contents) {
int dispalyId = display.getDisplayId();
// 如果当前resentation已经是显示状态则直接返回
if (mActivePresentations.get(dispalyId) != null) {
return;
}
// 否则则新建一个presentation,并存储到mActivePresentations当中
DemoPresentation presentation = new DemoPresentation(this, display,
contents);
presentation.show();
// 设置prsentation的解除监听
presentation.setOnDismissListener(mPresentationDismissListener);
mActivePresentations.put(dispalyId, presentation);
}
private void hidePresentation(Display display) {
int dispalyId = display.getDisplayId();
DemoPresentation presentation = mActivePresentations.get(dispalyId);
if (presentation != null) {
presentation.dismiss();
mActivePresentations.remove(dispalyId);
}
}
private OnDismissListener mPresentationDismissListener = new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
DemoPresentation prsentation = (DemoPresentation) dialog;
int displayId = prsentation.getDisplay().getDisplayId();
// 从presentation数组当中将当前presentation删除
mActivePresentations.delete(displayId);
// 更新listView
displayAdapter.notifyDataSetChanged();
}
};
/**
* 当activity恢复时,首先从之前在pause状态中保存的presentation中显示的内容恢复过来
*/
@Override
protected void onResume() {
super.onResume();
// 更新listView
displayAdapter.updateListView();
// 恢复保存的presentationContent
if (mSavedPresentationContents.size() > 0) {
for (int i = 0; i < displayAdapter.getCount(); i++) {
Display display = displayAdapter.getItem(i);
PresentationContents content = mSavedPresentationContents
.get(display.getDisplayId());
if (content != null) {
showPresentation(display, content);
}
}
// 恢复完成后清空mSavedPresentationContents中的内容
mSavedPresentationContents.clear();
}
// 注册屏幕的监听事件
displayManager.registerDisplayListener(mDisplayListener, null);
}
/**
* 当activity不可见时保存presentation中显示的内容 将所有屏幕的presentation解除
*/
@Override
protected void onPause() {
super.onPause();
// 注销掉对屏幕的监听
displayManager.unregisterDisplayListener(mDisplayListener);
// 遍历当前所有可见的presentation
for (int i = 0; i < mActivePresentations.size(); i++) {
// 如果当前的presentation是可见的则将共内容保存
DemoPresentation presentation = mActivePresentations.valueAt(i);
int displayId = mActivePresentations.keyAt(i);
if (presentation != null) {
// 将所有display的显示内容保存
mSavedPresentationContents.put(displayId,
presentation.getmContents());
presentation.dismiss();
}
// 清空所mActivePresentations数组(所有presentation都不可见了)
mActivePresentations.clear();
}
}
/**
* 保存presentation的状态信息,用于当activity被非正常杀死时再次调用oncreate方法重建activity时 恢复状态
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSparseParcelableArray(PRESENTATION_KEY,
mSavedPresentationContents);
}
private DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
@Override
public void onDisplayRemoved(int displayId) {
displayAdapter.updateListView();
}
@Override
public void onDisplayChanged(int displayId) {
displayAdapter.updateListView();
}
@Override
public void onDisplayAdded(int displayId) {
displayAdapter.updateListView();
}
};
}
创建listView的item的布局文件listview_item.xml
主要是一个用于控制显示resentation的复选框,一个显示图片和display信息的textView。还有一个Button点击时显示display的详细信息。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp" >
<CheckBox
android:id="@+id/cb_presentation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"/>
<TextView
android:id="@+id/tv_displayId"
android:layout_toRightOf="@id/cb_presentation"
android:paddingLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Display #?:内置屏幕"/>
<Button
android:id="@+id/bt_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="info"/>
RelativeLayout>
创建presentation的布局文件,简单地显示了一个imageView和一个textView
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="@+id/presentation_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
android:layout_gravity="center"
/>
<TextView
android:id="@+id/presentation_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="text"/>
FrameLayout>
创建DemoPresentation类继承Presentation
/**
* 创建Presentation的子类,prsentation是一种特殊的对话框,它用来在另外的屏幕上显示内容
* 需要注意的是在创建它之前就必须要和它的目标屏幕进行绑定,指定目标屏幕的方式有两种一是利用MediaRouter
* 二是利用DisplayManager,本例演示的是后一种方法
* @author aaaa
*
*/
public class DemoPresentation extends Presentation {
private PresentationContents mContents;
public DemoPresentation(Context outerContext, Display display,PresentationContents contents) {
super(outerContext, display);
this.mContents=contents;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//根据prsentation的上下文获取到资源文件
Resources r=getContext().getResources();
setContentView(R.layout.presentation);
//获取到与之关联的屏幕
int photo=mContents.getPhoto();
Display display=getDisplay();
int displayId=display.getDisplayId();
String diplayName=display.getName();
TextView tv_desc=(TextView) findViewById(R.id.presentation_text);
ImageView iv_photo=(ImageView) findViewById(R.id.presentation_image);
//设置文本显示的内容:描述显示的图片的Id,屏幕的Id,屏幕的名字等信息
tv_desc.setText(r.getString(R.string.prsentation_photo_text,1,displayId,diplayName));
iv_photo.setImageDrawable(r.getDrawable(photo));
//GradientDrawable 支持使用渐变色来绘制图形,用其为activity设置渐变的背景色
GradientDrawable drawable=new GradientDrawable();
//设置图形模式为矩形
drawable.setShape(GradientDrawable.RECTANGLE);
//设置渐变的模式为圆形渐变
drawable.setGradientType(GradientDrawable.RADIAL_GRADIENT);
//获取到屏幕的大小
Point outSize=new Point();
getDisplay().getSize(outSize);
//设置圆形渐变的半径为屏幕长和宽的最大值的一半
drawable.setGradientRadius((Math.max(outSize.x, outSize.y))/2);
//设置渐变的颜色
drawable.setColors(mContents.getColors());
//为presentation的主界面添加渐变背景色
findViewById(android.R.id.content).setBackground(drawable);
}
public PresentationContents getmContents() {
return mContents;
}
}
创建PresentationContents类,用于定义在Presentation上显示的内容,该类实现了pacelable接口。该接口用于实现对象的序列化,可以实现在多个activity之间进行复杂的数据传递
/**
* 创建类,用于定义在presentation上显示的内容
* 该类实现了parcelable接口用于实现对象的序列化,
* 序列化之后就可以方便地在多个activity之间传递复杂的数据
* 实现parcelable接口必须实现三个方法
* 1.public int describeContents() 默认返回0即可
* 2.public void writeToParcel将类中的数据写入到包中(打包的过程)
* 3.public static final Creator CREATOR=new Creator(){}
* public static final一个都不能少,方法名CREATOR不能更改
* @author aaaa
*
*/
public class PresentationContents implements Parcelable {
private int photo;
private int[] colors;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(photo);
dest.writeInt(colors[0]);
dest.writeInt(colors[1]);
}
public static final Creator CREATOR=new Creator() {
/**
* 返回一组对象
*/
@Override
public PresentationContents[] newArray(int size) {
return new PresentationContents[size];
}
/**
* 返回单个对象
*/
@Override
public PresentationContents createFromParcel(Parcel source) {
return new PresentationContents(source);
}
};
//从包中解析数据
private PresentationContents(Parcel source) {
photo=source.readInt();
colors=new int[]{source.readInt(),source.readInt()};
}
public PresentationContents(int photo) {
super();
this.photo = photo;
colors=new int[]{
//获取两种随机颜色
((int) (Math.random()*Integer.MAX_VALUE))|0xff000000,
((int) (Math.random()*Integer.MAX_VALUE))|0xff000000
};
}
public int getPhoto() {
return photo;
}
public void setPhoto(int photo) {
this.photo = photo;
}
public int[] getColors() {
return colors;
}
}