Android主界面小控件,可以动态对App的状态进行更新。
1.首先在工程 Res目录下创建 xml文件夹,在文件夹下新建 appWidgetInfo.xml,在里面声明
AppWidgetProviderInfo的相关属
性
。
android:minWidth="180dp"
android:minHeight="180dp"
android:previewImage="@drawable/preview"
android:initialLayout="@layout/layout_widget"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen|keyguard"
android:updatePeriodMillis="0"
>
<!--
android:minWidth : 最小宽度
android:minHeight : 最小高度
android:updatePeriodMillis : 更新widget的时间间隔(ms),"0"表示应用主动更新
android:previewImage : 预览图片
android:initialLayout : 加载到桌面时对应的布局文件,即自己widget控件的布局
android:resizeMode : widget可以被拉伸的方向。horizontal表示可以水平拉伸,vertical表示可以竖直拉伸
android:widgetCategory : widget可以被显示的位置。home_screen表示可以将widget添加到桌面,keyguard表示widget可以被添加到锁屏界面。
android:initialKeyguardLayout : 加载到锁屏界面时对应的布局文件
-->
</appwidget-provider>
2.实现自己的AppWidgetProvider,widget的UI加载以及更新逻辑的实现。
以下代码实现 Music 的播放/暂停, 上一曲/下一曲功能,并动态更新当前的歌曲名。
public class WidgetProvider extends AppWidgetProvider {
private static final String TAG = "WidgetProvider";
public static final String PREV_ACTION = "com.yoke.music.prev";
public static final String NEXT_ACTION = "com.yoke.music.next";
public static final String MUTE_ACTION = "com.yoke.music
.play";
public static final String UPDATE_ACTION = "com.yoke.music.update";
@Override
public void onReceive(Context context, Intent intent) {
//处理绑定按钮的点击事件,通过接收到的按钮绑定的事件广播来进行相应的响应。
String action = intent.getAction();
Log.d(TAG, " App Widget Receive action=" + action);
if (action.equals(PREV_ACTION)) {
MusicService.prev();
} else if (action.equals(NEXT_ACTION)) {
MusicService.next();
} else if (action.equals(MUTE_ACTION)) {
boolean playOrPause = MusicService.getPlayOrPause();
if(playOrPause) {
MusicService.Play();
}else{
MusicService.Pause();
)
} else if (action.equals(UPDATE_ACTION)) {
String musicTitle = intent.getIntExtra("Music_Title_change", "Hello");
updateWidget(context, AppWidgetManager.getInstance(context),
musicTitle
,MusicSerivice.getPlayOrPause()
);
}
super.onReceive(context, intent);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Log.d(TAG, "update All widget");
updateWidget(context, appWidgetManager, "Hello World.mp3", false);
}
private void updateWidget(Context context,
AppWidgetManager appWidgetManager, String musicTitle, boolean mute) {
//以下使用 RemoteViews设置widget的布局和绑定点击事件。
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.bottom_widget);
if (freq != null) {
remoteViews.setTextViewText(R.id.music_title, musicTitle);
}
Intent prevIntent = new Intent().setAction(PREV_ACTION);
PendingIntent prevPendingIntent = PendingIntent.getBroadcast(context,
0, prevIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews
.setOnClickPendingIntent(R.id.prev_widget, prevPendingIntent);
// play or pause
Intent muteIntent = new Intent().setAction(MUTE_ACTION);
PendingIntent mutePendingIntent = PendingIntent.getBroadcast(context,
0, muteIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews
.setOnClickPendingIntent(R.id.mute_widget, mutePendingIntent);
// next
Intent nextIntent = new Intent().setAction(NEXT_ACTION);
PendingIntent nextPendingIntent = PendingIntent.getBroadcast(context,
0, nextIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews
.setOnClickPendingIntent(R.id.next_widget, nextPendingIntent);
//根据当前是play or pause来设置不同的按钮图标
if (mute) {
remoteViews.setImageViewResource(R.id.mute_widget,
R.drawable.music_play_selector);
} else {
remoteViews.setImageViewResource(R.id.mute_widget,
R.drawable.music_stop_selector);
}
// 更新widget UI
ComponentName componentName = new ComponentName(context,
WidgetProvider.class);
appWidgetManager.updateAppWidget(componentName, remoteViews);
}
}
3.实现功能控制的MusicService,并在MusicTitle改变时发送广播通知widget更新 MusicTitle
public class MusicService extends Service {
// 播放器
private MediaPlayer mMediaPlayer;
// 音频文件
private File audioFile;
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void play(){
}
public void pause(){
}
public boolean getPlayOrPause(){
return false;
}
public void prev(){
}
public void next(){
}
public void musicTitileChange(){
Intent intent = new Intent().setAction("Music_Title_change");
sendBoardcast(intent);
}
}
4. 在AndroidMainfest中注册AppProvider 和 MusicService
<receiver
android:name="com.adayo.radio.widget.WidgetProvider"
android:enabled="true"
android:exported="true"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.yoke.music.prev"/>
<action android:name="com.yoke.music.next"/>
<action android:name="com.yoke.music.mute"/>
<action android:name="com.yoke.music.update"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appWidgetInfo" />
</receiver>
<service
android:name="com.yoke.MusicService"/>
总结: App widget的实现原理 主要是通过 Boardcast机制来实现的,
使用Service和Widget进行业务逻辑的处理和UI交互的实时状态 更新。