com.marlonjones.nimbus.WeatherWatchFaceService.WeatherWatchFaceEngine

时间:2015-06-05 00:16:37

标签: java android wear-os watch-face-api

我看了几个地方,包括在这里,我找到的答案没有帮助。我还查看了我正在使用的模板的代码,但没有看到我出错的地方,所以如果这看起来像一个糟糕的问题,我很抱歉。但我正在制作一个表盘,我正试图从我的引擎WeatherWatchFaceEngine扩展它。但是当我这样做时,我得到了这个问题标题中的错误。我做错了什么?

这是表盘的代码:

    public class NimbusSplashAnalog extends WeatherWatchFaceService {
/**
 * Update rate in milliseconds for interactive mode. We update once a second to advance the
 * second hand.
 */
private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.SECONDS.toMillis(1);

/**
 * Handler message id for updating the time periodically in interactive mode.
 */
private static final int MSG_UPDATE_TIME = 0;

@Override
public Engine onCreateEngine() {
    return new Engine();
}

private class Engine extends WeatherWatchFaceEngine {
    Paint mBackgroundPaint;
    Paint mHandPaint;
    boolean mAmbient;
    Time mTime;

    final Handler mUpdateTimeHandler = new EngineHandler(this);

    final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            mTime.clear(intent.getStringExtra("time-zone"));
            mTime.setToNow();
        }
    };
    boolean mRegisteredTimeZoneReceiver = false;

    /**
     * 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(NimbusSplashAnalog.this)
                .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
                .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
                .setShowSystemUiTime(false)
                .build());

        Resources resources = NimbusSplashAnalog.this.getResources();

        mBackgroundPaint = new Paint();
        mBackgroundPaint.setColor(resources.getColor(R.color.analog_background));

        mHandPaint = new Paint();
        mHandPaint.setColor(resources.getColor(R.color.analog_hands));
        mHandPaint.setStrokeWidth(resources.getDimension(R.dimen.analog_hand_stroke));
        mHandPaint.setAntiAlias(true);
        mHandPaint.setStrokeCap(Paint.Cap.ROUND);

        mTime = new Time();
    }

    @Override
    public void onDestroy() {
        mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
        super.onDestroy();
    }

    @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) {
                mHandPaint.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();
    }

    @Override
    public void onDraw(Canvas canvas, Rect bounds) {
        mTime.setToNow();

        int width = bounds.width();
        int height = bounds.height();

        // Draw the background.
        canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mBackgroundPaint);

        // Find the center. Ignore the window insets so that, on round watches with a
        // "chin", the watch face is centered on the entire screen, not just the usable
        // portion.
        float centerX = width / 2f;
        float centerY = height / 2f;

        float secRot = mTime.second / 30f * (float) Math.PI;
        int minutes = mTime.minute;
        float minRot = minutes / 30f * (float) Math.PI;
        float hrRot = ((mTime.hour + (minutes / 60f)) / 6f) * (float) Math.PI;

        float secLength = centerX - 20;
        float minLength = centerX - 40;
        float hrLength = centerX - 80;

        if (!mAmbient) {
            float secX = (float) Math.sin(secRot) * secLength;
            float secY = (float) -Math.cos(secRot) * secLength;
            canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mHandPaint);
        }

        float minX = (float) Math.sin(minRot) * minLength;
        float minY = (float) -Math.cos(minRot) * minLength;
        canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY, mHandPaint);

        float hrX = (float) Math.sin(hrRot) * hrLength;
        float hrY = (float) -Math.cos(hrRot) * hrLength;
        canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY, mHandPaint);
    }


    @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);
        NimbusSplashAnalog.this.registerReceiver(mTimeZoneReceiver, filter);
    }

    private void unregisterReceiver() {
        if (!mRegisteredTimeZoneReceiver) {
            return;
        }
        mRegisteredTimeZoneReceiver = false;
        NimbusSplashAnalog.this.unregisterReceiver(mTimeZoneReceiver);
    }

    /**
     * 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);
        }
    }
}

private static class EngineHandler extends Handler {
    private final WeakReference<NimbusSplashAnalog.Engine> mWeakReference;

    public EngineHandler(NimbusSplashAnalog.Engine reference) {
        mWeakReference = new WeakReference<>(reference);
    }

    @Override
    public void handleMessage(Message msg) {
        NimbusSplashAnalog.Engine engine = mWeakReference.get();
        if (engine != null) {
            switch (msg.what) {
                case MSG_UPDATE_TIME:
                    engine.handleUpdateTimeMessage();
                    break;
            }
        }
    }
}

}

这是我要扩展的引擎/服务的代码:

    public abstract class WeatherWatchFaceService extends CanvasWatchFaceService {
public class WeatherWatchFaceEngine extends CanvasWatchFaceService.Engine
        implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        DataApi.DataListener, NodeApi.NodeListener {

    protected static final int MSG_UPDATE_TIME = 0;
    protected long UPDATE_RATE_MS;
    protected static final long WEATHER_INFO_TIME_OUT = DateUtils.HOUR_IN_MILLIS * 6;
    protected final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            //Time zone changed
            mWeatherInfoReceivedTime = 0;
            mTime.clear(intent.getStringExtra("time-zone"));
            mTime.setToNow();
        }
    };
    /**
     * Handler to update the time periodically in interactive mode.
     */
    protected final Handler mUpdateTimeHandler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            switch (message.what) {
                case MSG_UPDATE_TIME:
                    invalidate();

                    if (shouldUpdateTimerBeRunning()) {
                        long timeMs = System.currentTimeMillis();
                        long delayMs = UPDATE_RATE_MS - (timeMs % UPDATE_RATE_MS);
                        mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
                        requireWeatherInfo();
                    }
                    break;
            }
        }
    };
    protected int mTheme = 3;
    protected int mTimeUnit = ConverterUtil.TIME_UNIT_12;
    protected AssetManager mAsserts;
    protected Bitmap mWeatherConditionDrawable;
    protected GoogleApiClient mGoogleApiClient;
    protected Paint mBackgroundPaint;
    protected Paint mDatePaint;
    protected Paint mDateSuffixPaint;
    protected Paint mDebugInfoPaint;
    protected Paint mTemperatureBorderPaint;
    protected Paint mTemperaturePaint;
    protected Paint mTemperatureSuffixPaint;
    protected Paint mTimePaint;
    protected Resources mResources;
    protected String mWeatherCondition;
    protected String mWeatherConditionResourceName;
    protected Time mSunriseTime;
    protected Time mSunsetTime;
    protected Time mTime;
    protected boolean isRound;
    protected boolean mLowBitAmbient;
    protected boolean mRegisteredService = false;

    protected int mBackgroundColor;
    protected int mBackgroundDefaultColor;
    protected int mRequireInterval;
    protected int mTemperature = Integer.MAX_VALUE;
    protected int mTemperatureScale;
    protected long mWeatherInfoReceivedTime;
    protected long mWeatherInfoRequiredTime;
    private String mName;

    public WeatherWatchFaceEngine(String name) {
        mName = name;
        mGoogleApiClient = new GoogleApiClient.Builder(WeatherWatchFaceService.this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(Wearable.API)
                .build();
    }

    @Override
    public void onConnected(Bundle bundle) {
        log("Connected: " + bundle);
        getConfig();

        Wearable.NodeApi.addListener(mGoogleApiClient, this);
        Wearable.DataApi.addListener(mGoogleApiClient, this);
        requireWeatherInfo();
    }

    @Override
    public void onConnectionSuspended(int i) {
        log("ConnectionSuspended: " + i);
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        for (int i = 0; i < dataEvents.getCount(); i++) {
            DataEvent event = dataEvents.get(i);
            DataMap dataMap = DataMap.fromByteArray(event.getDataItem().getData());
            log("onDataChanged: " + dataMap);

            fetchConfig(dataMap);
        }
    }

    @Override
    public void onPeerConnected(Node node) {
        log("PeerConnected: " + node);
        requireWeatherInfo();
    }

    @Override
    public void onPeerDisconnected(Node node) {
        log("PeerDisconnected: " + node);
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        log("ConnectionFailed: " + connectionResult);

    }


    @Override
    public void onCreate(SurfaceHolder holder) {
        super.onCreate(holder);

        setWatchFaceStyle(new WatchFaceStyle.Builder(WeatherWatchFaceService.this)
                .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
                .setAmbientPeekMode(WatchFaceStyle.AMBIENT_PEEK_MODE_HIDDEN)
                .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
                .setShowSystemUiTime(false)
                .build());

        mResources = WeatherWatchFaceService.this.getResources();
        mAsserts = WeatherWatchFaceService.this.getAssets();

        mDebugInfoPaint = new Paint();
        mDebugInfoPaint.setColor(Color.parseColor("White"));
        mDebugInfoPaint.setTextSize(20);
        mDebugInfoPaint.setAntiAlias(true);

        mTime = new Time();
        mSunriseTime = new Time();
        mSunsetTime = new Time();

        mRequireInterval = mResources.getInteger(R.integer.weather_default_require_interval);
        mWeatherInfoRequiredTime = System.currentTimeMillis() - (DateUtils.SECOND_IN_MILLIS * 58);
        mGoogleApiClient.connect();
    }

    @Override
    public void onDestroy() {
        log("Destroy");
        mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
        super.onDestroy();
    }

    @Override
    public void onInterruptionFilterChanged(int interruptionFilter) {
        super.onInterruptionFilterChanged(interruptionFilter);

        log("onInterruptionFilterChanged: " + interruptionFilter);
    }

    @Override
    public void onPropertiesChanged(Bundle properties) {
        super.onPropertiesChanged(properties);
        mLowBitAmbient = properties.getBoolean(WatchFaceService.PROPERTY_LOW_BIT_AMBIENT, false);

        log("onPropertiesChanged: LowBitAmbient=" + mLowBitAmbient);
    }

    @Override
    public void onTimeTick() {
        super.onTimeTick();
        log("TimeTick");
        invalidate();
        requireWeatherInfo();
    }

    @Override
    public void onVisibilityChanged(boolean visible) {
        super.onVisibilityChanged(visible);
        log("onVisibilityChanged: " + visible);

        if (visible) {
            mGoogleApiClient.connect();
            registerTimeZoneService();

            // Update time zone in case it changed while we weren't visible.
            mTime.clear(TimeZone.getDefault().getID());
            mTime.setToNow();
        } else {
            if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
                Wearable.DataApi.removeListener(mGoogleApiClient, this);
                Wearable.NodeApi.removeListener(mGoogleApiClient, this);
                mGoogleApiClient.disconnect();
            }

            unregisterTimeZoneService();
        }

        // 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();
    }

    protected Paint createTextPaint(int color, Typeface typeface) {
        Paint paint = new Paint();
        paint.setColor(color);
        if (typeface != null)
            paint.setTypeface(typeface);
        paint.setAntiAlias(true);
        return paint;
    }

    protected boolean shouldUpdateTimerBeRunning() {
        return isVisible() && !isInAmbientMode();
    }

    protected void fetchConfig(DataMap config) {
        if (config.containsKey(Consts.KEY_WEATHER_UPDATE_TIME)) {
            mWeatherInfoReceivedTime = config.getLong(Consts.KEY_WEATHER_UPDATE_TIME);
        }

        if (config.containsKey(Consts.KEY_WEATHER_CONDITION)) {
            String cond = config.getString(Consts.KEY_WEATHER_CONDITION);
            if (TextUtils.isEmpty(cond)) {
                mWeatherCondition = null;
            } else {
                mWeatherCondition = cond;
            }
        }

        if (config.containsKey(Consts.KEY_WEATHER_TEMPERATURE)) {
            mTemperature = config.getInt(Consts.KEY_WEATHER_TEMPERATURE);
            if (mTemperatureScale != ConverterUtil.FAHRENHEIT) {
                mTemperature = ConverterUtil.convertFahrenheitToCelsius(mTemperature);
            }
        }

        if (config.containsKey(Consts.KEY_WEATHER_SUNRISE)) {
            mSunriseTime.set(config.getLong(Consts.KEY_WEATHER_SUNRISE) * 1000);
            log("SunriseTime: " + mSunriseTime);
        }

        if (config.containsKey(Consts.KEY_WEATHER_SUNSET)) {
            mSunsetTime.set(config.getLong(Consts.KEY_WEATHER_SUNSET) * 1000);
            log("SunsetTime: " + mSunsetTime);
        }

        if (config.containsKey(Consts.KEY_CONFIG_TEMPERATURE_SCALE)) {
            int scale = config.getInt(Consts.KEY_CONFIG_TEMPERATURE_SCALE);

            if (scale != mTemperatureScale) {
                if (scale == ConverterUtil.FAHRENHEIT) {
                    mTemperature = ConverterUtil.convertCelsiusToFahrenheit(mTemperature);
                } else {
                    mTemperature = ConverterUtil.convertFahrenheitToCelsius(mTemperature);
                }
            }

            mTemperatureScale = scale;
        }

        if (config.containsKey(Consts.KEY_CONFIG_THEME)) {
            mTheme = config.getInt(Consts.KEY_CONFIG_THEME);
        }

        if (config.containsKey(Consts.KEY_CONFIG_TIME_UNIT)) {
            mTimeUnit = config.getInt(Consts.KEY_CONFIG_TIME_UNIT);
        }

        if (config.containsKey(Consts.KEY_CONFIG_REQUIRE_INTERVAL)) {
            mRequireInterval = config.getInt(Consts.KEY_CONFIG_REQUIRE_INTERVAL);
        }

        invalidate();
    }

    protected void getConfig() {
        log("Start getting Config");
        Wearable.NodeApi.getLocalNode(mGoogleApiClient).setResultCallback(new ResultCallback<NodeApi.GetLocalNodeResult>() {
            @Override
            public void onResult(NodeApi.GetLocalNodeResult getLocalNodeResult) {
                Uri uri = new Uri.Builder()
                        .scheme("wear")
                        .path(Consts.PATH_CONFIG + mName)
                        .authority(getLocalNodeResult.getNode().getId())
                        .build();

                getConfig(uri);

                uri = new Uri.Builder()
                        .scheme("wear")
                        .path(Consts.PATH_WEATHER_INFO)
                        .authority(getLocalNodeResult.getNode().getId())
                        .build();

                getConfig(uri);
            }
        });
    }

    protected void getConfig(Uri uri) {

        Wearable.DataApi.getDataItem(mGoogleApiClient, uri)
                .setResultCallback(
                        new ResultCallback<DataApi.DataItemResult>() {
                            @Override
                            public void onResult(DataApi.DataItemResult dataItemResult) {
                                log("Finish Config: " + dataItemResult.getStatus());
                                if (dataItemResult.getStatus().isSuccess() && dataItemResult.getDataItem() != null) {
                                    fetchConfig(DataMapItem.fromDataItem(dataItemResult.getDataItem()).getDataMap());
                                }
                            }
                        }
                );
    }

    protected void log(String message) {
        Log.d(WeatherWatchFaceService.this.getClass().getSimpleName(), message);
    }

    protected void registerTimeZoneService() {
        //TimeZone
        if (mRegisteredService) {
            return;
        }

        mRegisteredService = true;

        // TimeZone
        IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
        WeatherWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter);
    }

    protected void requireWeatherInfo() {
        if (!mGoogleApiClient.isConnected())
            return;

        long timeMs = System.currentTimeMillis();

        // The weather info is still up to date.
        if ((timeMs - mWeatherInfoReceivedTime) <= mRequireInterval)
            return;

        // Try once in a min.
        if ((timeMs - mWeatherInfoRequiredTime) <= DateUtils.MINUTE_IN_MILLIS)
            return;

        mWeatherInfoRequiredTime = timeMs;
        Wearable.MessageApi.sendMessage(mGoogleApiClient, "", Consts.PATH_WEATHER_REQUIRE, null)
                .setResultCallback(new ResultCallback<MessageApi.SendMessageResult>() {
                    @Override
                    public void onResult(MessageApi.SendMessageResult sendMessageResult) {
                        log("SendRequireMessage:" + sendMessageResult.getStatus());
                    }
                });
    }

    protected void unregisterTimeZoneService() {
        if (!mRegisteredService) {
            return;
        }
        mRegisteredService = false;

        //TimeZone
        WeatherWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver);
    }

    protected void updateTimer() {
        mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
        if (shouldUpdateTimerBeRunning()) {
            mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
        }
    }
}

}

任何帮助都会非常感激:)(这也是我第一次实时制作表盘,所以请原谅我)

1 个答案:

答案 0 :(得分:0)

默认构造函数接受零参数。 WeatherWatchFaceEngine中只有一个参数构造函数。

将零参数构造函数添加到WeatherWatchFaceEngine,其签名将为public WeatherWatchFaceEngine(){...}

相关问题