我以为我弄明白了,但在对这个问题进行了一些调试之后: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滴答声时,它似乎都会将应用程序带到前台。有什么办法可以避免吗?
答案 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()中放置一个日志,并注意每个日志的启动时间。