精华内容
下载资源
问答
  • Android通知栏权限是否开启
    2021-06-07 10:55:21

    通知栏权限是否开启

    需要分系统版本来操作

    4.4版本一下不处理,4.4到8.0,8.0以上

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)

    public static boolean isNotificationEnabled(Context context) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

    //8.0手机以上

    if (((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).getImportance() == NotificationManager.IMPORTANCE_NONE) {

    return false;

    }

    }

    String CHECK_OP_NO_THROW = "checkOpNoThrow";

    String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";

    AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);

    ApplicationInfo appInfo = context.getApplicationInfo();

    String pkg = context.getApplicationContext().getPackageName();

    int uid = appInfo.uid;

    Class appOpsClass = null;

    try {

    appOpsClass = Class.forName(AppOpsManager.class.getName());

    Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE,

    String.class);

    Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);

    int value = (Integer) opPostNotificationValue.get(Integer.class);

    return ((Integer) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == AppOpsManager.MODE_ALLOWED);

    } catch (Exception e) {

    e.printStackTrace();

    }

    return false;

    }

    跳转到手机设置界面:

    fun toSetting(activity: Activity, requestCode: Int) {

    val intent = Intent()

    intent.action = "android.settings.APPLICATION_DETAILS_SETTINGS"

    intent.data = Uri.fromParts("package", activity.packageName, null)

    activity.startActivityForResult(intent, requestCode)

    }

    设置界面返回处理:

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

    super.onActivityResult(requestCode, resultCode, data)

    if (requestCode == 101) {

    if (PermissionsUtil.isNotificationEnabled(mActivity!!) ) {

    ViewUtils.visibility(card_view_notification_status,false)

    }

    }

    }

    如果解决问题,是不是要打赏一波呢

    更多相关内容
  • 最常见的表现形式就是音乐播放服务,应用程序后台运行时,用户可以通过通知栏,知道当前播放内容,并进行暂停、继续、切歌等相关操作。 二、为什么使用前台服务 后台运行的Service系统优先级相对较低,当系统内存...
  • android 通知栏跳转

    2016-09-03 23:53:19
    通知栏接受消息跳转到相应的界面的处理
  • Android通知栏消息、点亮屏幕、震动、声音、显示样式的小例子。
  • 这个是通知栏框架(Notificaiton)的全面学习,里面把大概所有的情况都列了出来,通过一个DEMO让你了解它的大致所有使用过程。 可以通过以下博文进行配套了解(有效果图): ...
  • Android通知栏拦获微信消息
  • 通知栏内更新,下载完成自动安装并清除消息通知,已修改测试,可直接用于项目
  • 本篇文章是对Android消息通知栏的实现方法进行了详细的分析介绍,需要的朋友参考下
  • 主要介绍了android通知栏的实现方法,结合实例形式分析了系统Notification及自定义Notification两种实现技巧与相关操作步骤,需要的朋友可以参考下
  • Andoid解决通知栏图标显示小黑块以及 8.0以上版本的适配和多个版本的通知栏开启状态判断。
  • 主要介绍了关于解决Android中点击通知栏的通知启动Activity问题的相关资料,文中介绍的非常详细,对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。
  • 这几天做一个小软件在API28(Android 9.0)的模拟器上测试时,发现通知栏无效,经过一番查询,了解到:API26(Android 8.0)以后,引入了**通知渠道(Notification Channels)**这么一个东西来帮助用户管理通知。...
  • 主要为大家详细介绍了Android使用Notification实现普通通知栏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 主要介绍了android实现常驻通知栏遇到的问题及解决办法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
  • android 通知栏样式_Android通知样式

    千次阅读 2020-07-06 12:54:52
    android 通知栏样式We’ve discussed and implemented basic Notifications in this post. In this tutorial, we’ll be looking into more advanced features of android notification and styling our ...

    android 通知栏样式

    We’ve discussed and implemented basic Notifications in this post. In this tutorial, we’ll be looking into more advanced features of android notification and styling our notifications in different ways.

    我们已经讨论并实现基本声明文章。 在本教程中,我们将研究android通知的更高级功能,并以不同方式设置通知样式。

    Android通知样式 (Android Notification Styling)

    Android Notification have plenty of powerful features that when used correctly would significantly improve the UX and user engagement. Some noteworthy features that we’ll be covering in this Android Notification tutorial are listed below.

    Android Notification具有许多强大的功能,如果正确使用它们,将大大提高用户体验和用户参与度。 下面列出了我们将在本Android Notification教程中介绍的一些值得注意的功能。

    1. Notification Actions

      通知动作
    2. Heads Up Notification

      抬头通知
    3. Big Text Style Notification

      大文字样式通知
    4. Big Picture Style Notification

      大图样式通知
    5. Inbox Style Notification

      收件箱样式通知
    6. Message Style Notification

      邮件样式通知

    Android notification consists of three major components:

    Android通知包含三个主要组件:

    1. Small Icon (often our app logo)

      小图标(通常是我们的应用徽标)
    2. Title

      标题
    3. Content Text

      内容文字

    The introduction of Android Nougat (API 24) has given a new look to notifications as shown below.

    Android Nougat(API 24)的引入使通知有了新外观,如下所示。

    The large icon now appears on the right. There’s an arrow besides the notification title that lets us expand, collapse the notification.

    现在,大图标出现在右侧。 通知标题旁边有一个箭头,可让我们展开,折叠通知。

    In this tutorial, we’ll be styling our notifications using some pre-defined awesome styles that Android has in store for us. We’ll be covering the following features at length.

    在本教程中,我们将使用Android为我们提供的一些预定义超赞样式来设置通知的样式。 我们将详细介绍以下功能。

    1. Android Notification Actions

      Android通知动作
    2. Heads Up Notifications

      抬头通知
    3. Rich Notifications

      丰富的通知

    Android通知动作 (Android Notification Actions)

    Android Notification actions are basically buttons placed below the body of the notification. A Notification action must include an icon, a label, and a PendingIntent to be fired when the action is selected by the user.

    Android Notification动作基本上是位于通知主体下方的按钮。 通知动作必须包含一个图标,一个标签以及一个当用户选择该动作时要触发的PendingIntent

    With the Introduction of Android N, the icons are omitted from the action buttons to give space to other components.

    随着Android N的介绍,操作按钮中的图标被省略,以留出空间给其他组件。

    An example of notification actions in Pre Nougat devices is given below.

    牛轧糖前设备中的通知操作示例如下。

    android notification before android N

    Pre-Nougat Notification Action Design

    牛轧糖前通知动作设计

    An example of Notification Actions in Android N and above is given below.

    以下是Android N及更高版本中的通知操作示例。

    android notification tutorial

    Notification Action in Android Nougat

    Android Nougat中的通知动作

    抬头通知 (Heads Up Notifications)

    With the introduction of Android Lollipop (API level 21), notifications can appear in a small floating window (also called a heads-up notification) when the device is active (that is, the device is unlocked and its screen is on).

    随着Android Lollipop(API级别21)的引入,当设备处于活动状态(即设备已解锁且屏幕处于打开状态)时,通知可以显示在一个小的浮动窗口中(也称为平视通知)。

    Such type of notifications are commonly seen when you’re using an application and you get a call. A small floating notification known as heads up notifications pops up with the notification actions to accept or decline a call.

    当您使用应用程序并接到电话时,通常会看到此类通知。 一个小的浮动通知(称为抬头通知)随通知动作弹出,以接听或拒绝呼叫。

    丰富的通知 (Rich Notifications)

    Android allows us to add rich styles to our application with the introduction of Android L. Using these styles would make the notification look more appealing than ever. Some of the known styles that are used in many applications are listed below and are self-explanatory.

    Android允许我们通过引入Android L向我们的应用程序添加丰富的样式。使用这些样式将使通知看起来比以往更具吸引力。 下面列出了许多应用程序中使用的一些已知样式,这些样式是不言自明的。

    • BigTextStyle

      BigTextStyle
    • BigPictureStyle

      BigPictureStyle
    • InboxStyle

      InboxStyle
    • MessageStyle

      MessageStyle

    We know that notifications on Android N can be expanded using the arrows. To expand notifications on pre-Nougat versions, you can swipe down over the notification using two fingers.

    我们知道可以使用箭头扩展Android N上的通知。 要扩展牛轧糖之前版本的通知,您可以用两根手指在通知上向下滑动。

    Not all Android versions would support the above styles. In case an Android OS doesn’t support the rich style, that style would simply be ignored.

    并非所有的Android版本都支持上述样式。 如果Android操作系统不支持丰富样式,则该样式将被忽略。

    Now let’s jump into the business end of this tutorial and develop an application that’ll have all the above features.

    现在,让我们进入本教程的业务范围,并开发一个具有上述所有功能的应用程序。

    Android Notification Tutorial项目结构 (Android Notification Tutorial Project Structure)

    Android通知教程代码 (Android Notification Tutorial Code)

    The code for the activity_main.xml is given below:

    下面给出了activity_main.xml的代码:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
        xmlns:app="https://schemas.android.com/apk/res-auto"
        xmlns:tools="https://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.journaldev.stylingnotifications.MainActivity">
    
        <Button
            android:id="@+id/btnNotificationActions"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="NOTIFICATION ACTIONS"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.196" />
    
        <Button
            android:id="@+id/btnHeadsUp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginTop="8dp"
            android:text="HEADS UP NOTIFICATION"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/btnNotificationActions" />
    
        <Button
            android:id="@+id/btnBigTextStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="BIG TEXT STYLE"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            android:layout_marginTop="8dp"
            app:layout_constraintTop_toBottomOf="@+id/btnHeadsUp" />
    
        <Button
            android:id="@+id/btnBigPictureStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="BIG PICTURE STYLE"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            android:layout_marginTop="8dp"
            app:layout_constraintTop_toBottomOf="@+id/btnBigTextStyle" />
    
        <Button
            android:id="@+id/btnInboxStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="INBOX STYLE"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            android:layout_marginTop="8dp"
            app:layout_constraintTop_toBottomOf="@+id/btnBigPictureStyle" />
    
        <Button
            android:id="@+id/btnMessageStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="MESSAGE STYLE"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            android:layout_marginTop="8dp"
            app:layout_constraintTop_toBottomOf="@+id/btnInboxStyle" />
    
    </android.support.constraint.ConstraintLayout>

    We’ve added a button for each type of notification that we’ll be discussing.

    我们为将要讨论的每种通知类型添加了一个按钮。

    The skeleton code for the MainActivity.java is given below.

    MainActivity.java的框架代码如下。

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        Button btnNotificationActions, btnHeadsUpNotification, btnBigTextStyle, btnBigPictureStyle,
                btnInboxStyle, btnMessageStyle;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            clearNotification();
    
            btnNotificationActions = (Button) findViewById(R.id.btnNotificationActions);
            btnHeadsUpNotification = (Button) findViewById(R.id.btnHeadsUp);
            btnBigTextStyle = (Button) findViewById(R.id.btnBigTextStyle);
            btnBigPictureStyle = (Button) findViewById(R.id.btnBigPictureStyle);
            btnInboxStyle = (Button) findViewById(R.id.btnInboxStyle);
            btnMessageStyle = (Button) findViewById(R.id.btnMessageStyle);
            btnNotificationActions.setOnClickListener(this);
            btnHeadsUpNotification.setOnClickListener(this);
            btnBigTextStyle.setOnClickListener(this);
            btnBigPictureStyle.setOnClickListener(this);
            btnInboxStyle.setOnClickListener(this);
            btnMessageStyle.setOnClickListener(this);
    
        }
    
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btnNotificationActions:
                    notificationActions();
                    break;
                case R.id.btnHeadsUp:
                    headsUpNotification();
                    break;
                case R.id.btnBigTextStyle:
                    bigTextStyleNotification();
                    break;
                case R.id.btnBigPictureStyle:
                    bigPictureStyleNotification();
                    break;
                case R.id.btnInboxStyle:
                    inboxStyleNotification();
                    break;
                case R.id.btnMessageStyle:
                    messageStyleNotification();
                    break;
    
            }
        }
    
    
       public PendingIntent getLaunchIntent(int notificationId, Context context) {
    
            Intent intent = new Intent(context, MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            intent.putExtra("notificationId", notificationId);
            return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        }
    
    
        private void clearNotification() {
            int notificationId = getIntent().getIntExtra("notificationId", 0);
    
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.cancel(notificationId);
        }
    
      private void notificationActions()
      {
       //Logic goes here.
      }
    
      private void headsUpNotification()
      {
       //Logic goes here.
      }
    
      private void bigTextStyleNotification()
      {
       //Logic goes here.
      }
    
      private void bigPictureStyleNotification();
      {
       //Logic goes here.
      }
    
      private void inboxStyleNotification()
      {
       //Logic goes here.
      }
    
      private void messageStyleNotification()
      {
       //Logic goes here.
      }
    }

    The method clearNotification() is used to clear any existing notifications from the notification bar.
    The method getLaunchIntent() returns an instance of PendingIntent which when triggered from the notification, will relaunch the application.

    方法clearNotification()用于清除通知栏中的所有现有通知。
    方法getLaunchIntent()返回PendingIntent的实例,当从通知中触发该实例时,它将重新启动应用程序。

    Before we delve into the implementation of each type of notification, let’s define the BroadcastReceiver as shown below.

    在深入研究每种通知的实现之前,让我们定义如下的BroadcastReceiver

    package com.journaldev.stylingnotifications;
    
    import android.app.NotificationManager;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    
    public class NotificationReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
    
            int notificationId = intent.getIntExtra("notificationId", 0);
    
            NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            manager.cancel(notificationId);
        }
    }

    Update the AndroidManifest.xml file with the receiver defined as shown below.

    使用定义如下的接收器更新AndroidManifest.xml文件。

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="https://schemas.android.com/apk/res/android"
        package="com.journaldev.stylingnotifications">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
    
            <receiver android:name=".NotificationReceiver"
                android:exported="false"/>
    
    
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
    
        </application>
    
    </manifest>

    在通知中添加动作 (Adding actions inside a notification)

    private void notificationActions() {
    
            int NOTIFICATION_ID = 1;
    
    
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.jd);
            builder.setColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.jd));
            builder.setContentTitle("Notification Actions");
            builder.setContentText("Tap View to launch our website");
            builder.setAutoCancel(true);
            PendingIntent launchIntent = getLaunchIntent(NOTIFICATION_ID, getBaseContext());
    
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.journaldev.com"));
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    
            Intent buttonIntent = new Intent(getBaseContext(), NotificationReceiver.class);
            buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
            PendingIntent dismissIntent = PendingIntent.getBroadcast(getBaseContext(), 0, buttonIntent, 0);
    
            builder.setContentIntent(launchIntent);
            builder.addAction(android.R.drawable.ic_menu_view, "VIEW", pendingIntent);
            builder.addAction(android.R.drawable.ic_delete, "DISMISS", dismissIntent);
    
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
            // Will display the notification in the notification bar
            notificationManager.notify(NOTIFICATION_ID, builder.build());
        }

    In the above code, we set the various styles on the instance builder.

    在上面的代码中,我们在实例builder上设置了各种样式。

    setColor() sets the custom color for the notification icon, title and action button texts.

    setColor()设置通知图标,标题和操作按钮文本的自定义颜色。

    addAction() is used to set the action buttons beneath the notification content. It expects three params: icon, text and the instance of PendingIntent.

    addAction()用于在通知内容下方设置操作按钮。 它需要三个参数:图标,文本和PendingIntent实例。

    setContentIntent() sets the PendingIntent that’ll be triggered when the body of the notification is clicked. In the above code we’ve simply added the PendingIntent to relaunch the application.

    setContentIntent()设置单击通知正文时将触发的PendingIntent。 在上面的代码中,我们仅添加了PendingIntent以重新启动该应用程序。

    setAutoCancel(true) is used to dismiss the notification when its clicked.

    setAutoCancel(true)用于在单击通知时关闭该通知。

    NotificationManager class is used to display the notification.

    NotificationManager类用于显示通知。

    The output of the application when the above type of notification is triggered is given below.

    android notification example

    下面给出了触发上述类型的通知时应用程序的输出。

    Note:

    注意事项

    • When the VIEW button is clicked, the url is launched in the browser but the notification isn’t dismissed.

      单击“查看”按钮时,URL将在浏览器中启动,但不会关闭通知。
    • When the DISMISS button is clicked the notification is cleared but the notification tray stays open.

      单击“ DISMISS”按钮时,通知已清除,但通知托盘保持打开状态。
    • When the Notification content is clicked, the notification is dismissed as well as the activity is re-launched. This is where getLaunchIntent() and clearNotification() methods are invoked.

      单击通知内容后,该通知将被取消,并且该活动将重新启动。 这是调用getLaunchIntent()clearNotification()方法的地方。

    实施抬头通知 (Implementing Heads Up Notification)

    private void headsUpNotification() {
    
            int NOTIFICATION_ID = 1;
            NotificationCompat.Builder builder =
                    new NotificationCompat.Builder(this)
                            .setSmallIcon(R.drawable.jd)
                            .setContentTitle("Heads Up Notification")
                            .setContentText("View the latest Swift Tutorial")
                            .setAutoCancel(true)
                            .setDefaults(NotificationCompat.DEFAULT_ALL)
                            .setPriority(NotificationCompat.PRIORITY_HIGH);
    
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.journaldev.com/15126/swift-function"));
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    
            Intent buttonIntent = new Intent(getBaseContext(), NotificationReceiver.class);
            buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
            PendingIntent dismissIntent = PendingIntent.getBroadcast(getBaseContext(), 0, buttonIntent, 0);
    
            builder.addAction(android.R.drawable.ic_menu_view, "VIEW", pendingIntent);
            builder.addAction(android.R.drawable.ic_delete, "DISMISS", dismissIntent);
    
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            notificationManager.notify(NOTIFICATION_ID, builder.build());
        }

    To set a notification as heads up notification, two properties need to set on the builder instance.

    要将通知设置为抬头通知,需要在构建器实例上设置两个属性。

    setDefaults(NotificationCompat.DEFAULT_ALL)
    setPriority(NotificationCompat.PRIORITY_HIGH)

    Swiping a heads up notification would dismiss it. If it’s not dismissed, the heads-up notifications will fade away and change into a standard notification in the status bar.

    刷单向通知会取消该通知。 如果未取消,则抬头通知将消失,并在状态栏中变为标准通知。

    The output of heads up notification is given below.

    android notification heads up

    抬头通知的输出如下。

    BigTextStyle通知 (BigTextStyle Notification)

    private void bigTextStyleNotification() {
            int NOTIFICATION_ID = 1;
    
            PendingIntent launchIntent = getLaunchIntent(NOTIFICATION_ID, getBaseContext());
            Intent buttonIntent = new Intent(getBaseContext(), NotificationReceiver.class);
            buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
            PendingIntent dismissIntent = PendingIntent.getBroadcast(getBaseContext(), 0, buttonIntent, 0);
    
    
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.jd);
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.jd));
            builder.setContentTitle("Big Text Style");
            builder.setStyle(new NotificationCompat.BigTextStyle().bigText(getResources().getString(R.string.lorem_ipsum)));
            builder.setAutoCancel(true);
            builder.setContentIntent(launchIntent);
            builder.addAction(android.R.drawable.ic_delete, "DISMISS", dismissIntent);
            builder.addAction(android.R.drawable.ic_menu_send, "OPEN APP", launchIntent);
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
            // Will display the notification in the notification bar
            notificationManager.notify(NOTIFICATION_ID, builder.build());
        }

    A notification can be customised into a big text style notification by setting the style as
    NotificationCompat.BigTextStyle(). The string to be displayed is entered inside the method bigText().

    通过将样式设置为,可以将通知定制为大文本样式通知
    NotificationCompat.BigTextStyle() 。 要显示的字符串在方法bigText()中输入。

    The output of above type of notification is given below.

    android notification big text style

    上述通知的输出如下。

    BigPictureStyle通知 (BigPictureStyle Notification)

    private void bigPictureStyleNotification() {
            int NOTIFICATION_ID = 1;
            Bitmap pic = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
    
            Intent buttonIntent = new Intent(getBaseContext(), NotificationReceiver.class);
            buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
            PendingIntent dismissIntent = PendingIntent.getBroadcast(getBaseContext(), 0, buttonIntent, 0);
            PendingIntent launchIntent = getLaunchIntent(NOTIFICATION_ID, getBaseContext());
    
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.jd);
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.jd));
            builder.setContentTitle("Big Picture Style");
            builder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(pic));
            builder.setAutoCancel(true);
            builder.setContentIntent(launchIntent);
            builder.addAction(android.R.drawable.ic_delete, "DISMISS", dismissIntent);
    
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
            // Will display the notification in the notification bar
            notificationManager.notify(NOTIFICATION_ID, builder.build());
        }

    For BigPicture to be displayed inside a notification the style is set as NotificationCompat.BigPictureStyle().bigPicture(bitmap)).

    为了使BigPicture显示在通知中,样式设置为NotificationCompat.BigPictureStyle().bigPicture(bitmap))

    The output with the above type of notification is given below.

    android notification custom style big picture

    具有上述通知类型的输出如下。

    InboxStyle通知 (InboxStyle Notification)

    private void inboxStyleNotification() {
            int NOTIFICATION_ID = 1;
    
            PendingIntent launchIntent = getLaunchIntent(NOTIFICATION_ID, getBaseContext());
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.jd);
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.jd));
            builder.setStyle(new NotificationCompat.InboxStyle().addLine("Hello").addLine("Are you there?").addLine("How's your day?").setBigContentTitle("3 New Messages for you").setSummaryText("Inbox"));
            builder.setAutoCancel(true);
            builder.setContentIntent(launchIntent);
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
            // Will display the notification in the notification bar
            notificationManager.notify(NOTIFICATION_ID, builder.build());
        }

    An inbox style notification is set by using the style new NotificationCompat.InboxStyle().
    Each message is placed inside the method addLine(). The summary text of all the messages is placed inside the method setSummaryText().
    setContentTitle() is replaced with setBigContentTitle() in this style

    收件箱样式通知是通过使用样式new NotificationCompat.InboxStyle()
    每个消息都放在方法addLine() 。 所有消息的摘要文本都放在方法setSummaryText()
    setContentTitle()以此样式替换为setBigContentTitle()

    The output of the above type of notification is given below

    custom android notification inbox style

    上述通知的输出如下

    邮件样式通知 (Message Style Notification)

    Message Style is introduced with Android N. Typically used for chats.

    消息样式是Android N引入的。通常用于聊天。

    private void messageStyleNotification() {
            int NOTIFICATION_ID = 1;
    
            PendingIntent launchIntent = getLaunchIntent(NOTIFICATION_ID, getBaseContext());
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.jd);
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.jd));
            builder.setContentTitle("Messages");
            builder.setStyle(new NotificationCompat.MessagingStyle("Teacher").setConversationTitle("Q&A Group")
                    .addMessage("This type of notification was introduced in Android N. Right?",0,"Student 1")
                    .addMessage("Yes",0,null)
                    .addMessage("The constructor is passed with the name of the current user. Right?",0,"Student 2")
                    .addMessage("True",0,null));
            builder.setAutoCancel(true);
            builder.setContentIntent(launchIntent);
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
            // Will display the notification in the notification bar
            notificationManager.notify(NOTIFICATION_ID, builder.build());
        }

    In the above code NotificationCompat.MessagingStyle(String) contains a string that represents the current user(Typically in a chat its you!).
    Each message is added in the method addMessage() with the timestamp as well as sender name.
    If the sender name is set to null it signifies that the message is from the current user(you) and the name is taken from the constructor.

    在上面的代码中, NotificationCompat.MessagingStyle(String)包含一个表示当前用户的字符串(通常在聊天中是您!)。
    每条消息都将在方法addMessage()中添加时间戳和发件人名称。
    如果发件人名称设置为null,则表示该消息来自当前用户(您),并且该名称来自构造函数。

    The output of the above type of notification is given below.

    android message style notification

    上述通知的输出如下。

    Adding all the above methods in the MainActivity.java would give us the below code.

    MainActivity.java添加上述所有方法将为我们提供以下代码。

    package com.journaldev.stylingnotifications;
    
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.support.v4.app.NotificationCompat;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        Button btnNotificationActions, btnHeadsUpNotification, btnBigTextStyle, btnBigPictureStyle,
                btnInboxStyle, btnMessageStyle;
    
        NotificationCompat.Builder builder;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            clearNotification();
    
            btnNotificationActions = (Button) findViewById(R.id.btnNotificationActions);
            btnHeadsUpNotification = (Button) findViewById(R.id.btnHeadsUp);
            btnBigTextStyle = (Button) findViewById(R.id.btnBigTextStyle);
            btnBigPictureStyle = (Button) findViewById(R.id.btnBigPictureStyle);
            btnInboxStyle = (Button) findViewById(R.id.btnInboxStyle);
            btnMessageStyle = (Button) findViewById(R.id.btnMessageStyle);
            btnNotificationActions.setOnClickListener(this);
            btnHeadsUpNotification.setOnClickListener(this);
            btnBigTextStyle.setOnClickListener(this);
            btnBigPictureStyle.setOnClickListener(this);
            btnInboxStyle.setOnClickListener(this);
            btnMessageStyle.setOnClickListener(this);
    
        }
    
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btnNotificationActions:
                    notificationActions();
                    break;
                case R.id.btnHeadsUp:
                    headsUpNotification();
                    break;
                case R.id.btnBigTextStyle:
                    bigTextStyleNotification();
                    break;
                case R.id.btnBigPictureStyle:
                    bigPictureStyleNotification();
                    break;
                case R.id.btnInboxStyle:
                    inboxStyleNotification();
                    break;
                case R.id.btnMessageStyle:
                    messageStyleNotification();
                    break;
    
            }
        }
    
        private void notificationActions() {
    
            int NOTIFICATION_ID = 1;
    
    
            builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.jd);
            builder.setColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.jd));
            builder.setContentTitle("Notification Actions");
            builder.setContentText("Tap View to launch our website");
            builder.setAutoCancel(true);
            PendingIntent launchIntent = getLaunchIntent(NOTIFICATION_ID, getBaseContext());
    
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.journaldev.com"));
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    
            Intent buttonIntent = new Intent(getBaseContext(), NotificationReceiver.class);
            buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
            PendingIntent dismissIntent = PendingIntent.getBroadcast(getBaseContext(), 0, buttonIntent, 0);
    
            builder.setContentIntent(launchIntent);
            builder.addAction(android.R.drawable.ic_menu_view, "VIEW", pendingIntent);
            builder.addAction(android.R.drawable.ic_delete, "DISMISS", dismissIntent);
    
            buildNotification(NOTIFICATION_ID);
        }
    
        public PendingIntent getLaunchIntent(int notificationId, Context context) {
    
            Intent intent = new Intent(context, MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            intent.putExtra("notificationId", notificationId);
            return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        }
    
    
        private void clearNotification() {
            int notificationId = getIntent().getIntExtra("notificationId", 0);
    
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.cancel(notificationId);
        }
    
        private void headsUpNotification() {
    
            int NOTIFICATION_ID = 1;
            builder =
                    new NotificationCompat.Builder(this)
                            .setSmallIcon(R.drawable.jd)
                            .setContentTitle("Heads Up Notification")
                            .setContentText("View the latest Swift Tutorial")
                            .setAutoCancel(true)
                            .setDefaults(NotificationCompat.DEFAULT_ALL)
                            .setPriority(NotificationCompat.PRIORITY_HIGH);
    
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.journaldev.com/15126/swift-function"));
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    
            Intent buttonIntent = new Intent(getBaseContext(), NotificationReceiver.class);
            buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
            PendingIntent dismissIntent = PendingIntent.getBroadcast(getBaseContext(), 0, buttonIntent, 0);
    
            builder.addAction(android.R.drawable.ic_menu_view, "VIEW", pendingIntent);
            builder.addAction(android.R.drawable.ic_delete, "DISMISS", dismissIntent);
    
            buildNotification(NOTIFICATION_ID);
        }
    
        private void bigTextStyleNotification() {
            int NOTIFICATION_ID = 1;
    
            PendingIntent launchIntent = getLaunchIntent(NOTIFICATION_ID, getBaseContext());
            Intent buttonIntent = new Intent(getBaseContext(), NotificationReceiver.class);
            buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
            PendingIntent dismissIntent = PendingIntent.getBroadcast(getBaseContext(), 0, buttonIntent, 0);
    
    
            builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.jd);
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.jd));
            builder.setContentTitle("Big Text Style");
            builder.setStyle(new NotificationCompat.BigTextStyle().bigText(getResources().getString(R.string.lorem_ipsum)));
            builder.setAutoCancel(true);
            builder.setContentIntent(launchIntent);
            builder.addAction(android.R.drawable.ic_delete, "DISMISS", dismissIntent);
            builder.addAction(android.R.drawable.ic_menu_send, "OPEN APP", launchIntent);
    
            buildNotification(NOTIFICATION_ID);
        }
    
        private void bigPictureStyleNotification() {
            int NOTIFICATION_ID = 1;
    
            Bitmap pic = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
    
    
            Intent buttonIntent = new Intent(getBaseContext(), NotificationReceiver.class);
            buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
            PendingIntent dismissIntent = PendingIntent.getBroadcast(getBaseContext(), 0, buttonIntent, 0);
            PendingIntent launchIntent = getLaunchIntent(NOTIFICATION_ID, getBaseContext());
    
    
            builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.jd);
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.jd));
            builder.setContentTitle("Big Picture Style");
            builder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(pic));
            builder.setAutoCancel(true);
            builder.setContentIntent(launchIntent);
            builder.addAction(android.R.drawable.ic_delete, "DISMISS", dismissIntent);
    
            buildNotification(NOTIFICATION_ID);
        }
    
        private void inboxStyleNotification() {
            int NOTIFICATION_ID = 1;
    
            PendingIntent launchIntent = getLaunchIntent(NOTIFICATION_ID, getBaseContext());
            builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.jd);
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.jd));
            builder.setContentTitle("Messages");
            builder.setStyle(new NotificationCompat.InboxStyle().addLine("Hello").addLine("Are you there?").addLine("How's your day?").setBigContentTitle("3 New Messages for you").setSummaryText("Inbox"));
            builder.setAutoCancel(true);
            builder.setContentIntent(launchIntent);
            
            buildNotification(NOTIFICATION_ID);
        }
    
        private void messageStyleNotification() {
            int NOTIFICATION_ID = 1;
    
            PendingIntent launchIntent = getLaunchIntent(NOTIFICATION_ID, getBaseContext());
            builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.jd);
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.jd));
            builder.setContentTitle("Messages");
            builder.setStyle(new NotificationCompat.MessagingStyle("Teacher").setConversationTitle("Q&A Group")
                    .addMessage("This type of notification was introduced in Android N. Right?", 0, "Student 1")
                    .addMessage("Yes", 0, null)
                    .addMessage("The constructor is passed with the name of the current user. Right?", 0, "Student 2")
                    .addMessage("True", 0, null));
            builder.setAutoCancel(true);
            builder.setContentIntent(launchIntent);
    
            buildNotification(NOTIFICATION_ID);
        }
    
        private void buildNotification(int NOTIFICATION_ID) {
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
            // Will display the notification in the notification bar
            notificationManager.notify(NOTIFICATION_ID, builder.build());
        }
    }

    This brings an end to android notification tutorial. We’ve styled our notifications in some interesting ways. You can download the final Android notification example project from the link below.

    这结束了android通知教程。 我们以一些有趣的方式设置了通知的样式。 您可以从下面的链接下载最终的Android通知示例项目

    Reference: Official Doc

    参考: 官方文件

    翻译自: https://www.journaldev.com/15468/android-notification-styling

    android 通知栏样式

    展开全文
  • Android通知栏微技巧,8.0系统中通知栏的适配

    万次阅读 多人点赞 2018-04-17 07:39:11
    大家好,今天我们继续来学习Android 8.0系统的适配。...在上一篇文章当中,我们学习了Android 8.0系统应用图标的适配,那么本篇文章,我们自然要将重点放在通知栏上面了,学习一下Android 8.0系统的通知栏适配

    转载请注明出处:https://blog.csdn.net/guolin_blog/article/details/79854070

    本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每个工作日都有文章更新。

    大家好,今天我们继续来学习Android 8.0系统的适配。

    之前我们已经讲到了,Android 8.0系统最主要需要进行适配的地方有两处:应用图标和通知栏。在上一篇文章当中,我们学习了Android 8.0系统应用图标的适配,还没有看过这篇文章的朋友可以先去阅读 Android应用图标微技巧,8.0系统中应用图标的适配

    那么本篇文章,我们自然要将重点放在通知栏上面了,学习一下Android 8.0系统的通知栏适配。

    其实在8.0系统之前,还有一次通知栏变动比较大的版本,就是5.0系统。关于5.0系统需要对通知栏进行适配的内容,我也整理了一篇文章,感兴趣的朋友可以去阅读 Android通知栏微技巧,那些你所没关注过的小细节

    那么下面我们就开始进入本篇文章的正题。


    为什么要进行通知栏适配?

    不得不说,通知栏真是一个让人又爱又恨的东西。

    通知栏是Android系统原创的一个功能,虽说乔布斯一直认为Android系统是彻彻底底抄袭iOS的一个产品,但是通知栏确实是Android系统原创的,反而苹果在iOS 5之后也加入了类似的通知栏功能。

    通知栏的设计确实非常巧妙,它默认情况下不占用任何空间,只有当用户需要的时候用手指在状态栏上向下滑动,通知栏的内容才会显示出来,这在智能手机发展的初期极大地解决了手机屏幕过小,内容展示区域不足的问题。

    可是随着智能手机发展的逐渐成熟,通知栏却变得越来越不讨人喜欢了。各个App都希望能抢占通知栏的空间,来尽可能地宣传和推广自己的产品。现在经常是早上一觉醒来拿起手机一看,通知栏上全是各种APP的推送,不胜其烦。

    我个人虽然是Android应用开发者,但同时也是Android手机的资深用户。我已经使用了8年的Android手机,目前我对于通知栏的这种垃圾推送是零容忍的。现在每当我安装一个新的App时,我都会先到设置里面去找一找有没有推送开关,如果有的话我会第一时间把它关掉。而如果一个App经常给我推送垃圾信息却又无法关闭时,我会直接将它的通知总开关给关掉,如果还不是什么重要的App的话,那么我可能就直接将它卸载掉了。

    为什么一个很好的通知栏功能现在却变得这么遭用户讨厌?很大一部分原因都是因为开发者没有节制地使用导致的。就好像App保活一样,直到今天还是不断有人问我该如何保活App,试想如何每个人都能保活自己的App,那么最终受害的人是谁?还不是使用Android手机的用户。大家的手机只会越来越卡,最后只想把手机丢掉,变成iPhone用户了。也是因为开发者没节制地使用,Android现在的每个版本都会不断收缩后台权限。

    回到通知栏上也是一样,每个开发者都只想着尽可能地去宣传自己的App,最后用户的手机就乱得跟鸡窝一样了。但是通知栏又还是有用处的,比如我们收到微信、短信等消息的时候,确实需要通知栏给我们提醒。因此分析下来,通知栏目前最大的问题就是,无法让用户对感兴趣和不感兴趣的消息进行区分。就比如说,我希望淘宝向我推送卖家发货和物流的相关消息,但是我不想收到那些打折促销或者是让我去买衣服的这类消息。那么就目前来说,是没有办法对这些消息做区分的,我要么同意接受所有消息,要么就屏蔽所有消息,这是当前通知栏的痛点。

    那么在Android 8.0系统中,Google也是从这个痛点开始下手的。

    8.0系统的通知栏适配

    从Android 8.0系统开始,Google引入了通知渠道这个概念。

    什么是通知渠道呢?顾名思义,就是每条通知都要属于一个对应的渠道。每个App都可以自由地创建当前App拥有哪些通知渠道,但是这些通知渠道的控制权都是掌握在用户手上的。用户可以自由地选择这些通知渠道的重要程度,是否响铃、是否振动、或者是否要关闭这个渠道的通知。

    拥有了这些控制权之后,用户就再也不用害怕那些垃圾推送消息的打扰了,因为用户可以自主地选择自己关心哪些通知、不关心哪些通知。举个具体的例子,我希望可以即时收到支付宝的收款信息,因为我不想错过任何一笔收益,但是我又不想收到支付宝给我推荐的周围美食,因为我没钱只吃得起公司食堂。这种情况,支付宝就可以创建两种通知渠道,一个收支,一个推荐,而我作为用户对推荐类的通知不感兴趣,那么我就可以直接将推荐通知渠道关闭,这样既不影响我关心的通知,又不会让那些我不关心的通知来打扰我了。

    对于每个App来说,通知渠道的划分是非常需要仔细考究的,因为通知渠道一旦创建之后就不能再修改了,因此开发者需要仔细分析自己的App一共有哪些类型的通知,然后再去创建相应的通知渠道。这里我们来参考一下Twitter的通知渠道划分:

    可以看到,Twitter就是根据自己的通知类型,对通知渠道进行了非常详细的划分,这样用户的自主选择性就比较高了,也就大大降低了用户不堪其垃圾通知的骚扰而将App卸载的概率。


    我一定要适配吗?

    Google这次对于8.0系统通知渠道的推广态度还是比较强硬的。

    首先,如果你升级了appcompat库,那么所有使用appcompat库来构建通知的地方全部都会进行废弃方法提示,如下所示:

    上图告诉我们,此方法已废弃,需要使用带有通知渠道的方法才行。

    当然,Google也并没有完全做绝,即使方法标为了废弃,但还是可以正常使用的。可是如果你将项目中的targetSdkVersion指定到了26或者更高,那么Android系统就会认为你的App已经做好了8.0系统的适配工作,当然包括了通知栏的适配。这个时候如果还不使用通知渠道的话,那么你的App的通知将完全无法弹出。因此这里给大家的建议就是,一定要适配。

    好了,前面向大家介绍了这么多的背景知识,那么现在开始我们就正式进入正题,来学习一下如何进行8.0系统中通知栏的适配。

    创建通知渠道

    首先我们使用Android Studio来新建一个项目,就叫它NotificationTest吧。

    创建好项目之后,打开app/build.gradle文件检查一下,确保targetSdkVersion已经指定到了26或者更高,如下所示:

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 26
        defaultConfig {
            applicationId "com.example.notificationtest"
            minSdkVersion 15
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
    }

    可以看到,这里我在创建新项目的时候默认targetSdkVersion就是26,如果你是低于26的话,说明你的Android SDK有些老了,最好还是更新一下。当然如果你懒得更新也没关系,手动把它改成26就可以了。

    接下来修改MainActivity中的代码,如下所示:

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                String channelId = "chat";
                String channelName = "聊天消息";
                int importance = NotificationManager.IMPORTANCE_HIGH;
                createNotificationChannel(channelId, channelName, importance);
    
                channelId = "subscribe";
                channelName = "订阅消息";
                importance = NotificationManager.IMPORTANCE_DEFAULT;
                createNotificationChannel(channelId, channelName, importance);
            }
        }
    
    
        @TargetApi(Build.VERSION_CODES.O)
        private void createNotificationChannel(String channelId, String channelName, int importance) {
            NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
            NotificationManager notificationManager = (NotificationManager) getSystemService(
                    NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);
        }
    }

    代码不长,我来简单解释下。这里我们在MainActivity中创建了两个通知渠道,首先要确保的是当前手机的系统版本必须是Android 8.0系统或者更高,因为低版本的手机系统并没有通知渠道这个功能,不做系统版本检查的话会在低版本手机上造成崩溃。

    创建一个通知渠道的方式非常简单,这里我封装了一个createNotificationChannel()方法,里面的逻辑相信大家都看得懂。需要注意的是,创建一个通知渠道至少需要渠道ID、渠道名称以及重要等级这三个参数,其中渠道ID可以随便定义,只要保证全局唯一性就可以。渠道名称是给用户看的,需要能够表达清楚这个渠道的用途。重要等级的不同则会决定通知的不同行为,当然这里只是初始状态下的重要等级,用户可以随时手动更改某个渠道的重要等级,App是无法干预的。

    上述代码我是模拟了这样一个场景。想象一下我们正在开发一个类似于微信的App,其中App通知主要可以分为两类,一类是我和别人的聊天消息,这类消息非常重要,因此重要等级我设为了IMPORTANCE_HIGH。另一类是公众号的订阅消息,这类消息不是那么重要,因此重要等级我设为了IMPORTANCE_DEFAULT。除此之外,重要等级还可以设置为IMPORTANCE_LOW、IMPORTANCE_MIN,分别对应了更低的通知重要程度。

    现在就可以运行一下代码了,运行成功之后我们关闭App,进入到设置 -> 应用 -> 通知当中,查看NotificationTest这个App的通知界面,如下图所示:

    刚才我们创建的两个通知渠道这里已经显示出来了。可以看到,由于这两个通知渠道的重要等级不同,通知的行为也是不同的,聊天消息可以发出提示音并在屏幕上弹出通知,而订阅消息只能发出提示音。

    当然,用户还可以点击进去对该通知渠道进行任意的修改,比如降低聊天消息的重要等级,甚至是可以完全关闭该渠道的通知。

    至于创建通知渠道的这部分代码,你可以写在MainActivity中,也可以写在Application中,实际上可以写在程序的任何位置,只需要保证在通知弹出之前调用就可以了。并且创建通知渠道的代码只在第一次执行的时候才会创建,以后每次执行创建代码系统会检测到该通知渠道已经存在了,因此不会重复创建,也并不会影响任何效率。


    让通知显示出来

    触发通知的代码和之前版本基本是没有任何区别的,只是在构建通知对象的时候,需要多传入一个通知渠道ID,表示这条通知是属于哪个渠道的。

    那么下面我们就来让通知显示出来。

    首先修改activity_main.xml中的代码,如下所示:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发送聊天消息"
            android:onClick="sendChatMsg"
            />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发送订阅消息"
            android:onClick="sendSubscribeMsg"
            />
    </LinearLayout>

    这里我们在布局文件中加入了两个按钮,很显然,一个是用于触发聊天消息渠道通知的,一个是用于触发订阅消息渠道通知的。

    接下来修改MainActivity中的代码,如下所示:

    public class MainActivity extends AppCompatActivity {
    
        ...
    
        public void sendChatMsg(View view) {
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            Notification notification = new NotificationCompat.Builder(this, "chat")
                    .setContentTitle("收到一条聊天消息")
                    .setContentText("今天中午吃什么?")
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.drawable.icon)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.icon))
                    .setAutoCancel(true)
                    .build();
            manager.notify(1, notification);
        }
    
        public void sendSubscribeMsg(View view) {
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            Notification notification = new NotificationCompat.Builder(this, "subscribe")
                    .setContentTitle("收到一条订阅消息")
                    .setContentText("地铁沿线30万商铺抢购中!")
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.drawable.icon)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.icon))
                    .setAutoCancel(true)
                    .build();
            manager.notify(2, notification);
        }
    }

    这里我们分别在sendChatMsg()和sendSubscribeMsg()方法中触发了两条通知,创建通知的代码就不再多做解释了,和传统创建通知的方法没什么两样,只是在NotificationCompat.Builder中需要多传入一个通知渠道ID,那么这里我们分别传入了chat和subscribe这两个刚刚创建的渠道ID。

    现在重新运行一下代码,并点击发送聊天消息按钮,效果如下图所示:

    由于这是一条重要等级高的通知,因此会使用这种屏幕弹窗的方式来通知用户有消息到来。然后我们可以下拉展开通知栏,这里也能查看到通知的详细信息:

    用户可以通过快速向左或者向右滑动来关闭这条通知。

    接下来点击发送订阅消息按钮,你会发现现在屏幕上不会弹出一条通知提醒了,只会在状态栏上显示一个小小的通知图标:

    因为订阅消息通知的重要等级是默认级别,这就是默认级别通知的展示形式。当然我们还是可以下拉展开通知栏,查看通知的详细信息:

    不过上面演示的都是通知栏的传统功能,接下来我们看一看Android 8.0系统中通知栏特有的功能。

    刚才提到了,快速向左或者向右滑动可以关闭一条通知,但如果你缓慢地向左或者向右滑动,就会看到这样两个按钮:

    其中,左边那个时钟图标的按钮可以让通知延迟显示。比方说这是一条比较重要的通知,但是我暂时没时间看,也不想让它一直显示在状态栏里打扰我,我就可以让它延迟一段后时间再显示,这样我就暂时能够先将精力放在专注的事情上,等过会有时间了这条通知会再次显示出来,我不会错过任何信息。如下所示:

    而右边那个设置图标的按钮就可以用来对通知渠道进行屏蔽和配置了,用户对每一个App的每一个通知渠道都有绝对的控制权,可以根据自身的喜好来进行配置和修改。如下所示:

    比如说我觉得订阅消息老是向我推荐广告,实在是太烦了,我就可以将订阅消息的通知渠道关闭掉。这样我以后就不会再收到这个通知渠道下的任何消息,而聊天消息却不会受到影响,这就是8.0系统通知渠道最大的特色。

    另外,点击上图中的所有类别就可以进入到当前应用程序通知的完整设置界面。


    管理通知渠道

    在前面的内容中我们已经了解到,通知渠道一旦创建之后就不能再通过代码修改了。既然不能修改的话那还怎么管理呢?为此,Android赋予了开发者读取通知渠道配置的权限,如果我们的某个功能是必须按照指定要求来配置通知渠道才能使用的,那么就可以提示用户去手动更改通知渠道配置。

    只讲概念总是不容易理解,我们还是通过具体的例子来学习一下。想一想我们开发的是一个类似于微信的App,聊天消息是至关重要的,如果用户不小心将聊天消息的通知渠道给关闭了,那岂不是所有重要的信息全部都丢了?为此我们一定要保证用户打开了聊天消息的通知渠道才行。

    修改MainActivity中的代码,如下所示:

    public class MainActivity extends AppCompatActivity {
    
        ...
    
        public void sendChatMsg(View view) {
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = manager.getNotificationChannel("chat");
                if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
                    Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
                    intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
                    intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel.getId());
                    startActivity(intent);
                    Toast.makeText(this, "请手动将通知打开", Toast.LENGTH_SHORT).show();
                }
            }
    
            Notification notification = new NotificationCompat.Builder(this, "chat")
                    ...
                    .build();
            manager.notify(1, notification);
        }
    
        ...
    
    }

    这里我们对sendChatMsg()方法进行了修改,通过getNotificationChannel()方法获取到了NotificationChannel对象,然后就可以读取该通知渠道下的所有配置了。这里我们判断如果通知渠道的importance等于IMPORTANCE_NONE,就说明用户将该渠道的通知给关闭了,这时会跳转到通知的设置界面提醒用户手动打开。

    现在重新运行一下程序,效果如下图所示:

    可以看到,当我们将聊天消息的通知渠道关闭后,下次再次发送聊天消息将会直接跳转到通知设置界面,提醒用户手动将通知打开。

    除了以上管理通知渠道的方式之外,Android 8.0还赋予了我们删除通知渠道的功能,只需使用如下代码即可删除:

    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    manager.deleteNotificationChannel(channelId);

    但是这个功能非常不建议大家使用。因为Google为了防止应用程序随意地创建垃圾通知渠道,会在通知设置界面显示所有被删除的通知渠道数量,如下图所示:

    这样是非常不美观的,所以对于开发者来说最好的做法就是仔细规划好通知渠道,而不要轻易地使用删除功能。


    显示未读角标

    前面我们提到过,苹果是从iOS 5开始才引入了通知栏功能,那么在iOS 5之前,iPhone都是怎么进行消息通知的呢?使用的就是未读角标功能,效果如下所示:

    实际上Android系统之前是从未提供过这种类似于iOS的角标功能的,但是由于很多国产手机厂商都喜欢跟风iOS,因此各种国产手机ROM都纷纷推出了自己的角标功能。

    可是国产手机厂商虽然可以订制ROM,但是却没有制定API的能力,因此长期以来都没有一个标准的API来实现角标功能,很多都是要通过向系统发送广播来实现的,而各个手机厂商的广播标准又不一致,经常导致代码变得极其混杂。

    值得高兴的是,从8.0系统开始,Google制定了Android系统上的角标规范,也提供了标准的API,长期让开发者头疼的这个问题现在终于可以得到解决了。

    那么下面我们就来学习一下如何在Android系统上实现未读角标的效果。

    修改MainActivity中的代码,如下所示:

    public class MainActivity extends AppCompatActivity {
    
        ...
    
        @TargetApi(Build.VERSION_CODES.O)
        private void createNotificationChannel(String channelId, String channelName, int importance) {
            NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
            channel.setShowBadge(true);
            NotificationManager notificationManager = (NotificationManager) getSystemService(
                    NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);
        }
    
        public void sendSubscribeMsg(View view) {
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            Notification notification = new NotificationCompat.Builder(this, "subscribe")
                    ...
                    .setNumber(2)
                    .build();
            manager.notify(2, notification);
        }
    }

    可以看到,这里我们主要修改了两个地方。第一是在创建通知渠道的时候,调用了NotificationChannel的setShowBadge(true)方法,表示允许这个渠道下的通知显示角标。第二是在创建通知的时候,调用了setNumber()方法,并传入未读消息的数量。

    现在重新运行一下程序,并点击发送订阅消息按钮,然后在Launcher中找到NotificationTest这个应用程序,如下图所示:

    可以看到,在图标的右上角有个绿色的角标,说明我们编写的角标功能已经生效了。

    需要注意的是,即使我们不调用setShowBadge(true)方法,Android系统默认也是会显示角标的,但是如果你想禁用角标功能,那么记得一定要调用setShowBadge(false)方法。

    但是未读数量怎么没有显示出来呢?这个功能还需要我们对着图标进行长按才行,效果如下图所示:

    这样就能看到通知的未读数量是2了。

    可能有些朋友习惯了iOS上的那种未读角标,觉得Android上这种还要长按的方式很麻烦。这个没有办法,因为这毕竟是Android原生系统,Google没有办法像国内手机厂商那样可以肆无忌惮地模仿iOS,要不然可能会吃官司的。但是我相信国内手机厂商肯定会将这部分功能进行定制,风格应该会类似于iOS。不过这都不重要,对于我们开发者来说,最好的福音就是有了统一的API标准,不管国内手机厂商以后怎么定制ROM,都会按照这个API的标准来定制,我们只需要使用这个API来进行编程就可以了。

    好的,关于Android 8.0系统适配的上下两篇文章到这里就结束了,感谢大家阅读。

    文章中的示例源码点击 这里 下载。

    关注我的技术公众号,每天都有优质技术文章推送。关注我的娱乐公众号,工作、学习累了的时候放松一下自己。

    微信扫一扫下方二维码即可关注:

            

    展开全文
  • Android应用检查版本更新后,在通知栏下载,更新下载进度,下载完成自动安装。接下来通过本文给大家介绍Android程序版本更新之通知栏更新下载安装的相关知识,需要的朋友参考下吧
  • Android通知栏和服务相关知识

    千次阅读 2022-01-06 20:26:49
    Android通知栏与开启前后台服务执行下载任务 索引自定义通知栏关键点后台下载,同时打开前台服务显示进度关键点 自定义通知栏 关键点 在Android8之后,发送通知需要通知渠道,具体要求见官方文档 使用自定义通知栏...

    Android通知栏与开启前后台服务执行下载任务

    自定义通知栏

    关键点

    1. 在Android8之后,发送通知需要通知渠道,具体要求见官方文档
    2. 使用自定义通知栏需要RemoteViews,并且RemoteViews内部不支持包含有约束布局的view,支持相对布局、线下布局…具体见官方文档
    3. 对于自定义通知栏的点击事件,需要PendingIntent和广播(下一篇博客展示)

    这个部分是用的模拟器运行的,所以因为某些版本和机制的问题图标和style没有生效,后面在看看吧,另外小米手机可能会被收纳到不重要通知里面,所以要打开收纳通知才能看到,设置了优先级也不行,不知道是什么原因…
    请添加图片描述

    样例代码:(借用的别人博客,不记得是哪一篇了)
    5. MainActivity

    public class MainActivity extends AppCompatActivity {
    
        private NotificationManager nm;
        private Handler handler = new Handler();
        Notification customNotification;
        private int progress = 0;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initData();
    
            Button bt_send = findViewById(R.id.bt_send);
            bt_send.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    nm.notify(1, customNotification);
                    handler.post(run);
                }
            });
        }
    
        @SuppressWarnings("deprecation")
        public void initData() {
    
            nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
            // android8 以上需要通知渠道
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                CharSequence name = "getString(R.string.channel_name)";
                int importance = NotificationManager.IMPORTANCE_HIGH;
                NotificationChannel channel = new NotificationChannel("1", name, importance);
                channel.enableLights(true);
                channel.enableVibration(false);
                nm.createNotificationChannel(channel);
            }
    
    
    
            RemoteViews contentView = new RemoteViews(getPackageName(),R.layout.view);
            contentView.setProgressBar(R.id.pb, 100, progress, false);
            contentView.setTextViewText(R.id.iv, "进度条");
    
    
            customNotification = new NotificationCompat.Builder(MainActivity.this, "1")
                    .setSmallIcon(R.drawable.ic_launcher_background)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_background))
                    .setStyle(new NotificationCompat.DecoratedCustomViewStyle())
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setContent(contentView)
                    .build();
        }
    
        private Runnable run = new Runnable() {
    
            @Override
            public void run() {
    
                progress++;
                customNotification.contentView.setProgressBar(R.id.pb, 100, progress,false);
                customNotification.contentView.setTextViewText(R.id.tv , String.valueOf(progress));
                nm.notify(1, customNotification);// 更新notification,即更新进度条
                if (progress < 100)
                    handler.postDelayed(run, 500); // 500毫秒progress加1
            }
        };
        }
    
    1. R.layout.activity_main
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
    
        <Button
            android:id="@+id/bt_send"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="发送通知" />
    
    </LinearLayout>
    
    1. view.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:gravity="center_vertical">
    
        <TextView
            android:id="@+id/iv"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:text="progress"
            android:textColor="#000000"
            android:layout_weight="1"/>
    
        <ProgressBar
            android:id="@+id/pb"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="3"/>
    
        <TextView
            android:id="@+id/tv"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textColor="#000000"
            android:text="0%"/>
    
    </LinearLayout>
    

    后台下载,同时打开前台服务显示进度

    关键点

    后台服务AsyncTask、前台服务的 使用
    本部分代码参考第三行代码(第二版)关于android服务模块知识,因版本问题对原代码略作修改,效果图如下:
    请添加图片描述

    代码结构目录:
    在这里插入图片描述
    代码如下:

    1. MainActivity.java
    public class MainActivity extends AppCompatActivity {
        private Button start;
        private Button pause;
        private Button cancel;
    
        private DownloadService.DownloadBinder downloadBinder;
    
        private ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                downloadBinder = (DownloadService.DownloadBinder) service;
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initUI();
            Intent intent = new Intent(this , DownloadService.class);
            startService(intent);
            bindService(intent , connection , BIND_AUTO_CREATE);
            if(ContextCompat.checkSelfPermission(MainActivity.this ,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this , new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE } ,1);
            }
    
            start.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String url = "http://imtt.dd.qq.com/16891/apk/D7546A0CC8CC7C7DA082D804FAED1E78.apk?fsname=com.tencent.weishi_8.6.0.588_860.apk";
                    downloadBinder.startDownload(url);
                }
            });
    
            pause.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    downloadBinder.pauseDownload();
                }
            });
    
            cancel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    downloadBinder.cancelDownload();
                }
            });
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            switch (requestCode) {
                case 1:
                    if(grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                        Toast.makeText(this,"拒绝权限将无法使用此功能",Toast.LENGTH_SHORT).show();
                        finish();
                    }
                    break;
                default:
            }
        }
    
        private void initUI() {
            start = findViewById(R.id.start_download);
            pause = findViewById(R.id.paused_download);
            cancel = findViewById(R.id.cancel_download);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unbindService(connection);
        }
    }
    
    1. DownloadListener.java
    public interface DownloadListener {
    
        void onProgress(int progress);
    
        void onSuccess();
    
        void onFailed();
    
        void onPaused();
    
        void onCanceled();
    }
    
    1. DownloadService.java
    public class DownloadService extends Service {
    
        private DownloadTask downloadTask;
    
        private String downloadUrl;
    
    
        private DownloadListener listener = new DownloadListener() {
            @Override
            public void onProgress(int progress) {
                NotificationManager manager = getNotificationManager();
                getNotificationChannel(manager);
                manager.notify(1 , getNotification("Download..." , progress));
            }
    
            @Override
            public void onSuccess() {
                downloadTask = null;
                stopForeground(true);
                NotificationManager manager = getNotificationManager();
                getNotificationChannel(manager);
                manager.notify(1,getNotification("Download success" , -1));
                Toast.makeText(DownloadService.this,"Download success", Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void onFailed() {
                downloadTask = null;
                stopForeground(true);
                NotificationManager manager = getNotificationManager();
                getNotificationChannel(manager);
                manager.notify(1,getNotification("Download failed" , -1));
                Toast.makeText(DownloadService.this,"Download failed", Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void onPaused() {
                downloadTask = null;
                Toast.makeText(DownloadService.this,"Download paused", Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void onCanceled() {
                downloadTask = null;
                Toast.makeText(DownloadService.this,"Download canceled", Toast.LENGTH_SHORT).show();
            }
        };
    
        public DownloadService() {
        }
    
        private DownloadBinder mBinder = new DownloadBinder();
    
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
        class DownloadBinder extends Binder {
            public void startDownload(String url) {
                if(downloadTask == null) {
                    downloadUrl = url;
                    downloadTask = new DownloadTask(listener,DownloadService.this);
                    downloadTask.execute(downloadUrl);
                    startForeground(1 , getNotification("Downloading..." , 0));
                    Toast.makeText(DownloadService.this,"Downloading..." , Toast.LENGTH_SHORT).show();
                }
            }
    
            public void pauseDownload() {
                if(downloadTask != null) {
                    downloadTask.pauseDownload();
                }
            }
    
            public void cancelDownload() {
                if(downloadTask != null) {
                    downloadTask.cancelDownload();
                } else {
                    if(downloadUrl != null) {
                        String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
                        String directory = DownloadService.this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath();
                        File file = new File(directory + fileName);
                        if(file.exists()) {
                            file.delete();
                        }
                        NotificationManager manager = getNotificationManager();
                        getNotificationChannel(manager);
                        manager.cancel(1);
                        stopForeground(true);
                        Toast.makeText(DownloadService.this,"Canceled",Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }
    
        private NotificationManager getNotificationManager() {
            return (NotificationManager) getSystemService((NOTIFICATION_SERVICE));
        }
    
        private Notification getNotification(String title , int progress) {
            Intent intent = new Intent(this , MainActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this , 0 , intent , 0);
    
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"1");
            builder.setChannelId("1");
            builder.setSmallIcon(R.mipmap.ic_launcher);
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher));
            builder.setContentIntent(pendingIntent);
            builder.setContentTitle(title);
            if(progress >= 0) {
    
                builder.setContentText(progress + "%");
                builder.setProgress(100,progress,false);
            }
            return builder.build();
        }
    
        private void getNotificationChannel(NotificationManager manager) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                CharSequence name = "notification channel";
                String description = "channel_description";
                int importance = NotificationManager.IMPORTANCE_DEFAULT;
                NotificationChannel channel = new NotificationChannel("1", name, importance);
                channel.setDescription(description);
                manager.createNotificationChannel(channel);
            }
        }
    }
    
    1. DownloadTask.java
    public class DownloadTask extends AsyncTask<String , Integer , Integer> {
    
        public static final int TYPE_SUCCESS = 0;
        public static final int TYPE_FAILED = 1;
        public static final int TYPE_PAUSED = 2;
        public static final int TYPE_CANCELED = 3;
    
        private DownloadListener listener;
        private boolean isCanceled = false;
        private boolean isPaused = false;
        private int lastProgress;
        private Context context;
    
        public DownloadTask(DownloadListener listener, Context context) {
            this.listener = listener;
            this.context = context;
        }
    
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        @Override
        protected Integer doInBackground(String... strings) {
            InputStream in = null;
            RandomAccessFile saveFile = null;
            File file = null;
            long downloadedLength = 0; // 记录下载的文件长度
            String downloadUrl = strings[0];
            String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
            String directory = Objects.requireNonNull(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)).getPath();
            file = new File(directory + fileName);
            if (file.exists()) {
                downloadedLength = file.length();
            }
            try {
                long contentLength = getContentLength(downloadUrl);
                if (contentLength == 0) {
                    return TYPE_FAILED;
                } else if (contentLength == downloadedLength) {
                    return TYPE_SUCCESS;
                }
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder()
                        // 断点下载
                        .addHeader("RANGE", "bytes=" + downloadedLength + "-")
                        .url(downloadUrl)
                        .build();
                Response response = client.newCall(request).execute();
                if(response != null) {
                    in = response.body().byteStream();
                    saveFile = new RandomAccessFile(file , "rw");
                    saveFile.seek(downloadedLength); //跳过已下载字节
                    byte[] b = new byte[1024];
                    int total = 0;
                    int len;
                    while((len = in.read(b)) != -1) {
                        if(isCanceled) {
                            return TYPE_CANCELED;
                        } else if(isPaused) {
                            return TYPE_PAUSED;
                        } else {
                            total += len;
                            saveFile.write(b , 0 , len);
                            int progress = (int) ((total + downloadedLength) * 100 / contentLength);
                            publishProgress(progress);
                        }
                    }
                    response.body().close();
                    return TYPE_SUCCESS;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if(in != null) {
                        in.close();
                    }
                    if(saveFile != null) {
                        saveFile.close();
                    }
                    if(isCanceled && file != null) {
                        file.delete();
                      }
            } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return TYPE_FAILED;
        }
    
        @Override
        protected void onProgressUpdate(Integer... values) {
            int progress = values[0];
            if(progress > lastProgress) {
                listener.onProgress(progress);
                lastProgress = progress;
            }
        }
    
        @Override
        protected void onPostExecute(Integer integer) {
            switch (integer) {
                case TYPE_SUCCESS :
                    listener.onSuccess();
                    break;
                case TYPE_FAILED :
                    listener.onFailed();
                    break;
                case TYPE_PAUSED :
                    listener.onPaused();
                    break;
                case TYPE_CANCELED :
                    listener.onCanceled();
                    break;
                default :
                    break;
            }
        }
    
        public void pauseDownload() {
            isPaused = true;
        }
    
        public void cancelDownload() {
            isCanceled = true;
        }
    
        private long getContentLength(String downloadUrl) throws IOException {
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder().url(downloadUrl).build();
            Response response = client.newCall(request).execute();
            if(response != null && response.isSuccessful()) {
                long contentLength = response.body().contentLength();
                response.close();
                return contentLength;
            }
            return 0;
        }
    }
    
    1. activity_main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <Button
            android:id="@+id/start_download"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="开始下载"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/paused_download"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.3" />
    
        <Button
            android:id="@+id/paused_download"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="暂停下载"
            app:layout_constraintBottom_toBottomOf="@+id/start_download"
            app:layout_constraintEnd_toStartOf="@+id/cancel_download"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toEndOf="@+id/start_download"
            app:layout_constraintTop_toTopOf="@+id/start_download" />
    
        <Button
            android:id="@+id/cancel_download"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="取消下载"
            app:layout_constraintBottom_toBottomOf="@+id/paused_download"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toEndOf="@+id/paused_download"
            app:layout_constraintTop_toTopOf="@+id/paused_download" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    ** 下载位置**
    在图片中的data目录中,相关APP项目文件下
    在这里插入图片描述

    展开全文
  • 主要介绍了详解Android中使用Notification实现进度通知栏(示例三),具有一定的参考价值,有兴趣的可以了解一下。
  • Android通知栏监听

    千次阅读 2022-01-09 23:34:16
    通过继承 NotificationListenerService实现,它允许应用程序在创建或删除时接收有关通知的信息。 class MyNotificationListenerService : NotificationListenerService() { private val pkgName = this.javaClass...
  • 示例一:实现通知栏管理 当针对相同类型的事件多次发出通知,作为开发者,应该避免使用全新的通知,这时就应该考虑更新之前通知栏的一些值来达到提醒用户的目的。例如我们手机的短信系统,当不断有新消息传来时,...
  • 主要介绍了Android实现沉浸式通知栏通知栏背景颜色跟随app导航栏背景颜色而改变的相关资料,需要的朋友可以参考下
  • Android各种样式通知栏

    2018-07-30 22:20:20
    各种样式的通知栏,以及不同版本的兼容性的版本,还有自定义的QQ悬浮窗通知栏以及前台服务类型的通知栏
  • Android通知栏Notification效果代码简单演示,属于本人复习所用。
  • Android 通知栏

    2015-11-19 11:05:55
    Android 通知栏
  • NotificationListenerService是通过系统调起的服务,在应用发起通知时,系统会将通知的应用,动作和信息回调给NotificationListenerService。但使用之前需要引导用户进行授权。使用NotificationListenerService一般...
  • Android通知栏实现.rtf

    2021-04-17 16:42:40
    Android通知栏实现
  • 一文彻底玩转Android通知栏消息通知

    千次阅读 2021-12-09 19:58:20
    Google为什么要引入消息渠道这个,因为在之前版本的Android通知管理中,通知消息要么全部接收,要么全部屏蔽,然而消息渠道改变了这一特点。 就是每条通知都要属于一个对应的渠道。每个App都可以自由地创建当前App...
  • 1、使用AsyncTask异步任务实现,调用publishProgress()方法刷新进度来实现(已优化) public class MyAsyncTask extends AsyncTask<String> { private Context context; private NotificationManager ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 48,545
精华内容 19,418
关键字:

android通知栏

友情链接: out.zip