/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.widget;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

import com.android.internal.widget.IRemoteViewsFactory;

import java.util.HashMap;

The service to be connected to for a remote adapter to request RemoteViews. Users should extend the RemoteViewsService to provide the appropriate RemoteViewsFactory's used to populate the remote collection view (ListView, GridView, etc).
/** * The service to be connected to for a remote adapter to request RemoteViews. Users should * extend the RemoteViewsService to provide the appropriate RemoteViewsFactory's used to * populate the remote collection view (ListView, GridView, etc). */
public abstract class RemoteViewsService extends Service { private static final String LOG_TAG = "RemoteViewsService"; // Used for reference counting of RemoteViewsFactories // Because we are now unbinding when we are not using the Service (to allow them to be // reclaimed), the references to the factories that are created need to be stored and used when // the service is restarted (in response to user input for example). When the process is // destroyed, so is this static cache of RemoteViewsFactories. private static final HashMap<Intent.FilterComparison, RemoteViewsFactory> sRemoteViewFactories = new HashMap<Intent.FilterComparison, RemoteViewsFactory>(); private static final Object sLock = new Object();
An interface for an adapter between a remote collection view (ListView, GridView, etc) and the underlying data for that view. The implementor is responsible for making a RemoteView for each item in the data set. This interface is a thin wrapper around Adapter.
See Also:
/** * An interface for an adapter between a remote collection view (ListView, GridView, etc) and * the underlying data for that view. The implementor is responsible for making a RemoteView * for each item in the data set. This interface is a thin wrapper around {@link Adapter}. * * @see android.widget.Adapter * @see android.appwidget.AppWidgetManager */
public interface RemoteViewsFactory {
Called when your factory is first constructed. The same factory may be shared across multiple RemoteViewAdapters depending on the intent passed.
/** * Called when your factory is first constructed. The same factory may be shared across * multiple RemoteViewAdapters depending on the intent passed. */
public void onCreate();
Called when notifyDataSetChanged() is triggered on the remote adapter. This allows a RemoteViewsFactory to respond to data changes by updating any internal references. Note: expensive tasks can be safely performed synchronously within this method. In the interim, the old data will be displayed within the widget.
See Also:
  • notifyAppWidgetViewDataChanged.notifyAppWidgetViewDataChanged(int[], int)
/** * Called when notifyDataSetChanged() is triggered on the remote adapter. This allows a * RemoteViewsFactory to respond to data changes by updating any internal references. * * Note: expensive tasks can be safely performed synchronously within this method. In the * interim, the old data will be displayed within the widget. * * @see android.appwidget.AppWidgetManager#notifyAppWidgetViewDataChanged(int[], int) */
public void onDataSetChanged();
Called when the last RemoteViewsAdapter that is associated with this factory is unbound.
/** * Called when the last RemoteViewsAdapter that is associated with this factory is * unbound. */
public void onDestroy();
Returns:Count of items.
/** * See {@link Adapter#getCount()} * * @return Count of items. */
public int getCount();
See Adapter.getView(int, View, ViewGroup). Note: expensive tasks can be safely performed synchronously within this method, and a loading view will be displayed in the interim. See getLoadingView().
Params:
  • position – The position of the item within the Factory's data set of the item whose view we want.
Returns:A RemoteViews object corresponding to the data at the specified position.
/** * See {@link Adapter#getView(int, android.view.View, android.view.ViewGroup)}. * * Note: expensive tasks can be safely performed synchronously within this method, and a * loading view will be displayed in the interim. See {@link #getLoadingView()}. * * @param position The position of the item within the Factory's data set of the item whose * view we want. * @return A RemoteViews object corresponding to the data at the specified position. */
public RemoteViews getViewAt(int position);
This allows for the use of a custom loading view which appears between the time that getViewAt(int) is called and returns. If null is returned, a default loading view will be used.
Returns:The RemoteViews representing the desired loading view.
/** * This allows for the use of a custom loading view which appears between the time that * {@link #getViewAt(int)} is called and returns. If null is returned, a default loading * view will be used. * * @return The RemoteViews representing the desired loading view. */
public RemoteViews getLoadingView();
Returns:The number of types of Views that will be returned by this factory.
/** * See {@link Adapter#getViewTypeCount()}. * * @return The number of types of Views that will be returned by this factory. */
public int getViewTypeCount();
Params:
  • position – The position of the item within the data set whose row id we want.
Returns:The id of the item at the specified position.
/** * See {@link Adapter#getItemId(int)}. * * @param position The position of the item within the data set whose row id we want. * @return The id of the item at the specified position. */
public long getItemId(int position);
Returns:True if the same id always refers to the same object.
/** * See {@link Adapter#hasStableIds()}. * * @return True if the same id always refers to the same object. */
public boolean hasStableIds(); }
A private proxy class for the private IRemoteViewsFactory interface through the public RemoteViewsFactory interface.
/** * A private proxy class for the private IRemoteViewsFactory interface through the * public RemoteViewsFactory interface. */
private static class RemoteViewsFactoryAdapter extends IRemoteViewsFactory.Stub { public RemoteViewsFactoryAdapter(RemoteViewsFactory factory, boolean isCreated) { mFactory = factory; mIsCreated = isCreated; } public synchronized boolean isCreated() { return mIsCreated; } public synchronized void onDataSetChanged() { try { mFactory.onDataSetChanged(); } catch (Exception ex) { Thread t = Thread.currentThread(); Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); } } public synchronized void onDataSetChangedAsync() { onDataSetChanged(); } public synchronized int getCount() { int count = 0; try { count = mFactory.getCount(); } catch (Exception ex) { Thread t = Thread.currentThread(); Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); } return count; } public synchronized RemoteViews getViewAt(int position) { RemoteViews rv = null; try { rv = mFactory.getViewAt(position); if (rv != null) { rv.setIsWidgetCollectionChild(true); } } catch (Exception ex) { Thread t = Thread.currentThread(); Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); } return rv; } public synchronized RemoteViews getLoadingView() { RemoteViews rv = null; try { rv = mFactory.getLoadingView(); } catch (Exception ex) { Thread t = Thread.currentThread(); Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); } return rv; } public synchronized int getViewTypeCount() { int count = 0; try { count = mFactory.getViewTypeCount(); } catch (Exception ex) { Thread t = Thread.currentThread(); Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); } return count; } public synchronized long getItemId(int position) { long id = 0; try { id = mFactory.getItemId(position); } catch (Exception ex) { Thread t = Thread.currentThread(); Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); } return id; } public synchronized boolean hasStableIds() { boolean hasStableIds = false; try { hasStableIds = mFactory.hasStableIds(); } catch (Exception ex) { Thread t = Thread.currentThread(); Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); } return hasStableIds; } public void onDestroy(Intent intent) { synchronized (sLock) { Intent.FilterComparison fc = new Intent.FilterComparison(intent); if (RemoteViewsService.sRemoteViewFactories.containsKey(fc)) { RemoteViewsFactory factory = RemoteViewsService.sRemoteViewFactories.get(fc); try { factory.onDestroy(); } catch (Exception ex) { Thread t = Thread.currentThread(); Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex); } RemoteViewsService.sRemoteViewFactories.remove(fc); } } } private RemoteViewsFactory mFactory; private boolean mIsCreated; } @Override public IBinder onBind(Intent intent) { synchronized (sLock) { Intent.FilterComparison fc = new Intent.FilterComparison(intent); RemoteViewsFactory factory = null; boolean isCreated = false; if (!sRemoteViewFactories.containsKey(fc)) { factory = onGetViewFactory(intent); sRemoteViewFactories.put(fc, factory); factory.onCreate(); isCreated = false; } else { factory = sRemoteViewFactories.get(fc); isCreated = true; } return new RemoteViewsFactoryAdapter(factory, isCreated); } }
To be implemented by the derived service to generate appropriate factories for the data.
/** * To be implemented by the derived service to generate appropriate factories for * the data. */
public abstract RemoteViewsFactory onGetViewFactory(Intent intent); }