问题
I'm looking for make an AppWidget that check the battery status (level, charging/not charging).
I wrote a lot of codelines, but, even if it work perfectly, I see that put it on the screen make the telephone slower and, sometimes crash.
I think it's because I make something wrong. Can someone help me? Thank's
Here My Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="it.bisneff.widgetone"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="10" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<receiver android:name="MyWidgetProvider" >
<intent-filter >
<action
android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>
</application>
</manifest>
And here my main class:
package it.bisneff.widgetone;
import it.bisneff.widgetone.R;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.RemoteViews;
public class MyWidgetProvider extends AppWidgetProvider {
//Unused String
private static final String ACTION_CLICK = "ACTION_CLICK";
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
ComponentName thisWidget = new ComponentName(context,
MyWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
for (int widgetId : allWidgetIds) {
Intent batteryStatus =context.getApplicationContext().registerReceiver(this,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
//Battery Level
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
//Max Battery Level
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
// %
float batteryPct = level / (float)scale;
batteryPct=batteryPct*100;
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
//Charging or not
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
status == BatteryManager.BATTERY_STATUS_FULL;
//integer convertion
int batteryPctz=(int)batteryPct;
Log.w("WidgetExample", String.valueOf(batteryPctz)+"%");
//USB or AC charge
int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;
//update view
remoteViews.setTextViewText(R.id.update, String.valueOf(batteryPctz)+"%");
//select the image for the battery level
String res=new String();
res="it.bisneff.widgetone:drawable/battery";
if (batteryPct >= 90)
{ res+="6";
}
if (batteryPct >= 75 && batteryPct < 90)
{
res+="5";
}
if (batteryPct >= 60 && batteryPct < 75 )
{
res+="4";
}
if (batteryPct >= 35 && batteryPct < 60 )
{
res+="3";
}
if (batteryPct >= 15 && batteryPct < 35 )
{
res+="2";
}
if (batteryPct < 15 )
{
res+="1";
}
if(isCharging){
if(acCharge)
{
res+="cha";
}
if(usbCharge)
{
res+="usb";
}
if (batteryPctz==100){res="it.bisneff.widgetone:drawable/battery6full";}
}
//check the resource
int reso= context.getResources().getIdentifier(res, null, null);
//put the right image
remoteViews.setImageViewResource(R.id.imageView1, reso);
//Set Click Listener
Intent intent = new Intent(context, MyWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
//check received intent action
if( ((intent.getAction()).equals(Intent.ACTION_BATTERY_CHANGED)) || ((intent.getAction()).equals(Intent.ACTION_POWER_CONNECTED)) || ((intent.getAction()).equals(Intent.ACTION_POWER_DISCONNECTED))){
//get Bundle
Bundle extras = intent.getExtras();
//if extras
if(extras!=null) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName thisAppWidget = new ComponentName(context.getPackageName(), MyWidgetProvider.class.getName());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
//call the onUpdate
onUpdate(context, appWidgetManager, appWidgetIds);
}
}
}
}
EDIT:
I see where is the problem.
If I had
....
Intent batteryStatus =context.getApplicationContext().registerReceiver(this,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
context.getApplicationContext().unregisterReceiver(this);//this line
....
The widget stop to loop. But it stop to update on battery level changes...
I added
@Override
public void onEnabled(Context context){
context.getApplicationContext().registerReceiver(this, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
to be sure to register my receiver, but it won't work, and I cannot register it from XML cause documentation says it cannot be register there.
How can I do?
回答1:
Hello Valerio Bisneff Ponza,
You must be facing this exception:
android.content.ReceiverCallNotAllowedException: BroadcastReceiver components are not allowed to register to receive intents
Reason: This is because, you(Widget/ BroadCast Receiver) can not register itself with another Intent_Filter OR register another receiver, from within (Widget/ BroadCast Receiver)...
If you add in manifest, while registering Widget:
- action android:name="android.intent.action.BATTERY_CHANGED" OR
- action android:name="android.intent.action.ACTION_POWER_CONNECTED" OR
- action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" etc.
... most of the times your Widget won't respond.
Reason: Widget is associated with a process(pid) OR service, if run independently(activity/ service) not running, it shall not receive Intents.
WHAT to do THEN??
In On Enabled, start a service, explicitly for updating your widget, register your BroadCast receiver in onStart() of service and update Widget from Service.
NOTE: Please Remember to unregister receiver in onStop() of service, else another exception would come up......And explicitly call stopService() from onDisabled() of Widget. Keep your service as exported="false" in manifest if needed enter code here`d.
Dear Ponza, I have faced that sometimes, your service gets killed by Android, based on some usage based GC. But in that case, we can always have a smart check using some shared Pref boolean in every action of Widget.
HOPE my answer is detailed enough ;)
来源:https://stackoverflow.com/questions/16497591/android-appwidget-battery-status