【问题标题】:Weird behaviour when using intent and BroadcastReceiver to get android battery level使用意图和广播接收器获取android电池电量时的奇怪行为
【发布时间】:2011-02-07 20:56:18
【问题描述】:

我试图在运行 Android 应用程序后查找电池电量。当手机启动应用程序完全充电时,代码总是返回 100% 的电池电量(即使它已经耗尽了很多)。如果我以 75% 的电量或其他电量启动应用程序,那么它会在测试结束时返回实际的电池电量。我开始测试时将手机插入电脑并保持充电,然后在执行应用程序之前拔下它。理想情况下,我希望能够获得开始百分比和结束百分比,但两者的读数均为 100%。所以这就是我正在做的事情......我从我的活动中称之为:

this.registerReceiver(this.mBatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

然后在 BroadcastReceiver 中我做了很多事情(这需要一个多小时,因此电池电量会发生变化)。然后在 BoradcastReceiver 结束时我称之为

int level2 = intent.getIntExtra("level", 0);    /* Ending battery level */
String end = "Ending battery level: " + String.valueOf(level2) + "%";

然后将String end 发送到服务器。

我的代码如下所示:

package com.mdog.datareceive;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.PowerManager;
import android.util.Log;
import android.widget.TextView;


public class Receive extends Activity {

    /* Test parameters */
    static int BYTES_TO_READ = 1024*1024*50;    /* The size of the data for each transfer */
    static int TIMES_TO_READ = 20;              /* The number of times the client will request the data */
    static int PLAYER_BUFFER_SIZE = 1638400;    /* Clients buffer size 1638400 = 1.57MB */
    static int SLEEP_TIME_MS = 5000;

    /* Display Info */
    String start = "empty";                 /* String holder for the starting battery life */
    String end = "empty2";                  /* String holder for the ending battery life */
    int allMBytes = 0;                      /* Integer holder for the total number of megabytes received during the test */
    TextView tv;                            /* The view the phone displays after completion of test */

    /* Server Info */
    String serverIP = "192.168.0.104";      /* Server IP */
    int serverPort = 11313;                 /* Server port number */



    private BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver(){

        @Override
        public void onReceive(Context arg0, Intent intent) {

            //int level = intent.getIntExtra("level", 0);

            Socket connectionSocket = null;                         /* Socket to communicate with server */
            byte[] inputHolderByteArray = new byte[PLAYER_BUFFER_SIZE]; /* Used to read from the socket */

            int bufferBytes = 0;        /* filling the second buffer */
            int totalBytesRead = 0;     /* The total number of bytes read for this transfer round */
            int read=0;                 /* reading from stream, will contain the number of bytes read or -1 if the end has been hit */

            /* Acquire a wake lock for the phone so it does not go to sleep */
            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, getClass().getName());

            /* Connect to Server */
            try {

                connectionSocket = new Socket(serverIP, serverPort);
                connectionSocket.setReceiveBufferSize(PLAYER_BUFFER_SIZE); //1.5ish MB
                connectionSocket.setKeepAlive(true);
                PrintWriter out = new PrintWriter(connectionSocket.getOutputStream(), true);

                out.print("Client Info: Bytes expected per transfer:" + BYTES_TO_READ + ", Number of transfer to request:" + TIMES_TO_READ+ ", Buffer size:" +PLAYER_BUFFER_SIZE+ ", Sleep time(ms):" + SLEEP_TIME_MS + "\n");
                out.flush();

                wl.acquire();

                for(int i=0; i<TIMES_TO_READ; i++){

                    out.print("Start\n");
                    out.flush();

                    while(totalBytesRead < BYTES_TO_READ){

                        /* Read at most PLAYER_BUFFER_SIZE bytes */
                        read = connectionSocket.getInputStream().read(inputHolderByteArray, 0, PLAYER_BUFFER_SIZE);

                        if(read != -1){
                            bufferBytes += read;
                            totalBytesRead  += read;
                            if(bufferBytes >= PLAYER_BUFFER_SIZE){
                                    try {
                                        Thread.sleep(SLEEP_TIME_MS);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                bufferBytes = 0;
                            }
                        }
                        else{
                            /* End of stream reached */
                            break;
                        }     
                    }

                    allMBytes += ((totalBytesRead/1024)/1024);
                    totalBytesRead = 0;

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

                int level2 = intent.getIntExtra("level", 0);    /* Ending battery level */

                /* Put data on screen */
                start = "Starting battery level: 100%";
                end = "Ending battery level: " + String.valueOf(level2) + "%";
                out.print("Test Completed: " + start + ", " + end + ", Megabytes Read: " + allMBytes + "\n");
                out.flush();

                wl.release();

                tv.setText(start + "    \n" + end + "    \n Total MB transferred:" + allMBytes);
                setContentView(tv);

            } catch (UnknownHostException e) {
                Log.i("UnknownHost exception ", " ******************** Log Msg UHE " + e.getLocalizedMessage());
                e.printStackTrace();
            } catch (IOException e2) {
                Log.i("IO exception ", "******************** Log Msg IOE " + e2.toString());
                e2.printStackTrace();
            }
        }
    };


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {

        tv = new TextView(this);                /* The view to post text to */
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        this.registerReceiver(this.mBatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    }
}

【问题讨论】:

  • 一般注意事项:有一个额外的EXTRA_SCALE(“刻度”),其中包含级别的最大值。最大值似乎是 100,因此您对百分比的假设是正确的 - 但我不会指望它总是如此。

标签: android android-activity android-intent broadcastreceiver battery


【解决方案1】:

首先,intent.getIntExtra("level", 0); 不是百分比。 intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 1) 需要与 intent.getIntExtra(BatteryManager.EXTRA_SCALE, 1) 进行比较才能得到百分比。

其次,在主应用程序线程上进行网络 I/O,例如 onReceive()BroadcastReceiver

第三,您将电池电量与自身进行比较。您需要等待下一个 ACTION_BATTERY_CHANGED 广播以找出新的电池电量。

【讨论】:

  • @CommonsWare,感谢您的提示。你如何等待意图被广播?他们多久播出一次?有没有推荐做网络IO的具体地方?这是我的应用程序唯一做的事情,就是下载随机字节并检查使用了多少电池电量。
  • @Michael:“你如何等待意图被广播?” -- 从onReceive() 返回。最终,onReceive() 将再次被调用。 github.com/commonsguy/cw-advandroid/tree/master/SystemEvents/… "有没有具体的地方推荐做网络IO?" -- 后台线程,例如 AsyncTask。 “这是我的应用程序唯一做的事情,就是下载随机字节并检查使用了多少电池电量。” ——嗯,好的。
  • @CommonsWare 我做了一些更改...这看起来如何homepage.usask.ca/~mcb394/Receive.java(抱歉,某些地方的格式不正确)。我可以从我的 AsyncTask 内部类方法中可靠地调用包含 BroadcastReceiver 的方法吗?更重要的是我现在这样做正确吗?
  • @Michael:这是不同的,但仍然很糟糕。您正在注册您的广播接收器两次(每次batteryLevel() 调用一次)并且永远不会取消注册它,这意味着您将泄漏内存。您无法按照您尝试的方式按需获取电池电量。这纯粹是一个广播事件——你无法控制时间。您的总体目标(“下载随机字节并检查使用了多少电池电量”)不可能按照您实现的方式实现。
  • @CommonsWare 是的,我在一夜之间进行了测试,从下载完成到收到最后一次广播之间有 3 分钟的等待时间(尽管我确实得到了 100% 和 78%,这比100 和 100 哈哈)....你已经帮了很多忙了,谢谢。我想我不能请你帮我把它清理干净,让它尽可能接近?也就是说...开始,等待广播并设置变量,注销,下载,注册并等待广播,然后设置第二个电池变量?我想我只是不明白这里应该如何使用 BroadcastReceiver。
【解决方案2】:

您不应该将应用程序逻辑放在 onReceive() 方法中。此方法应该只处理意图。否则你可能会阻止意图传递到其他应用程序。

您的电池状态不会改变,因为您在使用此方法进行阻止时没有收到传递的意图。传递的意图本身不会改变。只要电池状态发生变化,就会调用 onReceive() 方法——只要你不阻塞它。

【讨论】:

  • 对不起,我是安卓新手。你能让我知道我是如何对 BroadcastReceiver 进行这些调用的吗?我是否在 BroadcastReceiver 中创建另一个方法并将我的代码放在那里?然后在该方法之前和之后调用 BroadcastReceiver 来获取关卡?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-31
相关资源
最近更新 更多