几年前我开发了一个小部件。该小部件完美地工作到现在。它在Android 5.1.1设备中运行不正常,但它在Android 4.4及更低版本中运行良好。窗口小部件显示操作系统给出的三个数值。这些值是正确获取的,因为我可以在测试应用程序中在此小部件之外显示它们,并且它们在该测试非小部件应用程序中得到更新。
在android 5.1.1中,小部件菜单中没有显示图标,它显示默认的android图标。此外,小部件没有更新!我不知道出了什么问题。我需要一个必须在4.1,4.4和5.1设备上运行的小部件。
必须实施的Android 5.1.1小部件有什么变化吗?我在文档中找不到任何不同的内容
这是我的小部件:
清单:
<receiver android:name="com.myapp.CPUWidgetProvider" android:label="@string/app_name" android:icon="@drawable/icon128">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action android:name="AUTO_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_provider" />
</receiver>
<service android:name="com.myapp.UpdateService"/>
我的widget_provider.xml文件:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="40dp"
android:minHeight="40dp"
android:initialLayout="@layout/widget_layout"
android:updatePeriodMillis="0"
/>
我的widget_layout.xml文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fondo"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/widget_background"
android:paddingLeft="1dp"
android:paddingRight="1dp"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/freq"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/loading"
android:textSize="12sp"
android:textColor="#EE08B608"
android:layout_weight="1"/>
<TextView
android:id="@+id/usage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="..."
android:textSize="12sp"
android:textColor="#EE08B608"
android:layout_weight="1"/>
<TextView
android:id="@+id/temp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="27ºC 80ºF"
android:textSize="11sp"
android:textColor="#EE08B608"
android:layout_weight="1"/>
</LinearLayout>
我的小部件闹钟:
public class WidgetAlarm{
private final int ALARM_ID = 0;
private final int INTERVAL_MILLIS = 5000;
private Context mContext;
public WidgetAlarm(Context context){
mContext = context;
}
public void startAlarm(){
Intent alarmIntent = new Intent(CPUWidgetProvider.ACTION_AUTO_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), INTERVAL_MILLIS, pendingIntent); // RTC does not wake the device up
}
public void stopAlarm(){
Intent alarmIntent = new Intent(CPUWidgetProvider.ACTION_AUTO_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
}
我的更新服务:
public class UpdateService extends Service implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mTempSensor;
double auxBatteryTemp;
String systemTemp=null;
String systemTempFarenheit=null;
String batteryTemp="25";
String batteryTempFarenheit="80";
int processorMaxFreq=-1;
DecimalFormatSymbols symbols;
DecimalFormat tempDecimalFormat;
boolean serviceDestroyed=false;
Context ctx;
PowerManager pm;
RemoteViews remoteViews;
ComponentName thisWidget;
private BroadcastReceiver mBatInfoReceiver; //Broadcast receiver for the battery temperature
private BroadcastReceiver screenoffReceiver; //Broadcast receiver for stop the alarm when the screen is off
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//System.out.println("XXXXX SERVICE START COMMAND");
/* receivers */
mBatInfoReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context arg0, Intent intent) {
try {
auxBatteryTemp = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
batteryTemp = ""+(int) (auxBatteryTemp / 10);
auxBatteryTemp=auxBatteryTemp/10;
batteryTempFarenheit = ""+(int)(((auxBatteryTemp*((float)9/5))+32));
updateTemperatures();
} catch (Exception e) {e.printStackTrace();}
}
};
screenoffReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
WidgetAlarm widgetAlarm = new WidgetAlarm(context.getApplicationContext());
widgetAlarm.stopAlarm();
}
else if(intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
WidgetAlarm widgetAlarm = new WidgetAlarm(context.getApplicationContext());
widgetAlarm.startAlarm();
}
return;
}
};
symbols = new DecimalFormatSymbols(Locale.GERMAN);
symbols.setDecimalSeparator('.');
tempDecimalFormat = new DecimalFormat("#.#", symbols);
this.ctx = this;
pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
remoteViews = new RemoteViews(ctx.getPackageName(), R.layout.widget_layout);
thisWidget = new ComponentName( ctx, CPUWidgetProvider.class );
//Temperature sensors
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
if (Build.VERSION.SDK_INT >= 14)
mTempSensor = mSensorManager.getDefaultSensor(13); //13 = Sensor.TYPE_AMBIENT_TEMPERATURE //this constant required Android 4.0
else
mTempSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
mSensorManager.registerListener(this, mTempSensor, SensorManager.SENSOR_DELAY_FASTEST);
//adding receivers
registerReceiver(this.mBatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(screenoffReceiver, filter);
//return super.onStartCommand(intent, flags, startId);
return Service.START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
try {
mSensorManager.unregisterListener(this);
unregisterReceiver(this.mBatInfoReceiver);
unregisterReceiver(this.screenoffReceiver);
serviceDestroyed=true;
} catch (Exception e) {e.printStackTrace();}
//System.out.println("XXXXX SERVICE DESTROY");
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
@Override
public void onSensorChanged(SensorEvent event) {
if (Build.VERSION.SDK_INT >= 14){
if (event.sensor.getType() == 13) { //13 = Sensor.TYPE_AMBIENT_TEMPERATURE //this constant required Android 4.0
getTemperature(event);
}
}else{
if (event.sensor.getType() == Sensor.TYPE_TEMPERATURE) {
getTemperature(event);
}
}
}
public void getTemperature(SensorEvent event){
float values[] = event.values;
if (values.length>0){
systemTemp = ""+(int)values[0];
systemTempFarenheit = ""+(int)((values[0]*((float)9/5))+32);
updateTemperatures();
}
}
public void updateTemperatures(){
if (pm.isScreenOn() && serviceDestroyed==false){
//si hemos podido obtener la temperatura del sistema, la mostramos, si no, mostramos la temperatura de la bateria.
if (systemTemp!=null){
remoteViews.setTextViewText(R.id.temp,systemTemp+"ºC"+" "+systemTempFarenheit+"ºF");
}
else{
remoteViews.setTextViewText(R.id.temp,batteryTemp+"ºC"+" "+batteryTempFarenheit+"ºF");
}
AppWidgetManager.getInstance( ctx).updateAppWidget( thisWidget, remoteViews );
//System.out.println("XXXXX SERVICE UPDATE TEMPERATURES");
}
}
}
我的应用小工具提供商:
public class CPUWidgetProvider extends AppWidgetProvider{
public static final String ACTION_WIDGET_CLICK = "ActionWidgetClick";
public static final String ACTION_AUTO_UPDATE = "AUTO_UPDATE";
DecimalFormatSymbols symbols;
DecimalFormat tempDecimalFormat;
int processorMaxFreq=-1;
String cpuCurrentFreq=null;
int freq = 0;
float usage =-1;
BufferedReader freqBufferedReader;
PowerManager pm;
RemoteViews remoteViews;
ComponentName thisWidget;
WidgetAlarm widgetAlarm;
ActivityManager manager;
Intent active;
PendingIntent actionPendingIntent;
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
context.stopService(new Intent(context, UpdateService.class));
//stop alarm
widgetAlarm = new WidgetAlarm(context.getApplicationContext());
widgetAlarm.stopAlarm();
//System.out.println("XXXXX onDISABLED");
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
//System.out.println("XXXXX onDELETED");
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
//System.out.println("XXXXX onENABLED");
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
if (isMyServiceRunning(context)==false){
context.startService(new Intent(context, UpdateService.class));
}
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
thisWidget = new ComponentName(context, CPUWidgetProvider.class );
//preparamos el evento para cuando el usuario presiona en el widget, ese evento será recibido en onReceive()
active = new Intent(context, CPUWidgetProvider.class);
active.setAction(ACTION_WIDGET_CLICK);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.fondo, actionPendingIntent);
AppWidgetManager.getInstance(context).updateAppWidget( thisWidget, remoteViews );
// start alarm
widgetAlarm = new WidgetAlarm(context.getApplicationContext());
widgetAlarm.startAlarm();
//System.out.println("XXXXX onUPDATE");
}
@Override
public void onReceive(Context context, Intent intent){
if (intent.getAction().equals(ACTION_WIDGET_CLICK)){
switchWidget(context);
}else if(intent.getAction().equals(ACTION_AUTO_UPDATE)){
symbols = new DecimalFormatSymbols(Locale.GERMAN);
symbols.setDecimalSeparator('.');
tempDecimalFormat = new DecimalFormat("#.#", symbols);
pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
thisWidget = new ComponentName(context, CPUWidgetProvider.class );
if (pm.isScreenOn()){
try{
freqBufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"))));
freq = Integer.valueOf(freqBufferedReader.readLine()).intValue();
freqBufferedReader.close();
freqBufferedReader = null;
cpuCurrentFreq=freq / 1000 + " Mhz";
}
catch (Exception Exception){
cpuCurrentFreq=null;
}
remoteViews.setTextViewText(R.id.freq,cpuCurrentFreq);
if (processorMaxFreq==-1)
getProcessorMaxFreq();
usage=(float) (freq/processorMaxFreq);
remoteViews.setTextViewText(R.id.usage,tempDecimalFormat.format(usage / 10.0D)+" %");
//preparamos el evento para cuando el usuario presiona en el widget, ese evento será recibido en onReceive()
active = new Intent(context, CPUWidgetProvider.class);
active.setAction(ACTION_WIDGET_CLICK);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.fondo, actionPendingIntent);
AppWidgetManager.getInstance(context).updateAppWidget( thisWidget, remoteViews );
//System.out.println("XXXXX UPDATING WIDGET");
}
}else{
super.onReceive(context, intent);
}
//System.out.println("XXXXX onRECEIVE: "+intent.getAction());
}
public void switchWidget(Context context){
symbols = new DecimalFormatSymbols(Locale.GERMAN);
symbols.setDecimalSeparator('.');
tempDecimalFormat = new DecimalFormat("#.#", symbols);
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
thisWidget = new ComponentName(context.getPackageName(), CPUWidgetProvider.class.getName());
widgetAlarm = new WidgetAlarm(context.getApplicationContext());
if (isMyServiceRunning(context)==true){ //si el widget está encendido la apagamos
context.stopService(new Intent(context, UpdateService.class));
widgetAlarm.stopAlarm();
remoteViews.setTextViewText(R.id.freq,"");
remoteViews.setTextViewText(R.id.usage,"OFF");
remoteViews.setTextViewText(R.id.temp,"");
}
else{ //si el widget está apagado lo encendemos
context.startService(new Intent(context, UpdateService.class));
widgetAlarm.startAlarm();
remoteViews.setTextViewText(R.id.freq,"-----");
remoteViews.setTextViewText(R.id.usage,"--");
remoteViews.setTextViewText(R.id.temp,"");
}
AppWidgetManager.getInstance(context).updateAppWidget(thisWidget,remoteViews);
}
private boolean isMyServiceRunning(Context context) {
manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (UpdateService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
public void getProcessorMaxFreq(){
int freq = 0;
try{
freqBufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"))));
freq = Integer.valueOf(freqBufferedReader.readLine()).intValue();
freqBufferedReader.close();
freqBufferedReader=null;
processorMaxFreq=(freq / 1000);
}
catch (Exception e){e.printStackTrace();}
}
}
答案 0 :(得分:3)
每this blog post和associated bug closed as Working as Intended:
低轮询时间被四舍五入到60000毫秒(一分钟)
你会看到一条logcat消息:
可疑短距离5000毫米;扩展到60秒
当被问及替代方案时,post #9 on the bug说:
如果您尝试的运行频率超过每5秒钟一次,那么警报就是错误的方法。唤醒通常对电池寿命非常不利的设备。如果您有需要不断更新的实时UI,请使用唤醒锁,然后在处理程序上安排您的活动。与每秒设置闹钟相比,这实际上是更多电池效率。
请记住,小部件只是偶尔运行;操作系统将提供的最小updatePeriodMillis是30分钟。