原文地址:http://bbs.seacat.cn/thread-896-1-1.html
动态卡片出现在时间轴的现在和将来区域,显示当前时间段的关联信息。
你可以低频率的渲染动态卡片,几秒一次更新。或者高频率,一秒更新几次。
动态卡片的构建
动态卡片会长时间运行,所以需要一个后台服务来管理。
![](http://bbs.seacat.cn/data/attachment/forum/201401/15/142728nmp474ffxcxxz914.png)
你可以在服务启动或者其他监听事件触发的时候显示一张活动卡片,当活动卡片不再相关的时候,销毁服务停止渲染。
低频率渲染
低频率渲染仅限制于少数的android view 且几秒钟才能更新一次。
这是最简单创建动态卡片的方式,内容简单,不用不停的渲染。
![](http://bbs.seacat.cn/data/attachment/forum/201401/15/143345z33esg0jzi0iv3s2.png)
高频率渲染
它比低频率渲染调用的次数多,但也能提供更多功能特性。
![](http://bbs.seacat.cn/data/attachment/forum/201401/15/143605q71vr51rr67v8831.png)
创建低频率动态卡片
低频率渲染需要一个 RemoteViews对象提供UI,支持以下Android layouts 和 views:
FrameLayout
LinearLayout
RelativeLayout
GridLayout
AdapterViewFlipper
AnalogClock
Button
Chronometer
GridView
ImageButton
ImageView
ListView
ProgressBar
StackView
TextView
ViewFlipper
当以下情况使用低频率渲染:
1、你只需要标准的Android views APIs ,不需要高级渲染
2、你只需要相对较少刷新(几秒刷新一下)
记住:
1、对于时间轴动态卡片一定需要调用 setAction() 传入一个 PendingIntent
2、当发布之后,如果发现改变,调用setViews() 来再次更新布局
// Tag used to identify the LiveCard in debugging logs.
private static final String LIVE_CARD_TAG = "my_card";
// Cached instance of the LiveCard created by the publishCard() method.
private LiveCard mLiveCard;
private void publishCard(Context context) {
if (mLiveCard == null) {
TimelineManager tm = TimelineManager.from(context);
mLiveCard = tm.createLiveCard(LIVE_CARD_TAG);
mLiveCard.setViews(new RemoteViews(context.getPackageName(),
R.layout.card_text));
Intent intent = new Intent(context, EntryActivity.class);
mLiveCard.setAction(PendingIntent.getActivity(context, 0,
intent, 0));
mLiveCard.publish(LiveCard.PublishMode.SILENT);
} else {
// Card is already published.
return;
}
}
private void unpublishCard(Context context) {
if (mLiveCard != null) {
mLiveCard.unpublish();
mLiveCard = null;
}
}
创建高频率动态卡片
高频率动态卡片能让你直接绘图。这种渲染更灵活且能让你是用所有的Android graphics
当以下情况时使用高频率动态卡片:
1、你需要频繁更新动态卡片(一秒更新几次)
2、你能更灵活的渲染。 RemoteViews 只支持渲染一个布局,直接渲染能让你使用更多的graphics功能。
牢记:
1、你应该创建一个后台服务来渲染活动卡片的surface
2、使用surfaceCreated() 和 surfaceDestroyed() 来显示或隐藏卡片
3、 surface holder的回调方法不要在主线程调用
4、动态卡片一定需要调用 setAction() 传入一个 PendingIntent
使用高频率渲染:
1、创建一个实现 DirectRenderingCallback 的类:
public class LiveCardRenderer implements DirectRenderingCallback {
// About 30 FPS.
private static final long FRAME_TIME_MILLIS = 33;
private SurfaceHolder mHolder;
private boolean mPaused;
private RenderThread mRenderThread;
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// Update your views accordingly.
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mHolder = holder;
updateRendering();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mHolder = null;
updateRendering();
}
@Override
public void renderingPaused(SurfaceHolder holder, boolean paused) {
mPaused = paused;
updateRendering();
}
/**
* Start or stop rendering according to the timeline state.
*/
private synchronized void updateRendering() {
boolean shouldRender = (mHolder != null) && !mPaused;
boolean rendering = mRenderThread != null;
if (shouldRender != rendering) {
if (shouldRender) {
mRenderThread = new RenderThread();
mRenderThread.start();
} else {
mRenderThread.quit();
mRenderThread = null;
}
}
}
/**
* Draws the view in the SurfaceHolder's canvas.
*/
private void draw(View view) {
Canvas canvas;
try {
canvas = mHolder.lockCanvas();
} catch (Exception e) {
return;
}
if (canvas != null) {
// Draw on the canvas.
mHolder.unlockCanvasAndPost(canvas);
}
}
/**
* Redraws in the background.
*/
private class RenderThread extends Thread {
private boolean mShouldRun;
/**
* Initializes the background rendering thread.
*/
public RenderThread() {
mShouldRun = true;
}
/**
* Returns true if the rendering thread should continue to run.
*
* @return true if the rendering thread should continue to run
*/
private synchronized boolean shouldRun() {
return mShouldRun;
}
/**
* Requests that the rendering thread exit at the next opportunity.
*/
public synchronized void quit() {
mShouldRun = false;
}
@Override
public void run() {
while (shouldRun()) {
draw();
SystemClock.sleep(FRAME_TIME_MILLIS);
}
}
}
}
2、设置你的类的实例作为 LiveCard SurfaceHolder 的回调:
// Tag used to identify the LiveCard in debugging logs.
private static final String LIVE_CARD_TAG = "my_card";
// Cached instance of the LiveCard created by the publishCard() method.
private LiveCard mLiveCard;
private void publishCard(Context context) {
if (mLiveCard == null) {
TimelineManager tm = TimelineManager.from(context);
mLiveCard = tm.createLiveCard(LIVE_CARD_TAG);
// Enable direct rendering.
mLiveCard.setDirectRenderingEnabled(true);
mLiveCard.getSurfaceHolder().addCallback(new RenderThread());
Intent intent = new Intent(context, MenuActivity.class);
mLiveCard.setAction(PendingIntent.getActivity(context, 0,
intent, 0));
mLiveCard.publish(LiveCard.PublishMode.SILENT);
} else {
// Card is already published.
return;
}
}
private void unpublishCard(Context context) {
if (mLiveCard != null) {
mLiveCard.unpublish();
mLiveCard = null;
}
}
这个实例使用一个后台线程周期性的渲染,但你也可以响应外部事件来刷新卡片(例如传感器或地理位置更新)。
静默发布活动卡片
上面的例子传入LiveCard.PublishMode.REVEAL 到 LiveCard.publish() 方法中可以直接显示卡片。当你的Glassware的主界面是一张活动卡片时这样很有用。
通过使用 LiveCard.PublishMode.SILENT ,你也可以从后台创建一张活动卡片。用户也能在时间轴中看到它。