Android clicks on the notification bar message to open the activity and determine if the app is running

Posted by mentor on Wed, 08 May 2019 05:10:05 +0200

android notification bar message click event if an activity is opened, we need to consider two situations:

 The application is running in the foreground.
 The application has exited.

If it's the first case, it's handled. Set flag to FLAG_ACTIVITY_NEW_TASK for Intent directly, and then call the context.startActivity method. Flag is not necessary. Under what circumstances should flag be set? When jumping to activity in the broadcast receiver, when jumping to activity in the service.

For the second case, I refer to a lot of app practices, which can be summarized as follows:

 Click on the notification bar message to open the activity and press the return key to determine whether the app is started or not. If it is not started, start the app.
Click on the notification bar message to determine whether the app is running in the foreground or not. Otherwise, start the app and then open the activity. The parameters are passed down through Intent layer by layer.

Several methods are needed: getting the running status of the application, judging whether the application process is running, and judging whether an activity exists in the task stack.

It's not important to judge whether a service is running or not. It may be used elsewhere and posted first. = =

/**
   * Determine whether a service is running
   * 
   * @param context
   * @param runService
   *            The class name of the service component to be validated
   * @return 
   */
  public static boolean isServiceRunning(Context context,
  		Class<? extends Service> runService) {
  	ActivityManager am = (ActivityManager) context
  			.getSystemService(Context.ACTIVITY_SERVICE);
  	ArrayList<RunningServiceInfo> runningService = (ArrayList<RunningServiceInfo>) am
  			.getRunningServices(1024);
  	for (int i = 0; i < runningService.size(); ++i) {
  		if (runService.getName().equals(
  				runningService.get(i).service.getClassName().toString())) {
  			return true;
  		}
  	}
  	return false;
  }

Get the running status of app, return 1 for the current application running in the foreground, return 2 for the current application running in the background, return 0 for the application not started (no live activity).

/**
	 * Return app running status
	 * 
	 * @param context
	 *            A context
	 * @param packageName
	 *            To determine the package name of the application
	 * @return int 1:Front Desk 2: Background 0: No
	 */
	public static int isAppAlive(Context context, String packageName) {
		ActivityManager activityManager = (ActivityManager) context
				.getSystemService(Context.ACTIVITY_SERVICE);
		List<ActivityManager.RunningTaskInfo> listInfos = activityManager
				.getRunningTasks(20);
		// Determine whether the program is at the top of the stack
		if (listInfos.get(0).topActivity.getPackageName().equals(packageName)) {
			return 1;
		} else {
			// Determine if the program is on the stack
			for (ActivityManager.RunningTaskInfo info : listInfos) {
				if (info.topActivity.getPackageName().equals(packageName)) {
					return 2;
				}
			}
			return 0;// Can't find it in the stack. Return to 3
		}
	}

Determine whether a process is running

/**
	 * Determine whether a process is running
	 * 
	 * @param context
	 * @param proessName The main process name of an application is usually a package name
	 * @return
	 */
	public static boolean isProessRunning(Context context, String proessName) {
		boolean isRunning = false;
		ActivityManager am = (ActivityManager) context
				.getSystemService(Context.ACTIVITY_SERVICE);
		List<RunningAppProcessInfo> lists = am.getRunningAppProcesses();
		for (RunningAppProcessInfo info : lists) {
			if (info.processName.equals(proessName)) {
				isRunning = true;
			}
		}
		return isRunning;
	}

To determine whether an activity is in the task stack, there will be a home page after the app starts. The home page will be destroyed only when the app exits. Therefore, it can be used to determine whether the MainActivity is in the task stack to determine whether the application has been started.

/**
	 * Determine whether a class exists in the task stack
	 * 
	 * @return
	 */
	public static boolean isExsitMianActivity(Context context, Class<?> cls) {
		Intent intent = new Intent(context, cls);
		ComponentName cmpName = intent.resolveActivity(context
				.getPackageManager());
		boolean flag = false;
		if (cmpName != null) { // Explain that this activity exists in the system
			ActivityManager am = (ActivityManager) context
					.getSystemService(Context.ACTIVITY_SERVICE);
			List<RunningTaskInfo> taskInfoList = am.getRunningTasks(10);
			for (RunningTaskInfo taskInfo : taskInfoList) {
				if (taskInfo.baseActivity.equals(cmpName)) { // That means it's started.
					flag = true;
					break; // Jump out of the cycle and optimize efficiency
				}
			}
		}
		return flag;
	}

Next comes the implementation of the first method:

Get the data from intent in the activity that needs to jump or in the onCreate method of BaseActivity, judge whether it is jumped from the click notification bar message, and save this state with a field, and then process the corresponding logical business.
private int isNoticeOpen = 0;// Did you jump in by clicking on the message notification?
 ```
 ```java
@Override
 public void onCreate(Bundle savedInstanceState) {
 	super.onCreate(savedInstanceState);
 	Bundle bun = getIntent().getExtras();
 	if (bun != null) {
 		// Determine whether a message notification click jump is performed?
 		try{
 			isNoticeOpen = Integer.valueOf(bun.getString("NOTICE"));
 		}catch(NumberFormatException e){
 			isNoticeOpen = 0;
 			e.printStackTrace();
 		}
 	}...............Get the parameters passed by other notifications...........
 }
stay onDestroy Method to determine whether the application is running in the foreground, but only available here MainActivity Judge whether there is a task stack, because when you click on the notification message, you jump to something activity When, the task stack should activity At the top of the stack, and at the top of the stack. activity The package name of the application is the package name of the application.
    @Override
    	public void onDestroy() {
    		super.onDestroy();
    		//If a click message jumps in, and (there is no application process in the running process or Activeness on the application home page does not exist in the task stack)
    		if (isNoticeOpen==1&&
    				(!ServiceHelper.isProessRunning(getApplicationContext(),this.getPackageName())
    						||!ServiceHelper.isExsitMianActivity(this,MainActivity_.class))) {

    			//Start app
    			Intent intent = getBaseContext().getPackageManager()
    					.getLaunchIntentForPackage(getPackageName());
    			intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    			startActivity(intent);
    		}
    	}

Finally, the second way is to determine whether the application is running in the foreground or not when the notification message is clicked, and start the application if it is not. Here we use a ServiceHelper class, which I wrote to encapsulate some step classes in order to shorten the jump process.

1. Processing notification message click event to jump to a page, where Intent does not set the activity to jump to, but will jump to the activity as an Intent parameter.
    /**
	 * Processing notification message click event to jump to specified interface
	 * 
	 * @param msg
	 */
	private void handerMsgCallToActivity(Context context, UMessage msg) {
		......................................................
		Intent intent = new Intent();
		/**
		 * Compatible with allied backstage direct push
		 */
		// Obtaining action parameters
		String actionKey = msg.extra.get("action");
		if (null == actionKey)
			return;
		if ("message".equals(actionKey)) {
			intent.putExtra(UmenPushManager.CALL_TO_ACTIVITY,
					MessageActivity_.class);
			intent.putExtra("NOTICE", true);
			intent.putExtra("msgCount", 999);// More than 0 is enough.
		} else if ("news".equals(actionKey)) {
			String newtype = msg.extra.get("newstype");
			String newsId = msg.extra.get("nid");
			String newsTitle = msg.extra.get("ntitle");
			String newsUrl = msg.extra.get("nurl");
			..............................
			intent.putExtra(UmenPushManager.CALL_TO_ACTIVITY,DetailsActivity_.class);
			intent.putExtra("NOTICE", true);
			intent.putExtra("news_id", newsId);
			intent.putExtra("url", newsUrl);
		
		} else if ("outlink".equals(actionKey)) {
			
			String title = msg.extra.get("title");
			String url = msg.extra.get("url");
			intent.putExtra(UmenPushManager.CALL_TO_ACTIVITY,
					BrowserActivity_.class);
			intent.putExtra("title", title);
			intent.putExtra("url", url);
		} 
 
		ServiceHelper.startActivityWithAppIsRuning(context, intent);
 
	}

2. In the previous step, we only acquired and set the data to be transferred in the page Jump and specified which page to jump to. The real jump task was assigned to the startActivityWithAppIsRuning method of the ServiceHelper class. In the startActivityWithAppIsRuning method, it judges whether the application is running or not. If not, it creates an Intent and sets the jump target Activity, which is obtained by the Intent passed over from the next step. Otherwise, start the application, pass a key in intent as FORM_NOTICE_OPEN, parameter identification with value true is jumped from the click message notification, and then pass the intent passed in the previous step as a parameter to the current intent.

    /**
    	 * Automatically determine whether the appUI process is running and set jump information
    	 * 
    	 * @param context
    	 * @param intent
    	 */
    	public static void startActivityWithAppIsRuning(Context context,
    			Intent intent) {
    		int isAppRuning = isAppAlive(context, UmenPushManager.APP_PACKAGE);
    		if (isAppRuning != 0) {
    			Intent newIntent = new Intent(context, (Class<?>) intent
    					.getExtras().getSerializable(
    							UmenPushManager.CALL_TO_ACTIVITY));
    			newIntent.putExtras(intent.getExtras());
    			newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    			context.startActivity(newIntent);
    			return;
    		}
    		// If the app process has been killed, restart app first, pass the start parameters of DetailActivity into Intent, and the parameters pass through
    		// SplashActivity is passed into MainActivity, at which point the initialization of app has been completed, and in MainActivity, it can be based on the incoming
    		// The parameter jumps to Detail Activity
    		Intent launchIntent = context.getPackageManager()
    				.getLaunchIntentForPackage(UmenPushManager.APP_PACKAGE);
    		launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
    				| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
    		launchIntent.putExtra(UmenPushManager.FORM_NOTICE_OPEN, true);
    		launchIntent.putExtra(UmenPushManager.FORM_NOTICE_OPEN_DATA, intent);
    		context.startActivity(launchIntent);
    	}

3. In the application startup page, it is not processed and passed directly to MainActivity. First, the startAppMainActivitySetNoticeIntent method of ServiceHelper class is called in the startup page WelcomeActivity to determine whether to jump from the click notification message, and if so, to write the passed data to the Intent jumping to MainActivity.

    //If click notification opens, set notification parameters
            ServiceHelper.startAppMainActivitySetNoticeIntent(this, intent);
    /**
    	 * When starting App, write the Intent that opens the notification for the Intent that jumps to MainActivity on the home page, if there is a notification
    	 * 
    	 * @param appStartActivity
    	 *            app The first activity to start, the main activity set in the configuration file
    	 * @param startMainActivityIntent
    	 */
    	public static void startAppMainActivitySetNoticeIntent(
    			Activity appStartActivity, Intent startMainActivityIntent) {
    		/**
    		 * If there are additional parameters in the Intent to start app, it means that app starts from the action of clicking on the notification bar and passes the parameters to MainActivity.
    		 */
    		try {
    			if (appStartActivity.getIntent().getExtras() != null) {
    				if (appStartActivity.getIntent().getExtras()
    						.getBoolean(UmenPushManager.FORM_NOTICE_OPEN) == true) {
    					startMainActivityIntent
    							.putExtra(
    									UmenPushManager.FORM_NOTICE_OPEN_DATA,
    									appStartActivity
    											.getIntent()
    											.getExtras()
    											.getParcelable(
    													UmenPushManager.FORM_NOTICE_OPEN_DATA));
    				}
    			}
    		} catch (Exception e) {
     
    		}
    	}

4. Call in onCreate of MainActivity

    	/**
    			 * If it's jumped from the notification of clicking on the notification bar
    			 */
    			ServiceHelper.isAppWithNoticeOpen(this);

Look again at ServiceHelper's isAppWithNoticeOpen method.

    /**
    	 * Judge if it's a jump by clicking on the notification bar?
    	 * 
    	 * @param mainActivity
    	 *            homepage
    	 */
    	public static void isAppWithNoticeOpen(Activity mainActivity) {
    		try {
    			if (mainActivity.getIntent().getExtras() != null) {
    				Intent intent = mainActivity.getIntent().getExtras()
    						.getParcelable(UmenPushManager.FORM_NOTICE_OPEN_DATA);
    				Intent newIntent = new Intent(mainActivity, (Class<?>) intent
    						.getExtras().getSerializable(
    								UmenPushManager.CALL_TO_ACTIVITY));
    				newIntent.putExtras(intent.getExtras());
    				mainActivity.startActivity(newIntent);
    			}
    		} catch (Exception e) {
     
    		}
    	}

The most critical point is that it is at this point that the click notification message is processed to the page that it really wants to jump to. (Class <?>) intent. getExtras (). getSerializable (UmenPushManager. CALL_TO_ACTIVITY) gets pages that need to be jumped to, and the rest of the data is passed down as it is.
Finally, attach the complete ServiceHelper class:

/**
 * Background service Component Assistant
 * 
 * @author wujiuye
 * 
 */
public final class ServiceHelper {
 
	/**
	 * Determine whether a service is running
	 * 
	 * @param context
	 * @param runService
	 *            The class name of the service component to be validated
	 * @return 
	 */
	public static boolean isServiceRunning(Context context,
			Class<? extends Service> runService) {
		ActivityManager am = (ActivityManager) context
				.getSystemService(Context.ACTIVITY_SERVICE);
		ArrayList<RunningServiceInfo> runningService = (ArrayList<RunningServiceInfo>) am
				.getRunningServices(1024);
		for (int i = 0; i < runningService.size(); ++i) {
			if (runService.getName().equals(
					runningService.get(i).service.getClassName().toString())) {
				return true;
			}
		}
		return false;
	}
 
	/**
	 * Return app running status
	 * 
	 * @param context
	 *            A context
	 * @param packageName
	 *            To determine the package name of the application
	 * @return int 1:Front Desk 2: Background 0: No
	 */
	public static int isAppAlive(Context context, String packageName) {
		ActivityManager activityManager = (ActivityManager) context
				.getSystemService(Context.ACTIVITY_SERVICE);
		List<ActivityManager.RunningTaskInfo> listInfos = activityManager
				.getRunningTasks(20);
		// Determine whether the program is at the top of the stack
		if (listInfos.get(0).topActivity.getPackageName().equals(packageName)) {
			return 1;
		} else {
			// Determine if the program is on the stack
			for (ActivityManager.RunningTaskInfo info : listInfos) {
				if (info.topActivity.getPackageName().equals(packageName)) {
					return 2;
				}
			}
			return 0;// Can't find it in the stack. Return to 3
		}
	}
 
	/**
	 * Automatically determine whether the appUI process is running and set jump information
	 * 
	 * @param context
	 * @param intent
	 */
	public static void startActivityWithAppIsRuning(Context context,
			Intent intent) {
		int isAppRuning = isAppAlive(context, UmenPushManager.APP_PACKAGE);
		if (isAppRuning != 0) {
			Intent newIntent = new Intent(context, (Class<?>) intent
					.getExtras().getSerializable(
							UmenPushManager.CALL_TO_ACTIVITY));
			newIntent.putExtras(intent.getExtras());
			newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			context.startActivity(newIntent);
			return;
		}
		// If the app process has been killed, restart app first, pass the start parameters of DetailActivity into Intent, and the parameters pass through
		// SplashActivity is passed into MainActivity, at which point the initialization of app has been completed, and in MainActivity, it can be based on the incoming
		// The parameter jumps to Detail Activity
		Intent launchIntent = context.getPackageManager()
				.getLaunchIntentForPackage(UmenPushManager.APP_PACKAGE);
		launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
				| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
		launchIntent.putExtra(UmenPushManager.FORM_NOTICE_OPEN, true);
		launchIntent.putExtra(UmenPushManager.FORM_NOTICE_OPEN_DATA, intent);
		context.startActivity(launchIntent);
	}
 
	/**
	 * When starting App, write the Intent that opens the notification for the Intent that jumps to MainActivity on the home page, if there is a notification
	 * 
	 * @param appStartActivity
	 *            app The first activity to start, the main activity set in the configuration file
	 * @param startMainActivityIntent
	 */
	public static void startAppMainActivitySetNoticeIntent(
			Activity appStartActivity, Intent startMainActivityIntent) {
		/**
		 * If there are additional parameters in the Intent to start app, it means that app starts from the action of clicking on the notification bar and passes the parameters to MainActivity.
		 */
		try {
			if (appStartActivity.getIntent().getExtras() != null) {
				if (appStartActivity.getIntent().getExtras()
						.getBoolean(UmenPushManager.FORM_NOTICE_OPEN) == true) {
					startMainActivityIntent
							.putExtra(
									UmenPushManager.FORM_NOTICE_OPEN_DATA,
									appStartActivity
											.getIntent()
											.getExtras()
											.getParcelable(
													UmenPushManager.FORM_NOTICE_OPEN_DATA));
				}
			}
		} catch (Exception e) {
 
		}
	}
 
	/**
	 * Judge if it's a jump by clicking on the notification bar?
	 * 
	 * @param mainActivity
	 *            homepage
	 */
	public static void isAppWithNoticeOpen(Activity mainActivity) {
		try {
			if (mainActivity.getIntent().getExtras() != null) {
				Intent intent = mainActivity.getIntent().getExtras()
						.getParcelable(UmenPushManager.FORM_NOTICE_OPEN_DATA);
				Intent newIntent = new Intent(mainActivity, (Class<?>) intent
						.getExtras().getSerializable(
								UmenPushManager.CALL_TO_ACTIVITY));
				newIntent.putExtras(intent.getExtras());
				mainActivity.startActivity(newIntent);
			}
		} catch (Exception e) {
 
		}
	}
 
	/**
	 * Determine whether a process is running
	 * 
	 * @param context
	 * @param proessName
	 * @return
	 */
	public static boolean isProessRunning(Context context, String proessName) {
		boolean isRunning = false;
		ActivityManager am = (ActivityManager) context
				.getSystemService(Context.ACTIVITY_SERVICE);
		List<RunningAppProcessInfo> lists = am.getRunningAppProcesses();
		for (RunningAppProcessInfo info : lists) {
			if (info.processName.equals(proessName)) {
				isRunning = true;
			}
		}
		return isRunning;
	}
 
	/**
	 * Determine whether a class exists in the task stack
	 * 
	 * @return
	 */
	public static boolean isExsitMianActivity(Context context, Class<?> cls) {
		Intent intent = new Intent(context, cls);
		ComponentName cmpName = intent.resolveActivity(context
				.getPackageManager());
		boolean flag = false;
		if (cmpName != null) { // Explain that this activity exists in the system
			ActivityManager am = (ActivityManager) context
					.getSystemService(Context.ACTIVITY_SERVICE);
			List<RunningTaskInfo> taskInfoList = am.getRunningTasks(10);
			for (RunningTaskInfo taskInfo : taskInfoList) {
				if (taskInfo.baseActivity.equals(cmpName)) { // That means it's started.
					flag = true;
					break; // Jump out of the cycle and optimize efficiency
				}
			}
		}
		return flag;
	}
 
}

** Finally, I would like to briefly mention the four loading modes of Activity at the end: **

1.standard: Activity's default loading method, even if one activity already exists in the Task stack, another activity jumps to the activity through Intent, and a new instance is created and pushed into the stack. For example, the current stack situation is: A B C D D, jumping to D through Intent in the activity of D, then the current stack situation is: A B C D D. At this point, if D at the top of the stack jumps to B through Intent, then the stack situation is: A B C D B. At this point, if you press the return key in turn, D D C B A will pop up the stack and display on the interface in turn.

2.singleTop: If the Lauch mode of an Activity is set to singleTop, then when the Activity is on the top of the stack and jumps to its own Activity through Intent, a new instance will not be created and pushed into the stack. For example, the current stack situation is: A B C D. D's Aunch mode is set to singleTop, then starting Intent to jump to D in D, then it will not create a new instance of D into the stack, at this time the stack situation is still as follows: A B C D. But if the mode of B is singleTop, D jumps to B, then a new instance of B will be pushed into the stack, because B is not at the top of the stack, then the stack becomes: A B C D B.

3.singleTask: If an Activity is singleTask mode, there will be only one instance of that Activity in the Task stack. For example, the current stack situation is: A B C D. B's Launch mode is singleTask, when D jumps to B through Intent, the stack situation becomes: A B. C and D are popped up and destroyed, that is to say, instances above B are destroyed.

4. Single Instance: Press Activity into a new task stack. For example, the case of Task Stack 1 is: A B C. C jumps to D through Intent, and D's Aunch mode is singleInstance, which will create a new Task stack 2. At this point, the Task stack 1 case is: A B C. The case of Task Stack 2 is: D. At this time, the screen interface shows the content of D. If D jumps to D through Intent, then an instance of D will not be created in Task Stack 2, so the situation of the two stacks will not change. If D jumps to C, stack 1 becomes A B C, because C's Launch mode is standard, then stack 1 becomes A B C if the return key is pressed again. That is to say, now the interface also shows the content of C, not D.

Topics: Mobile Android Java REST