标签:des android style blog http color os java io
AppWidget 通过内存共享进行数据通讯.原理图如下:
1.创建一个BroadcastReceiver,继承AppWidgetProvider.
2.在AndroidManifest.xml中配置如下:下面给出官网例子<action />是必须的.
<receiver android:name="ExampleAppWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/example_appwidget_info" />
</receiver>
3.提供一个<meta-data />标签里resource的xml文件,定义appwidget的样式属性(配置参数可选)
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="294dp"
android:minHeight="72dp"
android:updatePeriodMillis="86400000"
android:previewImage="@drawable/preview"
android:initialLayout="@layout/example_appwidget"
android:configure="com.example.android.ExampleAppWidgetConfigure"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen|keyguard"
android:initialKeyguardLayout="@layout/example_keyguard">
</appwidget-provider>4.定义appwidget的样式.定义一个layout文件做为布局文件 ,并配置在上面intialLayout属性中.
5.当用户点击选取添加某个小部件.首先获取appWidgetId,并打开一个选取小部件的Activity
6.选取后,通过appWidgetId获取appWidgetInfo,并转化为LauncherAppWidgetInfo对象,并添加到workspace中.
当然,这段时间包括了appwidget的定位.其添加源码如下:
private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) {
Bundle extras = data.getExtras();
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString());
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
// Calculate the grid spans needed to fit this widget
CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight);
// Try finding open space on Launcher screen
final int[] xy = mCellCoordinates;
if (!findSlot(cellInfo, xy, spans[0], spans[1])) {
if (appWidgetId != -1) mAppWidgetHost.deleteAppWidgetId(appWidgetId);
return;
}
// Build Launcher-specific widget info and save to database
LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId);
launcherInfo.spanX = spans[0];
launcherInfo.spanY = spans[1];
LauncherModel.addItemToDatabase(this, launcherInfo,
LauncherSettings.Favorites.CONTAINER_DESKTOP,
mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
if (!mRestoring) {
mDesktopItems.add(launcherInfo);
// Perform actual inflation because we're live
launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
launcherInfo.hostView.setTag(launcherInfo);
mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1],
launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
}
}总结:当我们执行完前3步,系统即会根据用户选择创建小部件.--更新AppWidget界面,其原理如下:
1AppWidgetManager发送广播传递ID.
void updateProvidersForPackageLocked(String pkgName) {
HashSet<String> keep = new HashSet<String>();
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.setPackage(pkgName);
List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
PackageManager.GET_META_DATA);
// add the missing ones and collect which ones to keep
int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
for (int i=0; i<N; i++) {
ResolveInfo ri = broadcastReceivers.get(i);
ActivityInfo ai = ri.activityInfo;
if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
continue;
}
if (pkgName.equals(ai.packageName)) {
ComponentName component = new ComponentName(ai.packageName, ai.name);
Provider p = lookupProviderLocked(component);
if (p == null) {
if (addProviderLocked(ri)) {
keep.add(ai.name);
}
} else {
Provider parsed = parseProviderInfoXml(component, ri);
if (parsed != null) {
keep.add(ai.name);
// Use the new AppWidgetProviderInfo.
p.info = parsed.info;
// If it's enabled
final int M = p.instances.size();
if (M > 0) {
int[] appWidgetIds = getAppWidgetIds(p);
// Reschedule for the new updatePeriodMillis (don't worry about handling
// it specially if updatePeriodMillis didn't change because we just sent
// an update, and the next one will be updatePeriodMillis from now).
cancelBroadcasts(p);
registerForBroadcastsLocked(p, appWidgetIds);
// If it's currently showing, call back with the new AppWidgetProviderInfo.
for (int j=0; j<M; j++) {
AppWidgetId id = p.instances.get(j);
id.views = null;
if (id.host != null && id.host.callbacks != null) {
try {
id.host.callbacks.providerChanged(id.appWidgetId, p.info);
} catch (RemoteException ex) {
// It failed; remove the callback. No need to prune because
// we know that this host is still referenced by this
// instance.
id.host.callbacks = null;
}
}
}
// Now that we've told the host, push out an update.
sendUpdateIntentLocked(p, appWidgetIds);
}
}
}
}
}
// prune the ones we don't want to keep
N = mInstalledProviders.size();
for (int i=N-1; i>=0; i--) {
Provider p = mInstalledProviders.get(i);
if (pkgName.equals(p.info.provider.getPackageName())
&& !keep.contains(p.info.provider.getClassName())) {
removeProviderLocked(i, p);
}
}
}
2.用户自定义AppwidgetProvider的onUpdate()接收数据.并通过Manager更新界面.(如下,官网给出了2个操作,1更新界面 2.点击小部件操作)
public class ExampleAppWidgetProvider extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
// Perform this loop procedure for each App Widget that belongs to this provider
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
// Create an Intent to launch ExampleActivity
Intent intent = new Intent(context, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
// Get the layout for the App Widget and attach an on-click listener
// to the button
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
// Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}--Updating the App Widget from the configuration Activity(通过配置选项更改APPwidget界面,当Appwidget创建时,先进入该Activity进行判断)
1.创建Activity并在AndroidManifest.xml里面配置:
<activity android:name="org.lean.ConfigureActivity" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>2.在appwidget的配置xml里面增加属性:
android:configure="org.lean.ConfigureActivity"
package org.lean;
import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.RemoteViews;
/**
*
*
* @author Lean @date:2014-8-27
*/
public class ConfigureActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.configure_view);
findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int appwidgetId=getIntent().getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);
if (appwidgetId!=AppWidgetManager.INVALID_APPWIDGET_ID) {
//修改远程界面
EditText editText=(EditText) findViewById(R.id.editText1);
String currenEtStr=editText.getText().toString();
RemoteViews views=new RemoteViews(ConfigureActivity.this.getPackageName(),
R.layout.layout_widget);
views.setTextViewText(R.id.btn,currenEtStr);
AppWidgetManager manager=AppWidgetManager.getInstance(ConfigureActivity.this);
manager.updateAppWidget(appwidgetId, views);
//返回activity
Intent reIntent=new Intent();
reIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appwidgetId);
setResult(RESULT_OK,reIntent);
finish();
}
}
});
}
}
Android-Launcher开发之AppWidget(2)
标签:des android style blog http color os java io
原文地址:http://blog.csdn.net/qq285016127/article/details/38849199