接着上篇继续写:
⑤为widget写一个配置Activity,具体效果是:当用户将一个widget拉至桌面时,弹出一个Activity,提示用户选择相关的样式!
效果:
具体步骤:
创建一个SettingActivity:
package ace.widget.myopwidget;
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.Button;
import android.widget.RadioGroup;
import android.widget.RemoteViews;
public class SettingActivity extends Activity {
private int mAppWidgetId;
private RadioGroup radioGroup;
private Button btn_ok;
private int srcId; // 配置背景图片的id
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.setting);
setResult(RESULT_CANCELED);
// Find the widget id from the intent.
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
// If they gave us an intent without the widget id, just bail.
if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
}
findView();
setListener();
}
private void setRadiogGroup() {
int checkedId = radioGroup.getCheckedRadioButtonId();
System.out.println(checkedId);
switch (checkedId) {
case R.id.radiobutton_white:
srcId = R.drawable.white_bg; // 白色
break;
case R.id.radiobutton_red:
srcId = R.drawable.red_bg;
break;
case R.id.radiobutton_blue:
srcId = R.drawable.blue_bg;
break;
default:
break;
}
}
private void findView() {
radioGroup = (RadioGroup) findViewById(R.id.radiogroup);
btn_ok = (Button) findViewById(R.id.btn_OK);
}
private void setListener() {
btn_ok.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
setRadiogGroup();
RemoteViews views = new RemoteViews(SettingActivity.this
.getPackageName(), R.layout.main);
views.setImageViewResource(R.id.imageView_background, srcId);
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(SettingActivity.this);
appWidgetManager.updateAppWidget(mAppWidgetId, views);
// return OK
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
mAppWidgetId);
setResult(RESULT_OK, resultValue);
OPWidget widget = new OPWidget();
// 这里将延迟设为100ms是因为如果设为0,widget得不到即使的更新
// OPWidget.timers_hashMap.get(mAppWidgetId).schedule(
// widget.timerTask, 100, 1000);
finish();
}
});
}
}
设置setting的布局文件setting.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >
<RadioGroup
android:id="@+id/radiogroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<RadioButton
android:id="@+id/radiobutton_white"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:checked="true"
android:drawablePadding="20dp"
android:text="白色背景" />
<RadioButton
android:id="@+id/radiobutton_red"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:drawablePadding="20dp"
android:text="红色背景" />
<RadioButton
android:id="@+id/radiobutton_blue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:drawablePadding="20dp"
android:text="蓝色背景" />
</RadioGroup>
<Button
android:id="@+id/btn_OK"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="确定" />
</LinearLayout>
然后在res/xml目录下对
widget的描述文件添加android:configuration标签并将android:initialLayout标签修改,具体如下
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:configure="ace.widget.myopwidget.SettingActivity"
android:initialLayout="@layout/setting"
android:minHeight="142dip"
android:minWidth="142dip"
android:updatePeriodMillis="1000000" >
</appwidget-provider>
最后对Androidmanifest.xml文件进行添加 <activity />
<activity android:name=".SettingActivity" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
写到这里android中widget的研究就大致写完了。
下面写一些我实际操作中碰到的一些Bug以及相关的解决方法:
1.当我们同时向桌面拉取了多个widget时,点击任意一个widget通过DescActivity对widget的显示图片进行更新,所有的widget都更新了。
解决方法 :PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent,0);
将第四个参数设置为PendingIntent.FLAG_UPDATE_CURRENT
然而 此时新的bug出现了(很蛋疼= .=!!),在DescActivity中进行相关操作,发现只对最后拉取的那个widget造成了更新。
原因 :DescActivity中获取到的WidgetID都是最后面的那个widget的ID,也就说点击widget无法获取对应的widgetId。
解决 方法:对PendingIntent传递的intent对象设置一个Action即可!
★★★★★通过网上的一些帖子得知,在Android_developers_Google Group里很多人提到pendingIntent不是以里面的bundle的不同而不同,而是以绑定的intentAction的不同而不同。这样你点击不同的widget时,事件接收方才可以接收到对应的bundle。
2. 同时向桌面拉取2个wiget,发现只有最后面拉至桌面的widget的时间时间在更新!
原因:timertask执行时,无法获取对应的widget的id!
解决方法:在TimerTask的run方法里面,获取到timertask的名字( Thread.currentThread().getName()), 然后以timertask的名字为标识来记录每个wiget的id!
相关代码:
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+ "timer is running!" + mAppWidgetIds[0]);
if (widgetids_hashMap == null) {
widgetids_hashMap = new HashMap<String, int[]>();
}
String timerName = Thread.currentThread().getName();
if (!widgetids_hashMap.containsKey(timerName)) {
widgetids_hashMap.put(timerName, mAppWidgetIds);
}
Message msg = new Message();
msg.obj = timerName;
handler.sendMessage(msg);
}
};
在handler里面获取当前Timertask
对应的widgetid
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
String timerName = msg.obj.toString();
int[] appWidgetIdsTemp = widgetids_hashMap.get(timerName);
int n = appWidgetIdsTemp.length;
for (int i = 0; i < n; i++) {
int appWidgetId = appWidgetIdsTemp[i];
System.out.println(Thread.currentThread().getName() + "+"
+ "appWidgetId--->" + appWidgetId);
DateFormat df = new SimpleDateFormat("yyy.MM.dd/HH:mm:ss E");
mRemoteViews.setTextViewText(R.id.tv, df.format(new Date()));
mAppWidgetManager.updateAppWidget(appWidgetId, mRemoteViews);
}
}
};
3.每次计时器更新后,导致DescActivity中获取到的widgetID都为最后拉出的widget的id号!
原因:我将OPWidget的全局变量private RemoteViews mRemoteViews设为了静态变量,导致mRemoteViews指向的对象不断的变更,直至指向最后拉取的那个widget!
解决方案:取消该变量的static的设置。
4.整个OPwidget完成,在桌面运行一段时间后,widget上的时间不再更新!
原因:是timer的问题,timertask线程运行一段时间后自动关闭了!
今天查了相关线程的资料,了解如下:
守护线程与普通线程的唯一区别是:当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则不会退出。(以上是针对正常退出,调用System.exit则必定会退出)
所以我猜测是timertask是守护进程,而JVM不存在其他运行的普通线程,所以伴随着JVM的退出,timertask也就跟着关闭了!(不知道猜测是否正确o(∩_∩)o )
解决方法:将所有在timertask中的操作放在一个重写的Thread类里面即可!问题得到解决!
5.手机重启之后,widget无法正常工作!(暂未解决)
该wigdet完整版的下载地址:
http://www.eoeandroid.com/forum.php?mod=viewthread&tid=117709&extra=