如何恢复通知而不重新创建活动?

时间:2013-06-03 13:35:08

标签: android notifications oncreate ondestroy

我以为我弄明白了,但在对这个问题进行了一些调试之后:How to make notification uncancellable/unremovable我刚刚意识到我的活动仍以随机顺序进入onCreated()和onDestroyed()。

我的活动清单:

<activity
        android:name="***.***.***.*****"
        android:configChanges="orientation|keyboardHidden"
        android:label="@string/app_name"
        android:screenOrientation="portrait"
        android:launchMode="singleTop" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

我也尝试过launchmodes singleTask,singleInstance。

我的通知意向代码:

Intent intent = new Intent(context, MyClass.class);
    intent.setAction(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    //intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
    //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    //intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
    //intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

正如你所看到的,我已经尝试过看起来可能相关的每一面旗帜,但没有运气......

这会产生一些不需要的工件,比如每次单击通知时重新启动AlarmManager并触发alarmmanager启动任务。我想避免这种情况。

有什么建议吗?

编辑:我知道有很多像这样的问题,但提供的解决方案似乎没有在这里做到这一点......:/

Edit2:根据要求,这是我的班级:

package ***.***.***;

import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PorterDuff;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;


public class MyClass extends FragmentActivity {


private static String userName;
String password;
private static Boolean LoggedIn = false;
private static Boolean RunningState = false;
private static Boolean OnlineState = false;
private static String LastReportTime;

private static Boolean isVisible = true;
private static Boolean firstStart = true;

private static TextView onlineTextView;
private static TextView reportTimeTextView;
private static TextView runningStatusTextView;
private static TextView userLoggedInTextView;

private static Context context;

public static final String PREFS_NAME = "Settings";

public static final String NOTIFICATION_RUNNING_OK = "Reporting Active";
public static final String NOTIFICATION_USER_STOPPED = "Reporting Stopped";
public static final String NOTIFICATION_NO_NETWORK = "No Network Connected";
public static final String NOTIFICATION_NO_CONNECTION = "No Connection To Server";

public static final int NOTIFICATION_ID = 10;

public static final int LOGIN_REQUEST_CODE = 1;
public static final int WAKEUP_LOGIN_REQUEST_CODE = 2;

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);

    Log.d("MyClass", "Main onCreate() Called");

    loadVariables();

    com.remobjects.sdk.TypeManager.setPackage("com.remobjects.sdk");
    //if (firstStart)
    //{
        Log.d("MyClass", "Main onCreate() firstStart Called");
        if (RunningState && checkConnection())
        {
           // After runLogin(), onResume() gets called here again immediately
            setLoginCode(LOGIN_REQUEST_CODE);
            runLogin();
        }
        else
            init();
    //}
}

@Override
protected void onStart() {
    // TODO Auto-generated method stub
    super.onStart();
}

@Override
public void onResume()
{
    super.onResume();

    Log.d("MyClass", "Main onResume() Called");
    //firstStart gets set to false during login
    if (!firstStart)
    {
        Log.d("MyClass", "Main onResume() !firstStart Called");
        loadVariables();
        setVisible(true);
        updateUI();
    }
}

@Override
protected void onPause()
{
    super.onPause();
    saveVariables();
    setVisible(false);
}

@Override
protected void onStop()
{
    super.onStop();

    saveVariables();
    setVisible(false);
}

@Override
public void onDestroy()
{
    super.onDestroy();
    //cancelNotification();
    Log.e("MyClass", "onDestroy() called");
    saveVariables();
    setVisible(false);
    //setFirstStart(true);
}


private void loadVariables()
{
    SharedPreferences sharedPrefs = getSharedPreferences(PREFS_NAME, 0);

    userName = sharedPrefs.getString("userName", "");
    RunningState = sharedPrefs.getBoolean("RunningState", true);
    LoggedIn = sharedPrefs.getBoolean("LoggedIn", false);
    OnlineState = sharedPrefs.getBoolean("OnlineState", false);
    LastReportTime = sharedPrefs.getString("LastReportTime", "");

    context = this.getApplicationContext();
}

private static void saveVariables()
{
    SharedPreferences settings = context.getSharedPreferences(PREFS_NAME, 0);
    SharedPreferences.Editor editor = settings.edit();

    editor.putString("userName", userName);
    editor.putBoolean("RunningState", RunningState);
    editor.putBoolean("LoggedIn", LoggedIn);
    editor.putBoolean("OnlineState", OnlineState);
    editor.putString("LastReportTime", LastReportTime);

    editor.commit();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_my_class, menu);
    return true;
}

private Boolean checkConnection()
{
    Log.d("MyClass", "checkConnection()");
    ConnectivityManager cnnxManager = (ConnectivityManager) 
            getSystemService(Context.CONNECTIVITY_SERVICE);

    NetworkInfo ni = cnnxManager.getActiveNetworkInfo();

    if (ni != null && ni.isAvailable() && ni.isConnected()) 
    {
        OnlineState = true;
        return true;
    }
    OnlineState = false;
    return false;
}

public void runLogin()
{
    Intent intent = new Intent(context, LoginActivity.class);
    startActivityForResult(intent, getLoginCode());
    Log.d("MyClass", "runLogin()");
}

private void init()
{
    Log.d("MyClass", "init()");
    setContentView(R.layout.activity_field_agent);

    onlineTextView = (TextView)findViewById(R.id.onlineStatusTextView);
    reportTimeTextView = (TextView)findViewById(R.id.lastReportTimeTextView);
    runningStatusTextView = (TextView)findViewById(R.id.runningStatusTextView);
    userLoggedInTextView = (TextView)findViewById(R.id.userLoggedInTextView);

    findViewById(R.id.button_online).getBackground().setColorFilter(0xFF00FF00, PorterDuff.Mode.MULTIPLY);
    findViewById(R.id.button_highRisk).getBackground().setColorFilter(0xFFFFA500, PorterDuff.Mode.MULTIPLY);
    findViewById(R.id.button_alarm).getBackground().setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);

    setVisible(true);

    updateUI();

    if (RunningState)
    {
        setupAlarmManager(AlarmManager.INTERVAL_FIFTEEN_MINUTES);
        // Here onResume() gets called again
        updateNotificationText(NOTIFICATION_RUNNING_OK);

        Button temp = (Button)findViewById(R.id.button_online);
        temp.setCompoundDrawablesWithIntrinsicBounds(R.drawable.check_box, 0, R.drawable.check_box, 0);
    }
    else
    {
        //cancelAlarmManager();

        updateNotificationText(NOTIFICATION_USER_STOPPED);

        Button temp = (Button)findViewById(R.id.button_offline);
        temp.setCompoundDrawablesWithIntrinsicBounds(R.drawable.check_box, 0, R.drawable.check_box, 0);
    }
}

private void updateUI() 
{
    Log.d("MyClass", "updateUI()");

    updateUserLoggedInStatus(userName);

    updateOnlineStatus(OnlineState);

    updateRunningStatus(RunningState);

    updateReportTimeStatus(LastReportTime);
}

public void offDutyButton_click(View view)
{
    cancelAlarmManager();
    Button temp = (Button)findViewById(R.id.button_offline);
    temp.setCompoundDrawablesWithIntrinsicBounds(R.drawable.check_box, 0, R.drawable.check_box, 0);

    temp = (Button)findViewById(R.id.button_online);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);

    temp = (Button)findViewById(R.id.button_highRisk);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);

    temp = (Button)findViewById(R.id.button_alarm);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}

public void onDutyButton_click(View view)
{
    Button temp = (Button)findViewById(R.id.button_online);
    temp.setCompoundDrawablesWithIntrinsicBounds(R.drawable.check_box, 0, R.drawable.check_box, 0);

    temp = (Button)findViewById(R.id.button_offline);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);

    temp = (Button)findViewById(R.id.button_highRisk);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);

    temp = (Button)findViewById(R.id.button_alarm);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
    //cancelAlarmManager();
    setupAlarmManager(AlarmManager.INTERVAL_FIFTEEN_MINUTES);
}

public void highRiskButton_click(View view)
{
    Button temp = (Button)findViewById(R.id.button_highRisk);
    temp.setCompoundDrawablesWithIntrinsicBounds(R.drawable.check_box, 0, R.drawable.check_box, 0);

    temp = (Button)findViewById(R.id.button_online);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);

    temp = (Button)findViewById(R.id.button_offline);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);

    temp = (Button)findViewById(R.id.button_alarm);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}

public void alarmButton_click(View view)
{
    Button temp = (Button)findViewById(R.id.button_alarm);
    temp.setCompoundDrawablesWithIntrinsicBounds(R.drawable.check_box, 0, R.drawable.check_box, 0);

    temp = (Button)findViewById(R.id.button_online);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);

    temp = (Button)findViewById(R.id.button_highRisk);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);

    temp = (Button)findViewById(R.id.button_offline);
    temp.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}

public static void setButtonIcon(int inId)
{

}

public static void showToast(String inString, Context context)
{
    Toast.makeText(context, inString.toString(), Toast.LENGTH_SHORT).show();
}

public static void updateOnlineStatus(Boolean inStatus)
{
    if (isVisible)
    {
        if (inStatus)
            onlineTextView.setText("Online");
        else
            onlineTextView.setText("Offline");
    }
}

public static void updateReportTimeStatus(String inString)
{
    if (isVisible)
        reportTimeTextView.setText(inString);
}

public static void updateRunningStatus(Boolean inStatus)
{
    if (isVisible)
    {
        if (inStatus)
            runningStatusTextView.setText("Reporting");
        else
            runningStatusTextView.setText("Not Reporting");
    }
}

public static void updateUserLoggedInStatus(String inString)
{
    if (isVisible)
        userLoggedInTextView.setText(inString);
}


//
//
// Getters and Setters
//
//
public static void setLoggedIn(Boolean inBool)
{
    LoggedIn = inBool;
}

public static Boolean getLoggedIn()
{
    return LoggedIn;
}

public static void setRunningState(Boolean inBool)
{
    RunningState = inBool;
}

public static Boolean getRunningState()
{
    return RunningState;
}

public static void setVisible(Boolean inBool)
{
    isVisible = inBool;
}

public static Boolean getVisible()
{
    return isVisible;
}

public static void setUsername(String inString)
{
    userName = inString;
}

public static String getUsername()
{
    return userName;
}

public static void setLastReportTime(String inString)
{
    LastReportTime = inString;
}

public static String getLastReportTime()
{
    return LastReportTime;
}

public static Context getAppContext()
{
    return MyClass.context;
}

public static void setLoginCode(int code)
{
    SharedPreferences settings = context.getSharedPreferences(PREFS_NAME, 0);
    SharedPreferences.Editor editor = settings.edit();

    editor.putInt("LoginCode", code);

    editor.commit();
}

public static int getLoginCode()
{
    SharedPreferences sharedPrefs = context.getSharedPreferences(PREFS_NAME, 0);

    return sharedPrefs.getInt("LoginCode", 1);
}

public static void setFirstStart(Boolean inBool)
{
    firstStart = inBool;
}

public static Boolean getFirstStart()
{
    return firstStart;
}

//
//
//
//
//
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  switch(requestCode) {
    case (LOGIN_REQUEST_CODE) : {
      if (resultCode == Activity.RESULT_OK) {
        LoggedIn = data.getBooleanExtra("LoggedIn", false);
        userName = data.getStringExtra("Username");

        init();
      }
      break;
    }
    case (WAKEUP_LOGIN_REQUEST_CODE) : {
        if (resultCode == Activity.RESULT_OK) {
          LoggedIn = data.getBooleanExtra("LoggedIn", false);
          userName = data.getStringExtra("Username");

          cancelAlarmManager();
          setupAlarmManager(AlarmManager.INTERVAL_FIFTEEN_MINUTES);
        }
        break;
    }
  }
}

//
//
// AlarmManager
//
//

public static void setupAlarmManager(long interval)
{
    AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    Intent alarmIntent = new Intent(context, LaunchReceiver.class); 
    PendingIntent pendingAlarmIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, alarmIntent, 0);
    alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0, interval,  pendingAlarmIntent);

    RunningState = true;
    updateRunningStatus(RunningState);

    updateNotificationText(NOTIFICATION_RUNNING_OK);

    Log.d("MyClass", "AlarmManager Started");
}


public static void cancelAlarmManager()
{
    Intent intent = new Intent(context.getApplicationContext(), LaunchReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
    AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    alarmMgr.cancel(pendingIntent);

    RunningState = false;
    updateRunningStatus(RunningState);

    updateNotificationText(NOTIFICATION_USER_STOPPED);

    Log.d("MyClass", "AlarmManager Stopped");

    Intent serviceIntent = new Intent(context, MonitorService.class);
    context.stopService(serviceIntent);
    Log.d("MyClass", "Stopping MonitorService");
}



//
//
// Notification
//
//

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static void createNotification()
{
    NotificationManager notificationManager = (NotificationManager)context.getSystemService(NOTIFICATION_SERVICE);

    NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                            .setContentTitle("blablabla")
                            .setContentText("Getting Status")
                            .setSmallIcon(R.drawable.ic_launcher)
                            .setOngoing(true)
                            .setAutoCancel(false);

    Intent intent = new Intent(context, MyClass.class);
    intent.setAction(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    //intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
    //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    //intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
    //intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addParentStack(MyClass.class);
    stackBuilder.addNextIntent(intent);

    PendingIntent pendingIntent = stackBuilder.getPendingIntent(0,  PendingIntent.FLAG_UPDATE_CURRENT);

    builder.setContentIntent(pendingIntent);

    /*Notification noti = builder.build();
    noti.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;*/

    notificationManager.notify(NOTIFICATION_ID, builder.build());
}

public static void updateNotificationText(String inString)
{
    NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

    NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                                            .setContentText(inString)
                                            .setContentTitle("blablabla")
                                            .setSmallIcon(R.drawable.ic_launcher)
                                            .setOngoing(true)
                                            .setAutoCancel(false);

    Intent intent = new Intent(context, MyClass.class);
    intent.setAction(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addParentStack(MyClass.class);
    stackBuilder.addNextIntent(intent);

    PendingIntent pendingIntent = stackBuilder.getPendingIntent(0,  PendingIntent.FLAG_UPDATE_CURRENT);

    builder.setContentIntent(pendingIntent);

    /*Notification noti = builder.build();
    noti.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;*/

    notificationManager.notify(NOTIFICATION_ID, builder.build());
}

public static void cancelNotification()
{
    NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.cancel(NOTIFICATION_ID);
}
}

正如评论中所提到的,在启动loginActivity之后,onResume()会立即再次被调用。启动alarmManager后也一样。

此外,每次alarmManager滴答声时,它似乎都会将应用程序带到前台。有什么办法可以避免吗?

5 个答案:

答案 0 :(得分:34)

看起来问题是由通知代码中的这些行引起的(直接来自Android的通知指南:

TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addParentStack(FieldAgent.class);
    stackBuilder.addNextIntent(intent);

    PendingIntent pendingIntent = stackBuilder.getPendingIntent(0,  PendingIntent.FLAG_UPDATE_CURRENT);

用这样的常规pendingintent替换它们解决了它:

PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

一个完整的例子

Intent intent = new Intent(getApplicationContext(), myactivity.class);
PendingIntent pIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), intent, 0);

Notification myNotification  = new Notification.Builder(getApplicationContext())
                        .setContentTitle("Title")
                        .setContentText("Some text....")
                        .setSmallIcon(R.drawable.myicon)
                        .setContentIntent(pIntent)
                        .setAutoCancel(true).build();


NotificationManager notificationManager =
                        (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

notificationManager.notify(0, myNotification);

答案 1 :(得分:6)

就我而言,CeeRo的答案是有效的,但却是一种奇怪的方式。我不得不重新启动手机! :)

答案 2 :(得分:4)

我不知道我的情况是否与你一样。 我试图像你一样创造意图。 我正在使用pageviewer + fragment。 我的情况下,点击通知消息去app然后回到main,然后再次启动app,重新创建活动 (这个代码在类片段中)

Intent intent = new Intent(getActivity(),MainActivity.class);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent =  PendingIntent.getActivity(getActivity(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

现在没关系,改为这段代码:

Intent intent = getActivity().getIntent();
PendingIntent pendingIntent =  PendingIntent.getActivity(getActivity(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

希望这有帮助^ _ ^

答案 3 :(得分:1)

您是否覆盖了活动上的onBackPressed?我想如果你不覆盖onBackPressed,Android的默认是销毁(finish())Activity。所以,如果你要回去,那么你的通知会检查Activity是否已经存在,找不到,然后创建一个新的。

答案 4 :(得分:0)

您有很多代码正在多次运行。

卸下:

saveVariables();
setVisible(false);

来自onStop()和onDestroy()。此代码将始终首先在onPause()中运行。

的loadVariables();也可能会跑两次。一旦进入onCreate()并进入onResume()。

在某种程度上更改加载逻辑可能是明智的。

您的init()代码可能会被运行两次。一旦进入onCreate(),一次进入onActivityResult()。

TL; DR至于您的实际问题:

onActivityResult()有时候有点奇怪,因为当你认为它应该时它并不总是会触发。尝试在onActivityResult()中的init()之前加载变量。

要试验这一点,请在onCreate(),onStart(),onResume()和onActivityResult()中放置一个日志,并注意每个日志的启动时间。