Situation Brief
In the process of developing an Android app, there is a need to launch a service in the app that runs in a standalone process, keeps a long connection to the server, displays the message that the server pushes over the notification bar, and sets the click action. Click to jump to the corresponding activity in the app. The problem is that the service is running as a standalone process, and after receiving the message and popping the notification, the app itself processes two things:
- App is running
- App has exited
For the first case, the processing is very simple, the parameters are passed directly into the intent and the corresponding activity can be opened.
However, the second case is complicated because the app has exited, and some of the actions in the activity that you want to open are dependent on the initialization of the app, which is done during the app startup process. For example, a shopping app pushes a message for a new item, and the user clicks on the notification to enter the activity for the product details, and the activity has an order button, which, when clicked, gets the user's ID from the local and a message to the server. Tell the server that a user ordered the item. These user information is obtained after a series of interactions with the server when the app is launched. If the app exits directly into the details activity and clicks on the purchase, it will fail because the user information is not available.
So at present to solve the problem, set the click Action in notification, if the app itself is running, jump directly to the target activity, if the app has exited, start the app to complete initialization, and then jump to the target activity.
Solutions and ideas
We assume that there are currently three activity:
- Splashactivity is used to display the app large image, while the user login and other operations, the server returned to the data to mainactivity.
- The main activity of the Mainactivity app.
- Detailactivity mainactivity Click button to enter activity to display the item details.
The service that pops up the notification is in another process.
What we want to achieve is to:
- Click the notification bar notification, if the app is running, then jump directly to detailactivity display specific content, in Detailactivity press the back key to return mainactivity
- Click the notification bar notification, if the app has exited, first from splashactivity to enter, display the app launch interface, the initialization of the operation to enter the mainactivity and then jump to detailactivity display specific content, Press the back key in Detailactivity to return to Mainactivity.
The initial idea is to determine whether the app process exists, if it exists, use startactivities to start mainactivity and detailactivity. Why do I have to start mainactivity instead of just starting detailactivity? Because of the following situation, all the activity in the process has exited, but the process has not been reclaimed by the system, when the process is determined to return true, and then only start detailactivity, press the back key task stack directly to the end, to return to the desktop. And the effect we want is to press the back key to return to the previous activity, which is mainactivity.
If the app process has exited and does not exist, start the app with a intent, which contains a bundle with the parameters required to start detailactivity in the bundle, which intent passed in Splashactivity, Again by the splashactivity to Mainactivity, in the mainactivity to add judgment, if there is this parameter, it means that the application is started from the notification bar, to jump to the detailactivity operation, otherwise is the general start.
Code implementation
With the approximate implementation of the idea, we have a demo of the actual operation.
First of all, our demo has a simple component:
- Pushservice, the service started in the new process, is responsible for listening to the server, receiving information from the server after the message broadcast, in this demo, in order to simplify, simply broadcast a message
- Shownotificationreceiver, Broadcastreceiver registered in the new process, after receiving the Pushservice message, will pop up the notification in the notification bar
- Notificationreceiver, the broadcastreceiver that is registered in the new process, is used to set the action of clicking Notifications in the notification bar to open an activity in the app
- Splashactivity, App launch page, first boot image, 3s enter mainactivity
- Mainactivity,app's main activity
- Activity that shows details in Detailactivity,app
Pushservice.java
The first is Pushservice, to start in a new process, add the following code to register the service in Androidmanifest.xml
<service android:name=".PushService" android:process=":push"/>
Pushservice's work is very simple, after launching a broadcast in the notification bar display notification, and then resident in the background
PublicClassPushserviceExtendsservice{@Nullable@OverridePublic IBinderOnbind(Intent Intent) {Returnnull;} @Override public void oncreate () { Super.oncreate (); LOG.I ( "Pushservice", "Pushservice onCreate"); //with Alarmmanager timed broadcast alarmmanager AM = (alarmmanager) getsystemservice (Context.alarm_service); Intent Intent = new Intent (this, Shownotificationreceiver.class); Pendingintent pendingintent = pendingintent.getbroadcast (this, 0, Intent, pendingintent.flag_update_current); Am.set (Alarmmanager.elapsed_realtime, Systemclock.currentthreadtimemillis (), pendingintent); }}
Shownotificationreceiver.java
This broadcast class is used to pop up notifications in the notification bar
PublicClassShownotificationreceiverExtendsbroadcastreceiver{private staticFinalStringTAG ="Repeatreceiver";@Override public void OnReceive (Context Context,Intent Intent) {LOG.D (TAG,"Shownotificationreceiver onreceive");Set the action of clicking on the notification bar to start another broadcastIntent broadcastintent =NewIntent (Context,Notificationreceiver.Class);Pendingintent pendingintent =Pendingintent. Getbroadcast (Context,0, Broadcastintent,Pendingintent.flag_update_current); notificationcompat. builder Builder = new Notificationcompat. builder (context), Builder.setcontenttitle ( "This is the ticker of notifications"). Setcontentintent (pendingintent). Setsmallicon (Android.r.drawable.ic_lock_idle_charging); log.i ( "repeat", "shownotification") ; notificationmanager manager = (notificationmanager) Context.getsystemservice (context. Notification_service); Manager.notify (2, Builder.build ())}}
Notificationreceiver.java
Click on the notification bar, will send a broadcast, Notificationreceiver received the broadcast, will determine whether the app process is still alive, according to the different status of the app process, define different app launch mode
PublicClassNotificationreceiverExtendsbroadcastreceiver{@OverridePublicvoidOnReceive(context context, Intent Intent) {Determine if the app process is aliveif (systemutils.isappalive (context,"Com.liangzili.notificationlaunch")) {If you survive, start detailactivity directly, but consider a situation where the app's process is stillBut the task stack is empty, for example, the user clicks the Back button to exit the app, but the process has not been reclaimed by the system, if it is started directlyDetailactivity, press the back key again to not return to mainactivity. So at the startBefore Detailactivity, start mainactivity first. LOG.I ("Notificationreceiver","The app process is Alive"); Intent mainintent =New Intent (context, mainactivity.class);Set the Launchmode of the mainativity to Singletask, or add intent.flag_clear_top to the FLAG below,If there is an instance of mainactivity in the task stack, it is moved to the top of the stack and the activity above it is cleared out of the stack.If the mainactivity instance does not exist on the TASK stack, create mainintent.setflags (Intent.flag_activity_new_task) at the top of the stack; Intent detailintent =New Intent (context, detailactivity.class); Detailintent.putextra ("Name","Rice cooker"); Detailintent.putextra ("Price","58 Yuan"); Detailintent.putextra ("Detail","This is a good pot, this is the app process exists, directly start the activity"); Intent[] intents = {mainintent, detailintent}; Context.startactivities (intents); }else {If the app process has been killed, restart the app and pass the detailactivity's startup parameters into the intent, with the parameters//splashactivity incoming mainactivity, this time the app initialization is complete, in mainactivity can be based on the incoming// Parameters jump to Detailactivity log.i ( "Notificationreceiver", "the app Process is dead "); Intent launchintent = Context.getpackagemanager (). Getlaunchintentforpackage ( "Com.liangzili.notificationlaunch"); Launchintent.setflags ( Intent.flag_activity_new_task | intent.flag_activity_reset_task_if_needed); Bundle args = new Bundle (); Args.putstring ( "name", " rice cooker "); Args.putstring ( "price", "58 Yuan"); Args.putstring (" detail ", " This is a good pot, this is the app process does not exist, first start the application and then start the activity "); Launchintent.putextra (Constants.extra_bundle, args); Context.startactivity (launchintent); } }}
Splashactivity.java
Splashactivity.java first the app to start the picture, 3s into the mainactivity, if the start splashactivity intent with parameters, will be taken out of the parameters, into the mainactivity of the start intent
PublicClassSplashactivityExtendsappcompatactivity{@OverrideProtectedvoidOnCreate(Bundle savedinstancestate) {Super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_splash);Hide Actionbar Getsupportactionbar (). Hide ();//use Handler countdown 3 seconds after entering mainactivity new Handler (). postdelayed ( Span class= "Hljs-keyword" >new Runnable () { @Override < Span class= "Hljs-keyword" >public void run () {Intent Intent = new Intent (Splashactivity.this, Mainactivity.class); //if you start the app with an extra parameter in the intent, it means that the app is //the parameter out, Passed to mainactivity in if (Getintent (). Getbundleextra (constants.extra_bundle)! = null) {Intent.putextra (Constants.extra_bundle, Getintent (). Getbundleextra (Constants.EXTRA_BUNDLE)) ; } startactivity (Intent); Finish (); }}, 3000); }}
Mainactivity.java
Mainactivity, if there are parameters passed in, after the initialization, starting detailactivity according to the parameters, if there are no parameters passed in, this ends their own task
PublicClassMainactivityExtendsappcompatactivity {PrivateStaticFinal String TAG ="Mainactivity";@OverrideProtectedvoidOnCreate(Bundle savedinstancestate) {Super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main); Intent Intent =New Intent (this, pushservice.class); StartService (Intent); Settitle ("Mainactivity"); Bundle bundle = Getintent (). Getbundleextra (Constants.extra_bundle);if (Bundle! =NULL) {If the bundle exists, take out the parameters and start detailactivity String name = bundle.getstring ("Name"); String Price = Bundle.getstring ("Price"); String detail = bundle.getstring ("Detail"); Systemutils.startdetailactivity (This, name, price, detail); LOG.I (TAG,"Launchparam exists, redirect to Detailactivity"); } }@OverrideProtectedvoidOnresume() {Super.onresume (); }@OverridePublicBooleanOncreateoptionsmenu(Menu menu) {Inflate the menu; This adds items to the action bar if it is present. Getmenuinflater (). Inflate (R.menu.menu_main, menu);Returntrue;} @Override public boolean onoptionsitemselected (MenuItem item) { //Handle Action Bar item clicks here. The action Bar would //automatically handle clicks on the Home/up button, so long //as you specify a parent activity in Androidmanifest.xml. int id = item.getitemid (); //noinspection simplifiableifstatement if (id = = R.id.action_ Settings) {return true;} return super.onoptionsitemselected (item);}}
Detailactivity.java
Simple, show incoming parameters:-D
PublicClassDetailactivityextends appcompatactivity{@ Override protected void oncreate (Bundle savedinstancestate) { Super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_detail); Getsupportactionbar (). Settitle ( "detailactivity"); String name = Getintent (). Getstringextra ( "name"); String Price = Getintent (). Getstringextra ( "detail"); ((TextView) Findviewbyid (R.id.name)). SetText (name); ((TextView) Findviewbyid (R.id.price)). SetText (price); ((TextView) Findviewbyid (R.id.detail)). SetText (detail); }}
Android Implementation click the Notification bar, start the app before you open the target activity