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

时间:2015-01-28 20:01:46

标签: java android

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

我发现this question帮助我调用了方法但是当应用程序关闭时,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);
        }
    }
}

2 个答案:

答案 0 :(得分:0)

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

你应该在你的BroadcastReceiver中执行methodToCall()(如果方法不花费很长时间)或者从那里调用Service,你可以在那里执行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);
    }

onCreate中的MainActivity检查CALL_METHOD extra;

if (getIntent() != null && getIntent().getExtras() != null && getIntent().getExtras().getBoolean("CALL_METHOD", false)) {
    methodToCall();
}

答案 1 :(得分:0)

  1. 不要通过静态方法(如单例)公开主活动。
  2. 您的活动getInstance()方法将返回null,因为它可能已从后台堆栈弹出(或者如果活动已被杀死)。不要依赖您的活动存在,并且在您的应用程序背景后参考有效。
  3. 我不了解活动定义的方法中您想要的功能。你应该能够把它放在广播接收器中。如果您需要显示UI,请再次启动您的活动(在这种情况下,UI将再次显示)。