Android – 应用程序关闭时从另一个类调用方法(使用AlarmManager)

我试图使用AlarmManager从另一个类调用我的MainActivity类中的方法。

我发现这个问题帮助我调用了方法但是当应用程序关闭时,AlarmManager仍在运行,它会产生NullPointerException错误。

另一个对我有用的解决方案是在我的AlarmRec类中包含getBatteryLevel()。 当我尝试这个时,我得到错误 – 无法解析方法registerReceiver(null,android.content.IntentFilter)。

我的MainActivity类:

package com.ds.shutdown; import android.app.Activity; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.BatteryManager; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.util.Calendar; public class MainActivity extends Activity { int userLvl; int batteryLvl; static MainActivity mainActivity; private AlarmManager alarmMgr; private PendingIntent alarmIntent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mainActivity = this; batteryLvl = getBatteryLevel(); String bat = Integer.toString(batteryLvl); TextView textViewTwo = (TextView) findViewById(R.id.textBatteryLvl); textViewTwo.setText("Battery level: " + bat); userLvl = loadSavedPreferences(); TextView textView = (TextView) findViewById(R.id.textUserLvl); textView.setText("User entry: " + Integer.toString(userLvl)); if (getIntent() != null && getIntent().getExtras() != null && getIntent().getExtras().getBoolean("CALL_METHOD", false)) { shutdown(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } public void shutdown() { Toast.makeText(this, "In shutdown method", Toast.LENGTH_SHORT).show(); batteryLvl = getBatteryLevel(); String bat = Integer.toString(batteryLvl); TextView textViewTwo = (TextView) findViewById(R.id.textBatteryLvl); textViewTwo.setText("Battery level: " + bat); userLvl = loadSavedPreferences(); if (batteryLvl <= userLvl) { try { Process process = Runtime.getRuntime().exec(new String[]{"su", "-c", "reboot -p"}); process.waitFor(); } catch (Exception ex) { ex.printStackTrace(); } } } public int getBatteryLevel() { Intent batteryIntent = registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); return level; } //OK button onClick public void btnPress(View v) { EditText mEditText = (EditText) findViewById(R.id.userLvl); //Look at text box String userLvlStr = mEditText.getText().toString(); //Take contents and set to string if (userLvlStr.matches("")){ Toast.makeText(this, "Invalid Entry", Toast.LENGTH_SHORT).show(); return; } userLvl = Integer.parseInt(userLvlStr); //Convert that string to an int saveSavedPreferences(userLvl); //Save that int setContentView(R.layout.activity_main); //Look at main activity TextView textView = (TextView) findViewById(R.id.textUserLvl); //Look at text view textView.setText("User entry: " + userLvlStr); //Change text view to show user entry batteryLvl = getBatteryLevel(); String bat = Integer.toString(batteryLvl); TextView textViewTwo = (TextView) findViewById(R.id.textBatteryLvl); textViewTwo.setText("Battery level: " + bat); alarmMethod(); } //Saves variable(s) across app close private void saveSavedPreferences(int userLvl){ SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); //Create SharedPreferences object SharedPreferences.Editor editor= sharedPref.edit(); //Now get editor editor.putInt("userLvl", userLvl); //Put in variable editor.commit(); //Save variable(s) } //Loads variable(s) across app close private int loadSavedPreferences() { SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); userLvl = sharedPrefs.getInt("userLvl", 0); return userLvl; //Using return since only one variable is needed } //Set alarm private void alarmMethod() { alarmMgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE); //Create Alarm Manager Intent intent = new Intent(this, AlarmRec.class); //Set intent alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0); Calendar calendar = Calendar.getInstance(); //setRepeating() lets you specify a precise custom interval--in this case, 20 seconds alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 10, alarmIntent); Toast.makeText(MainActivity.this, "Alarm set", Toast.LENGTH_LONG).show(); } public void cancelAlarm(View v2) { // If the alarm has been set, cancel it. if (alarmMgr != null) { alarmMgr.cancel(alarmIntent); } TextView textView = (TextView) findViewById(R.id.textUserLvl); textView.setText("User entry: "); } public static MainActivity getInstance(){ return mainActivity; } } 

我的闹钟接收器课程:

 package com.ds.shutdown; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.BatteryManager; import android.widget.Toast; public class AlarmRec extends BroadcastReceiver { //@Override public void onReceive(Context context, Intent intent) { //Call shutdown Toast.makeText(MainActivity.getInstance(), "Calling shutdown", Toast.LENGTH_SHORT).show(); if (MainActivity.getInstance() != null) { MainActivity.getInstance().shutdown(); } else { Intent i = new Intent(context, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //I also tried i.addFlags i.putExtra("CALL_METHOD", true); context.startActivity(i); } } } 

因为当您的应用程序关闭时,MainActivity.getInstance()将返回null。

您应该在BroadcastReceiver中执行methodToCall()(如果方法不花费很长时间)或从那里调用Service,您可以在其中执行methodToCall()。

另一种方法是像这样修改您的Receiver

 Toast.makeText(context, "Calling shutdown", Toast.LENGTH_SHORT).show(); if (MainActivity.getInstance() != null) { MainActivity.getInstance().methodToCall(); } else { Intent i = new Intent(context, MainActivity.class); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.putExtra("CALL_METHOD", true); context.startActivity(i); } 

并且onCreate中的MainActivity检查CALL_METHOD extra;

 if (getIntent() != null && getIntent().getExtras() != null && getIntent().getExtras().getBoolean("CALL_METHOD", false)) { methodToCall(); } 
  1. 不要通过静态方法(如单例)公开主活动。
  2. 您的活动getInstance()方法将返回null,因为它可能已从后台堆栈中弹出(或者如果活动已被杀死)。 不要依赖您的活动,并且在您的应用程序背景之后参考有效。
  3. 我不明白您在活动定义的方法中需要什么function。 你应该能够把它放在广播接收器中。 如果您需要显示UI,请再次启动您的活动(在这种情况下,UI会再次显示)。