内容简介:在运行代码,点击
在 MainActivity
中增加点击事件,用来启动 NotifyService
和延迟2秒销毁 MainActivity
,如下面代码所示
Intent intent = new Intent(MainActivity.this, NotifyService.class); startService(intent); tvTips.postDelayed(new Runnable() { @Override public void run() { finish(); } }, 2000L); 复制代码
NotifyService
类继承 IntentService
,并在 onHandleIntent()
方法类处理展示通知栏的逻辑,如下面代码所示
private void showNotification() { Notification notification; NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); //pendingIntent生成规则 Intent notifyIntent = new Intent(); notifyIntent.setClass(this, NotifyActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("0", "notify", NotificationManager.IMPORTANCE_DEFAULT); manager.createNotificationChannel(channel); Notification.Builder builder = new Notification.Builder(this, "0") .setAutoCancel(true) .setContentTitle(getString(R.string.app_name)) .setContentText("xxx") .setOnlyAlertOnce(true) .setSmallIcon(R.mipmap.ic_launcher) .setContentIntent(pendingIntent); notification = builder.build(); } else { NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setSmallIcon(R.mipmap.ic_launcher) .setContentText("xxx") .setAutoCancel(true) .setWhen(System.currentTimeMillis()) .setOnlyAlertOnce(true) .setContentTitle(getString(R.string.app_name)) .setContentIntent(pendingIntent); notification = builder.build(); } manager.notify(0, notification); } 复制代码
运行代码,点击 启动通知栏
按钮,此时会创建一个通知栏,并且2秒后,主页自动关闭。然后在点击 通知栏
,进入到 通知栏页面
,点击返回按钮时,发下APP没有回到主页面,而是回到了Launcher主页面。如下面截图所示
所以用 PendingIntent.getActivity
方式打开通知栏,就会出现上面所描述的问题。为了解决这问题,提供了一下几种方式。
用PendingIntent.getActivities创建通知栏
处理逻辑基本上跟上面一致,只需替换 pendingIntent生成规则
那部分代码,需替换的代码如下面所示
Intent notifyIntent = new Intent(); Intent mainIntent = new Intent(); notifyIntent.setClass(this, NotifyActivity.class); mainIntent.setClass(this, MainActivity.class); //需要注意这里的顺序 Intent[] intents = new Intent[]{mainIntent, notifyIntent}; PendingIntent pendingIntent = PendingIntent. getActivities(this, 0, intents, PendingIntent.FLAG_UPDATE_CURRENT); 复制代码
运行代码,如下面截图所示
此方法适用于 MainActivity
和 NotifyActivity
在同一个moudle的情况。如果不在同一个moudle又该如何处理呢?接着往下看。
用TaskStackBuilder创建通知栏
替换 pendingIntent生成规则
那部分代码,需替换的代码如下面所示
Intent notifyIntent = new Intent(); notifyIntent.setClass(this, NotifyActivity.class); TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); stackBuilder.addParentStack(NotifyActivity.class); stackBuilder.addNextIntent(notifyIntent); PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); 复制代码
除了替换 pendingIntent生成规则
之外,还需要修改 AndroidManifest.xml
内的代码,为 NotifyActivity
指定 parentActivityName
属性,如下面代码所示
<activity android:name=".NotifyActivity" android:parentActivityName=".MainActivity"/> 复制代码
该属性是在Android 4.1(API level 16)引入的,此处的名称必须与为相应 <activity>
元素的 android:name
属性指定的类名称一致,以确定当用户按下返回按钮时应该启动哪一个 Activity
。
运行代码,效果如图2所示
此方法可以适用于 Activity
在不同moudle的情况。
但是,当主页 MainActivity
(这里用A代表,方便后面描述)的 launchMode
设置为 singleTask
时,当主页 A
存在时,并且还打开了其他页面'OtherActivity'(B),目前Activity的栈的顺序是 A、B
。当打开用 PendingIntent.getActivities
和 TaskStackBuilder
两种方式创建的通知栏,页面跳转到 NotifyActivity
(C),并且一直按返回键,退栈的顺序是 C、A、Launcher
, B
却没在栈内了,见 图3
。具体原因是,当打开通知栏是,栈的顺序是 A、B、A
,由于 A
的 launchMode
是 singleTask
,此时会删除 B
,当整个通知栏操作全部完成时,Activity的栈的顺序是 A、C
,所以会出现上面描述的现象。如果要满足退栈顺序是 C、B、A、Launcher
该怎么实现?
用PendingIntent.getActivity创建通知栏,本地维护Activity栈
- 首先需要创建一个Activity管理类
ActivityManager
,来维护Activity栈,如下面代码所示
public class ActivityManager { private static final byte[] sLock = new byte[0]; private final Stack<Activity> mActivityStack = new Stack<>(); private static ActivityManager sInstance; public static ActivityManager getInstance() { if (sInstance == null) { synchronized (sLock) { if (sInstance == null) { sInstance = new ActivityManager(); } } } return sInstance; } private ActivityManager() { } /** * activity入栈 */ public void addActivity(Activity activity) { mActivityStack.add(activity); } /** * activity出栈 */ public void removeActivity(Activity activity) { mActivityStack.remove(activity); } /** * 当栈的个数为1的时候,判断cls是否在栈内 */ public boolean currentActivity(Class<?> cls) { if (mActivityStack.size() != 1) { return true; } for (Activity activity : mActivityStack) { if (activity.getClass().equals(cls)) { return true; } } return false; } } 复制代码
- 其次创建一个
Activity
的基类BaseActivity
,所有Activity
页面需要继承这个基类,并且分别在onCreate
和onDestroy
方法中分别实现Activity
的入栈和出栈操作,并且重写返回事件,如下面代码所示
public abstract class BaseActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityManager.getInstance().addActivity(this); } @Override public void onBackPressed() { super.onBackPressed(); if (!ActivityManager.getInstance().currentActivity(MainActivity.class)) { Intent intent = new Intent(BaseActivity.this, MainActivity.class); startActivity(intent); } } @Override protected void onDestroy() { super.onDestroy(); ActivityManager.getInstance().removeActivity(this); } } 复制代码
运行代码,如下面截图所示
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 回到未来:永恒的lisp
- Istiod——回到单体的理由
- [译] Istiod:回到单体的理由
- 用关系型 NoSQL 回到未来
- 回到基础:如何用原生 DOM API 生成表格
- 从Rails到Clojure再到Java,最后回到Rails
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The CS Detective: An Algorithmic Tale of Crime, Conspiracy, and
Jeremy Kubica / No Starch Press / 2016-8-15 / USD 13.74
Meet Frank Runtime. Disgraced ex-detective. Hard-boiled private eye. Search expert.When a robbery hits police headquarters, it's up to Frank Runtime and his extensive search skills to catch the culpri......一起来看看 《The CS Detective: An Algorithmic Tale of Crime, Conspiracy, and 》 这本书的介绍吧!