我正在尝试添加一个 AlarmManager 以每半分钟更新一次表盘。这是一个三进制时钟。这是我第一次使用 Java 或 android studio 编程。
我正在遵循https://developer.android.com/training/wearables/apps/always-on.html上的指南
该指南说“在您的活动的 onCreate() 方法中声明警报管理器和未决意图”
我应该使用
@Override
public Engine onCreateEngine() {
return new Engine();
}
或者
@Override
public Engine onCreateEngine() {
return new Engine();
}
或者我应该开始一个新方法还是在其他地方声明它?
目前我正在使用
private class Engine extends CanvasWatchFaceService.Engine {
final Handler mUpdateTimeHandler = new EngineHandler(this);
对于我的大部分初始化。
这是我没有警报管理器的代码。问题是它必须在半分钟内更新,因为作为平衡三进制,时间应该是最接近的分钟。
public class ternary extends CanvasWatchFaceService {
private static final Typeface NORMAL_TYPEFACE =
Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
private static final int MSG_UPDATE_TIME = 0;
@Override
public Engine onCreateEngine() {
return new Engine();
}
private static class EngineHandler extends Handler {
private final WeakReference<ternary.Engine> mWeakReference;
public EngineHandler(ternary.Engine reference) {
mWeakReference = new WeakReference<>(reference);
}
@Override
public void handleMessage(Message msg) {
ternary.Engine engine = mWeakReference.get();
if (engine != null) {
switch (msg.what) {
case MSG_UPDATE_TIME:
engine.handleUpdateTimeMessage();
break;
}
}
}
}
private class Engine extends CanvasWatchFaceService.Engine {
final Handler mUpdateTimeHandler = new EngineHandler(this);
boolean mRegisteredTimeZoneReceiver = false;
Paint mBackgroundPaint;
Paint mTextPaint;
boolean mAmbient;
Time mTime;
final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mTime.clear(intent.getStringExtra("time-zone"));
mTime.setToNow();
}
};
int mTapCount;
float mXOffset;
float mYOffset;
// adjust text size
float textRatio = (float)1; // 2/3;
// make adjusted offset for hours
float hrsIndent;
float hrsIndentAdjust = textRatio * 55;
// vertical offset for multiple lines
float ySpacer = textRatio * 65;
// first run.
boolean yesFirstRun = true;
// flag for seconds
boolean yesSecs;
// prior state of yesSecs
boolean wasSecs = true;
// flag for conservation mode (no seconds in ambient)
boolean yesConcerve = false;
// flag for allowing seconds
boolean allowSecs = true;
// for execution control
boolean openGate = false;
// counter for next draw
int c = 0;
// counter for time loops
int k;
boolean drawNow = true;
// strings for draw
String hrs = "";
String mns = "";
String sks = "";
// register for milliseconds
long millis = 0;
// float for calculating trits from time.
float tim = 0;
// ints for minute and hour offsets.
int minInt = 0;
int hourInt = 0;
// lists for time to trit for loop conversions.
int [] trits3 = {9, 3, 1};
int [] trits4 = {27, 9, 3, 1};
// absolute count for trouble shooting
// long x = 0;
/**
* Whether the display supports fewer bits for each color in ambient mode. When true, we
* disable anti-aliasing in ambient mode.
*/
boolean mLowBitAmbient;
@Override
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);
setWatchFaceStyle(new WatchFaceStyle.Builder(ternary.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
.setShowSystemUiTime(false)
.setAcceptsTapEvents(true)
.build());
Resources resources = ternary.this.getResources();
// shift y offset up
mYOffset = -30 + resources.getDimension(R.dimen.digital_y_offset);
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(resources.getColor(R.color.background));
mTextPaint = new Paint();
mTextPaint = createTextPaint(resources.getColor(R.color.digital_text));
mTime = new Time();
}
@Override
public void onDestroy() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
super.onDestroy();
}
private Paint createTextPaint(int textColor) {
Paint paint = new Paint();
paint.setColor(textColor);
paint.setTypeface(NORMAL_TYPEFACE);
paint.setAntiAlias(true);
return paint;
}
@Override
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
if (visible) {
registerReceiver();
// Update time zone in case it changed while we weren't visible.
mTime.clear(TimeZone.getDefault().getID());
mTime.setToNow();
} else {
unregisterReceiver();
}
// Whether the timer should be running depends on whether we're visible (as well as
// whether we're in ambient mode), so we may need to start or stop the timer.
updateTimer();
}
private void registerReceiver() {
if (mRegisteredTimeZoneReceiver) {
return;
}
mRegisteredTimeZoneReceiver = true;
IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
ternary.this.registerReceiver(mTimeZoneReceiver, filter);
}
private void unregisterReceiver() {
if (!mRegisteredTimeZoneReceiver) {
return;
}
mRegisteredTimeZoneReceiver = false;
ternary.this.unregisterReceiver(mTimeZoneReceiver);
}
@Override
public void onApplyWindowInsets(WindowInsets insets) {
super.onApplyWindowInsets(insets);
// Load resources that have alternate values for round watches.
Resources resources = ternary.this.getResources();
boolean isRound = insets.isRound();
// shift offset 75 to the right
mXOffset = 75 + resources.getDimension(isRound
? R.dimen.digital_x_offset_round : R.dimen.digital_x_offset);
float textSize = resources.getDimension(isRound
? R.dimen.digital_text_size_round : R.dimen.digital_text_size);
// adjust hrs Indent to MXOffset
hrsIndent = hrsIndentAdjust + mXOffset;
// adjust size to textRatio
mTextPaint.setTextSize(textSize * textRatio );
}
@Override
public void onPropertiesChanged(Bundle properties) {
super.onPropertiesChanged(properties);
mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
}
@Override
public void onTimeTick() {
super.onTimeTick();
invalidate();
}
@Override
public void onAmbientModeChanged(boolean inAmbientMode) {
super.onAmbientModeChanged(inAmbientMode);
if (mAmbient != inAmbientMode) {
mAmbient = inAmbientMode;
if (mLowBitAmbient) {
mTextPaint.setAntiAlias(!inAmbientMode);
}
invalidate();
}
// Whether the timer should be running depends on whether we're visible (as well as
// whether we're in ambient mode), so we may need to start or stop the timer.
updateTimer();
}
/**
* Captures tap event (and tap type) and toggles the background color if the user finishes
* a tap.
*/
@Override
public void onTapCommand(int tapType, int x, int y, long eventTime) {
Resources resources = ternary.this.getResources();
switch (tapType) {
case TAP_TYPE_TOUCH:
// The user has started touching the screen.
break;
case TAP_TYPE_TOUCH_CANCEL:
// The user has started a different gesture or otherwise cancelled the tap.
break;
case TAP_TYPE_TAP:
// The user has completed the tap gesture.
mTapCount++;
mBackgroundPaint.setColor(resources.getColor(mTapCount % 2 == 0 ?
R.color.background : R.color.background2));
break;
}
invalidate();
}
@Override
public void onDraw(Canvas canvas, Rect bounds) {
// Greebo counter
// x += 1;
// seconds handling
wasSecs = yesSecs;
yesSecs = allowSecs && !isInAmbientMode();
// for clearing seconds
if (!yesSecs && wasSecs) { sks = ""; }
// Draw at mid second
if (c == 0 && yesSecs) {
drawNow = true;
} else {
c = 0;
// mid minute
if (mTime.second == 30 || isInAmbientMode()) {
drawNow = true;
} else {
// mid hour
if (mTime.second == 0) {
if (mTime.minute == 30) {
drawNow = true;
} else {
// mid night
if (mTime.minute == 0) {
if (mTime.hour == 0) {
drawNow = true;
}
}
}
}
}
}
if (drawNow) {
drawNow = false;
mTime.setToNow();
millis = System.currentTimeMillis() % 1000;
// mid seconds
if (yesSecs) { if (millis > 499) { c = 1; } }
tim = (float)((mTime.minute * 60 + mTime.second) * 1000 + millis)/ 3600000;
// hours past noon
tim += mTime.hour - 12;
// find hrs 9s, 3s, 1s.
openGate = false;
if (yesFirstRun || mTime.minute == 30){ openGate = true; }
else { openGate = mTime.second == 0 && mTime.minute == 0 && mTime.hour == 0;}
if (openGate) {
hrs = "";
hourInt = 0;
// i is for item.
for (int i : trits3) {
if (tim > ((float) i / 2)) {
tim -= i;
hourInt -= i;
hrs = hrs + "1";
} else {
if (tim < ((float) i / -2)) {
tim += i;
hourInt += i;
hrs = hrs + "¬";
} else {
hrs = hrs + "0";
}
}
// add space
if (i > 1) {hrs += " "; }
}
} else { tim += hourInt; }
// minutes 27s, 9s, 3s, 1s
openGate = false;
if (yesFirstRun || mTime.second == 30 || isInAmbientMode()) {openGate = true; }
else { openGate = mTime.second == 0 && (mTime.minute == 30
|| (mTime.minute == 0 && mTime.hour == 0));}
if (openGate) {
mns = "";
tim *= 60;
minInt = 0;
// i is for item.
for (int i : trits4) {
if (tim > ((float) i / 2)) {
tim -= i;
if (yesSecs) {minInt -= i;}
mns = mns + "1";
} else {
if (tim < ((float) i / -2)) {
tim += i;
if (yesSecs) {minInt += i;}
mns = mns + "¬";
} else {
mns = mns + "0";
}
}
// add space
if (i > 1) {mns += " "; }
}
} else { if (yesSecs) { tim += minInt; tim *= 60; } }
// seconds 27s, 9s, 3s, 1s
if (yesSecs) {
sks = "";
tim *= 60;
for (int i : trits4) {
if (tim > ((float) i / 2)) {
tim -= i;
sks = sks + "1";
} else {
if (tim < ((float) i / -2)) {
tim += i;
sks = sks + "¬";
} else {
sks = sks + "0";
}
}
// add space
if (i > 1) {sks += " "; }
}
}
}
// Draw the background.
if (isInAmbientMode()) {
canvas.drawColor(Color.BLACK);
} else {
canvas.drawRect(0, 0, bounds.width(), bounds.height(), mBackgroundPaint);
}
// draw hours
canvas.drawText(hrs, hrsIndent, mYOffset - ySpacer, mTextPaint);
// draw minutes
canvas.drawText(mns, mXOffset, mYOffset, mTextPaint);
// draw or clear seconds
if (yesSecs || wasSecs) {canvas.drawText(sks, mXOffset, mYOffset + ySpacer , mTextPaint);}
// show count and millis for greebo reduction.
// canvas.drawText(String.format("%1$03d,%2$02d,%3$d", x % 1000, millis / 10, 0), mXOffset, mYOffset + 100, mTextPaint);
//canvas.drawText(String.format("%$02d:%2$02d:%3$02d", mTime.hour, mTime.minute,
// mTime.second), mXOffset, mYOffset + 100, mTextPaint);
}
/**
* Starts the {@link #mUpdateTimeHandler} timer if it should be running and isn't currently
* or stops it if it shouldn't be running but currently is.
*/
private void updateTimer() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
if (shouldTimerBeRunning()) {
mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
}
}
/**
* Returns whether the {@link #mUpdateTimeHandler} timer should be running. The timer should
* only run when we're visible and in interactive mode.
*/
private boolean shouldTimerBeRunning() {
return isVisible() && !isInAmbientMode();
}
/**
* Handle updating the time periodically in interactive mode.
*/
private void handleUpdateTimeMessage() {
invalidate();
if (shouldTimerBeRunning()) {
long timeMs = System.currentTimeMillis();
long delayMs = INTERACTIVE_UPDATE_RATE_MS
- (timeMs % INTERACTIVE_UPDATE_RATE_MS);
mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
}
}
}
}