如何在从服务呼叫接收异步数据时更新Google Glass菜单

时间:2015-01-20 23:37:19

标签: android android-asynctask google-glass

以下是我的设置。 我有一个livecard服务类,它执行异步任务以从外部获取天气和天气预报数据。 它还启动了一个Pendingintent,其中两个菜单项是“ShowForecast”& “停止”

天气数据到达时会显示在主屏幕上。 但是预测数据需要更长的时间。我想隐藏ShowForecast菜单,直到异步任务成功完成。

实现此目的的最佳方法是什么?我已经阅读了有关全局变量的内容,或者通过intent.putextra或直接更新卡片菜单。 我现在想的是在我的activity类中使用一个boolean值,该值在onPrepareOptionsMenu中被检入并隐藏/显示菜单。

但是,当异步任务完成时,如何从Service类设置此布尔值? 以下是课程片段。所有建议欢迎! :)

public class LiveCardMenuActivity extends Activity {

private static final String TAG = LiveCardMenuActivity.class.getSimpleName();
// default disabled menu
private boolean menu_showForecast = false;

@Override
// in this method we hide/ show forecast menu, depending if the service has gotten the data
public boolean onPrepareOptionsMenu(Menu menu) {
    if(!menu_showForecast) {
        menu.findItem(R.id.action_show_forecast).setVisible(false);
    }
    return super.onPrepareOptionsMenu(menu);

...

是具有异步任务的服务类

public class LiveCardService extends Service {

private static final String TAG = LiveCardService.class.getSimpleName();

private static final String LIVE_CARD_TAG = "LiveCardService";
private LiveCard mLiveCard;
private RemoteViews mLiveCardView;

private final Handler mHandler = new Handler();
private final UpdateLiveCardRunnable mUpdateLiveCardRunnable = new UpdateLiveCardRunnable();
private static final long DELAY_MILLIS = 1000;

// keep the weather info central, due to reuse and forecast cards
private Weather weather = new Weather();
private WeatherForecast weatherForecast = new WeatherForecast();

@Override
public IBinder onBind(Intent intent) {
    return null;
}

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

    // and get the weather data & icon, async call
    String loc = "id=2755420";
    JSONWeatherTask task = new JSONWeatherTask();
    task.execute(new String[]{loc});

    // including the weather forecast
    JSONWeatherForecastTask taskForecast = new JSONWeatherForecastTask();
    taskForecast.execute(new String[]{loc});
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (mLiveCard == null) {
        // Get an instance of a live card
        mLiveCard = new LiveCard(this, LIVE_CARD_TAG);

        // setup live card views
        mLiveCardView = new RemoteViews(getPackageName(), R.layout.live_card);
        mLiveCard.setViews(mLiveCardView);

        // Display the options menu when the live card is tapped.
        Intent menuIntent = new Intent(this, LiveCardMenuActivity.class);
        mLiveCard.setAction(PendingIntent.getActivity(this, 0, menuIntent, 0));
        mLiveCard.publish(PublishMode.REVEAL);

        // Queue the update text runnable
        mHandler.post(mUpdateLiveCardRunnable);
    } else {
        mLiveCard.navigate();
    }
    return START_STICKY;
}

...

private class JSONWeatherForecastTask extends AsyncTask<String, Void, WeatherForecast> {

    @Override
    protected WeatherForecast doInBackground(String... params) {
        //
        String data = ( (new WeatherHttpClient()).getWeatherForecastData(params[0]));

        try {
            weatherForecast = JSONWeatherForecastParser.getWeatherForecast(data);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return weatherForecast;
    }

    @Override
    protected void onPostExecute(WeatherForecast weatherForecast) {
        super.onPostExecute(weatherForecast);


        // there is no showing of data yet, except voor enabling the forecast menu
        Weather[] weatherForecastArray = weatherForecast.getWeatherForecastArray();
        int count = weatherForecastArray.length;
        if(count > 0){
            //mLiveCard menu update or boolean update?
        }
    }

}

1 个答案:

答案 0 :(得分:1)

Timer sample的菜单Activity有一些逻辑可根据正在运行的计时器状态动态更改其选项菜单:

  1. MenuActivity&#39; onCreate回调中:绑定到TimerService
  2. 绑定Service后,检索有关当前Timer
  3. 的信息
  4. 一旦满足所有状态(Activity已附加到Window,已检索到计时器信息):打开选项菜单。
  5. 以下是MenuActivity类的代码片段:

    /**
     * This activity manages the options menu that appears when the user taps on the timer's live
     * card or says "ok glass" while the live card is settled.
     */
    public class MenuActivity extends Activity {
    
        private Timer mTimer;
        private boolean mAttachedToWindow;
        private boolean mIsMenuClosed;
        private boolean mPreparePanelCalled;
        private boolean mIsSettingTimer;
    
        private boolean mFromLiveCardVoice;
    
        private ServiceConnection mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                if (service instanceof TimerService.TimerBinder) {
                    mTimer = ((TimerService.TimerBinder) service).getTimer();
                    openMenu();
                }
                // No need to keep the service bound.
                unbindService(this);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                // Nothing to do here.
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            mFromLiveCardVoice = getIntent().getBooleanExtra(LiveCard.EXTRA_FROM_LIVECARD_VOICE, false);
            if (mFromLiveCardVoice) {
                // When activated by voice from a live card, enable voice commands. The menu
                // will automatically "jump" ahead to the items (skipping the guard phrase
                // that was already said at the live card).
                getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS);
            }
    
            // Bind to the Timer service to retrive the current timer's data.
            Intent serviceIntent = new Intent(this, TimerService.class);
            serviceIntent.putExtra(
                TimerService.EXTRA_TIMER_HASH_CODE,
                getIntent().getIntExtra(TimerService.EXTRA_TIMER_HASH_CODE, 0));
            serviceIntent.setData(getIntent().getData());
            bindService(serviceIntent, mConnection, 0);
        }
    
        @Override
        public void onAttachedToWindow() {
            super.onAttachedToWindow();
            mAttachedToWindow = true;
            openMenu();
        }
    
        @Override
        public void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            mAttachedToWindow = false;
        }
    
        @Override
        public boolean onCreatePanelMenu(int featureId, Menu menu) {
            if (isMyMenu(featureId)) {
                getMenuInflater().inflate(R.menu.timer, menu);
                return true;
            }
            return super.onCreatePanelMenu(featureId, menu);
        }
    
        @Override
        public boolean onPreparePanel(int featureId, View view, Menu menu) {
            mPreparePanelCalled = true;
            if (isMyMenu(featureId)) {
                if (mTimer == null) {
                    // Can't prepare the menu as we're not yet bound to a timer.
                    return false;
                } else {
                    // Disable or enable menu item depending on the Timer's state.
    
                    // Don't reopen menu once we are finishing. This is necessary
                    // since voice menus reopen themselves while in focus.
                    return !mIsMenuClosed;
                }
            }
            return super.onPreparePanel(featureId, view, menu);
        }
    
        @Override
        public boolean onMenuItemSelected(int featureId, MenuItem item) {
            if (!isMyMenu(featureId)) {
                return super.onMenuItemSelected(featureId, item);
            }
            // Handle item selection.
        }
    
        @Override
        public void onPanelClosed(int featureId, Menu menu) {
            super.onPanelClosed(featureId, menu);
            if (isMyMenu(featureId)) {
                mIsMenuClosed = true;
                if (!mIsSettingTimer) {
                    // Nothing else to do, closing the Activity.
                    finish();
                }
            }
        }
    
        /**
         * Opens the touch or voice menu iff all the conditions are satifisfied.
         */
        private void openMenu() {
            if (mAttachedToWindow && mTimer != null) {
                if (mFromLiveCardVoice) {
                    if (mPreparePanelCalled) {
                        // Invalidates the previously prepared voice menu now that we can properly
                        // prepare it.
                        getWindow().invalidatePanelMenu(WindowUtils.FEATURE_VOICE_COMMANDS);
                    }
                } else {
                    // Open the options menu for the touch flow.
                    openOptionsMenu();
                }
            }
        }
    
        /**
         * Returns {@code true} when the {@code featureId} belongs to the options menu or voice
         * menu that are controlled by this menu activity.
         */
        private boolean isMyMenu(int featureId) {
            return featureId == Window.FEATURE_OPTIONS_PANEL ||
                   featureId == WindowUtils.FEATURE_VOICE_COMMANDS;
        }
    }