小部件在Android 5.1中运行不佳,但在4.1,4.4等方面表现完善

时间:2015-07-05 20:31:29

标签: android widget android-widget android-appwidget appwidgetprovider

几年前我开发了一个小部件。该小部件完美地工作到现在。它在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();}
    }
}

1 个答案:

答案 0 :(得分:3)

this blog postassociated bug closed as Working as Intended

  

低轮询时间被四舍五入到60000毫秒(一分钟)

你会看到一条logcat消息:

  

可疑短距离5000毫米;扩展到60秒

当被问及替代方案时,post #9 on the bug说:

  

如果您尝试的运行频率超过每5秒钟一次,那么警报就是错误的方法。唤醒通常对电池寿命非常不利的设备。如果您有需要不断更新的实时UI,请使用唤醒锁,然后在处理程序上安排您的活动。与每秒设置闹钟相比,这实际上是更多电池效率。

     

请记住,小部件只是偶尔运行;操作系统将提供的最小updatePeriodMillis是30分钟。