android开发之widget的研究(OPWidget关于海贼王的小插件)(下)

2 篇文章 0 订阅
2 篇文章 0 订阅

接着上篇继续写:

⑤为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=


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值