Android java.lang.RuntimeException: 接收广播 Intent 时出错

Android java.lang.RuntimeException: Error receiving broadcast Intent

我的应用程序一启动就崩溃了,我不明白为什么。我有一个 Service 用作计时器来计算自计时器启动以来的秒数,然后将其传递回我的 MainActivity

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "BroadcastTest";
    private Intent intent;

    private Chronometer timer;
    private Button start;
    private Button stop;
    private EditText hourlyRate;
    private TextView money;
    private long timeWhenStopped = 0;
    private double moneyEarned;
    private double secondsRate;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        timer = (Chronometer) findViewById(R.id.chronometer);
        start = (Button) findViewById(R.id.start);
        stop = (Button) findViewById(R.id.stop);
        hourlyRate = (EditText) findViewById(R.id.hourlyRate);
        money = (TextView) findViewById(R.id.money);

        intent = new Intent(this, Timer.class);

          start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                startService(new Intent(MainActivity.this, Timer.class));
                timer.setBase(SystemClock.elapsedRealtime() + timeWhenStopped);
                timer.start();

            }
        });

        stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                timeWhenStopped = timer.getBase() - SystemClock.elapsedRealtime();
                timer.stop();
            }
        });

        timer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener()
        {
            @Override
            public void onChronometerTick(Chronometer chronometer){
                long timeElapsed = SystemClock.elapsedRealtime() - timer.getBase();
                int seconds = (int) timeElapsed / 1000;

                double hrlyRate = Double.parseDouble(hourlyRate.getText().toString());
                secondsRate = (hrlyRate / 60) / 60;

                moneyEarned = secondsRate * seconds;

                double displayMoney = Math.round(moneyEarned * 100.0)/100.0;

                Log.d("hours",Long.toString(seconds));

                money.setText("$"+Double.toString(displayMoney));

            }
        });

        }

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updateUI(intent);
        }
    };

    @Override
    public void onResume() {
        super.onResume();
        startService(intent);
        registerReceiver(broadcastReceiver, new IntentFilter(Timer.BROADCAST_ACTION));
    }

    @Override
    public void onPause() {
        super.onPause();
        unregisterReceiver(broadcastReceiver);
        stopService(intent);
    }

    private void updateUI(Intent intent) {
        String counter = intent.getStringExtra("counter");
        Log.d("SERVICE_SECONDS", counter);
    }
}

Timer.java:

public class Timer extends Service {

    private static final String TAG = "BroadcastService";
    public static final String BROADCAST_ACTION = "b.calvin.com.dirtymoney";
    private final Handler handler = new Handler();
    Intent intent;
    int counter = 0;

    private Runnable sendUpdatesToUI = new Runnable() {
        public void run() {
            countSeconds();
            handler.postDelayed(this, 1000); // 1 second
        }
    };

    @Override
    public void onCreate()
    {
        super.onCreate();
        intent = new Intent(BROADCAST_ACTION);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        handler.removeCallbacks(sendUpdatesToUI);
        handler.postDelayed(sendUpdatesToUI, 0); // 1 second

        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
            return START_STICKY;
        }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void countSeconds() {
        Log.d(TAG, Integer.toString(++counter));
        sendBroadcast(intent);
    }
}

错误:

FATAL EXCEPTION: main
Process: b.calvin.com.dirtymoney, PID: 3348
java.lang.RuntimeException: Error receiving broadcast Intent { act=b.calvin.com.dirtymoney flg=0x10 } in b.calvin.com.dirtymoney.MainActivity@bf337ff
at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:891)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.NullPointerException: println needs a message
at android.util.Log.println_native(Native Method)
at android.util.Log.d(Log.java:139)
at b.calvin.com.dirtymoney.MainActivity.updateUI(MainActivity.java:113)
at b.calvin.com.dirtymoney.MainActivity.access0(MainActivity.java:20)
at b.calvin.com.dirtymoney.MainActivity.onReceive(MainActivity.java:93)
at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:881)
at android.os.Handler.handleCallback(Handler.java:739) 
at android.os.Handler.dispatchMessage(Handler.java:95) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5417) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

您似乎忘记将 counter 变量放入 Intent,因此您将 null 作为消息传递给 Log.d(),结果是 NullPointerException.

像这样的东西应该可以工作:

private void countSeconds() {
    Log.d(TAG, Integer.toString(++counter));

    Intent counterIntent = new Intent(BROADCAST_ACTION);
    counterIntent.putExtra("counter", counter);

    sendBroadcast(counterIntent);
}

此外,计数器是一个 int,因此您应该调用 getIntExtra() 而不是 getStringExtra():

private void updateUI(Intent intent) {
    int counter = intent.getIntExtra("counter");
    Log.d("SERVICE_SECONDS", Integer.toString(counter));
}