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

Java Android-应用程序关闭时从另一个类调用方法(使用AlarmManager),java,android,Java,Android,我试图使用AlarmManager从另一个类调用MainActivity类中的方法 我发现这有助于我调用该方法,但当应用程序关闭且AlarmManager仍在运行时,会出现NullPointerException错误 另一个对我有效的解决方案是在AlarmRec类中使用getBatteryLevel()。当我尝试此操作时,会出现错误-无法解析方法registerReceiver(null,android.content.IntentFilter) 我的主要活动课: package com.ds.

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

我发现这有助于我调用该方法,但当应用程序关闭且AlarmManager仍在运行时,会出现NullPointerException错误

另一个对我有效的解决方案是在AlarmRec类中使用getBatteryLevel()。当我尝试此操作时,会出现错误-无法解析方法registerReceiver(null,android.content.IntentFilter)

我的主要活动课:

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;
    }
}

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

您应该在BroadcastReceiver中执行methodToCall()(如果该方法不需要很长时间),或者从那里调用服务,在那里执行methodToCall()

另一种方法是像这样修改你的接收器

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);
    }
调用方法extra的onCreate检查中的main活动

if (getIntent() != null && getIntent().getExtras() != null && getIntent().getExtras().getBoolean("CALL_METHOD", false)) {
    methodToCall();
}
  • 不要像单例一样通过静态方法公开您的主要活动
  • 您的activity getInstance()方法将返回null,因为它可能已从后堆栈中弹出(或者如果activity已被终止)。不要依赖于你的活动,并且在你的应用程序建立背景后,引用才是有效的
  • 我不明白您希望在活动定义的方法中使用什么功能。你应该可以把它放在广播接收器里。如果需要显示UI,请再次启动活动(在这种情况下,UI将再次显示)
    你的意思是从onReceive方法调用methodToCall()吗?应用程序会在用户定义的电池电量下关闭手机,将该方法重新写入onReceive会起作用,但由于某些原因,更新电池电量在onReceive中不起作用。我已使用getBatteryLevel()方法更新了问题中的代码。当我将代码复制到AlarmRec类中时,我得到了“无法解析方法”registerReceiver(null,android.content.IntentFilter),因为在BroadcastReceiver中,您应该像context.registerReceiver(null,android.content.IntentFilter)一样调用它。用另一个解决方案更新了我的答案。感谢您的帮助,但现在应用程序在启动时崩溃,出现错误-尝试在空对象引用上调用虚拟方法“boolean android.os.Bundle.getBoolean(java.lang.String)”。您不能这样做。当应用程序关闭时,MainActivity.getInstance()返回null。你可以在Broadcast中编写方法。我不能在BroadcastReceiver中编写方法,因为我需要获得电池电量,我不知道如何使用BroadcastReceiver。我已经对另一个答案进行了评论,为什么我的代码不能,以及为什么我不能在AlarmRec类中使用它。(您可能在评论之前就开始键入答案)。
    if (getIntent() != null && getIntent().getExtras() != null && getIntent().getExtras().getBoolean("CALL_METHOD", false)) {
        methodToCall();
    }