Android向けの開発中の「工場メソッド」。 プッシュを処理する最良の方法

この記事では、Android開発の古典的なデザインパターンの1つであるFabricメソッドについて説明します。 Firebase Cloud Messaging(以降FCM)を使用した例を使用して調査します。 目標は、 Live Typingで行ったように、 オブジェクト指向設計手法を使用することの重要性、OOPのすべての利点をまだ完全にマスターしていない初心者開発者に伝えることです。







画像







なぜFCMが例ですか?



FCM-既製のメッセージングサービス(いわゆるプッシュ)の1つ。「パブリッシャー-サブスクライバー」のモデルに取り組んでいます。 デバイスで新しいメッセージ(ニュース/割引/新製品など)に関する通知を再度受信した場合、この機能はFCMまたは同等の機能を介して実装されている可能性があります。 現在、FCMは参照ソリューションとしてGoogleによって位置付けられています。 したがって、この記事は、読者がすでにこのサービスに精通している、または読者に彼を知る機会が与えられる可能性が高いという期待を持って書かれています。







そして、なぜプッシュメッセージについて?



ファクトリーメソッドを使用して、アプリケーションでプッシュメッセージの処理を記述することは、このテンプレートを一度だけ扱う絶好の機会です。 UIオブジェクトまたはビジネスロジックのオブジェクトを設計するとき、初心者が間違いを犯すことは許されます:オブジェクトの数の拡大を想定しないこと、および/またはそれぞれのロジックを簡単に変更する機能を設定しないことです。 しかし、経験が示すように、大砲の処理は多くの場合複雑であり、プロジェクト開発の全期間を通じて拡張されます。 VKアプリケーションを作成しなければならないと想像してください。 ユーザーは、プッシュに関するさまざまな通知を受け取ります。これらの通知は見た目が異なり、クリックして異なる画面を開きます。 また、プッシュ通知の処理を担当するモジュールが元々正しく設計されていなかった場合、新しいプッシュはそれぞれこんにちは、そうでない場合は新しい、こんにちは、回帰テスト、そして新しいバグもこんにちはです。







FCMを使用したサンプルプロジェクト



アイデア



幼稚園の先生とこの幼稚園に通う子供の親とのコミュニケーションを確立することを考えているスタートアップを想像してください。 コンテンツは教師アプリケーションを介して作成され、親アプリケーションを介して消費されるため、教師と保護者の両方に対する単一のアプリケーションは適していません。 サービスユーザーの3番目のタイプ-幼稚園の管理を検討してください。 彼らは、就業日の主要部分がデスクトップを通過するという事実のためにモバイルアプリケーションを必要としませんが、重要なニュースについて両親や介護者に通知する便利な方法が必要です。







合計:









Androidプロジェクトの構造



Android Studioのプロジェクトは次の構造になります







画像







コアモジュールは2つのアプリケーションに共通です。 これには、 モジュールと教師モジュールが含まれています。それぞれ、親アプリケーションと教師アプリケーションのモジュールです。







プッシュ通知を接続する段階でのタスクは、ユーザーがアプリケーションを開いているかどうかに関係なく、サーバー上のデータが変更されたときにユーザーに通知を表示することです。

教師および親アプリケーションには、さまざまなタイプのプッシュがあります。 そのため、通知にはさまざまなアイコンがあり、通知をクリックすると、さまざまな画面が開きます。







通知例



教師の申請の場合:









親アプリケーションの場合:









プッシュ処理



AndroidプロジェクトでFCMを接続および構成するためのすべての準備作業の後、プッシュ通知の処理は、 FirebaseMessagingServiceの継承者である1つのクラスの実装に削減されます。







public class MyFirebaseMessagingService extends FirebaseMessagingService {

     @Override
   public void onMessageReceived(RemoteMessage remoteMessage) {
          super.onMessageReceived(remoteMessage);
     }
}
      
      





FCM :







FCM Android

Firebase







onMessageReceived() RemoteMessage, , : , Map , push- .







     . push , , , onMessageReceived() . firebase-messaging push` . . ( ) data, MyFirebaseMessagingService. FCM. data.







Firebase









, , :







public class TeacherFirebaseMessagingService extends FirebaseMessagingService {

   private static final String KEY_PUSH_TYPE = "type";
   private static final String KEY_PUSH_TITLE = "title";
   private static final String KEY_PUSH_CONTENT = "content";

   private static final String TYPE_NEW_CHILD = "add_child";
   private static final String TYPE_BIRTHDAY = "birthday";

   private static final String EMPTY_STRING = "";

   private static final int DEFAULT_NOTIFICATION_ID = 15;

   @Override
   public void onMessageReceived(RemoteMessage remoteMessage) {
       super.onMessageReceived(remoteMessage);
       Map<String, String> data = remoteMessage.getData();
       if (data.containsKey(KEY_PUSH_TYPE)) {

           NotificationCompat.Builder notificationBuilder;
           String notificationTitle = null;
           if (data.containsKey(KEY_PUSH_TITLE)) {
               notificationTitle = data.get(KEY_PUSH_TITLE);
           }
           String notificationContent = null;
           if (data.containsKey(KEY_PUSH_CONTENT)) {
               notificationContent = data.get(KEY_PUSH_CONTENT);
           }
           NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
           String pushType = data.get(KEY_PUSH_TYPE);
           if (pushType.equals(TYPE_NEW_CHILD)) {
               builder.setSmallIcon(R.drawable.ic_add_child)
                       .setContentTitle(notificationTitle != null ? notificationTitle : EMPTY_STRING)
                       .setContentText(notificationContent != null ? notificationContent : EMPTY_STRING);
           } else if (pushType.equals(TYPE_BIRTHDAY)) {
//                notificationBuilder = ....
//                       
           }
           NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
           notificationManager.notify(DEFAULT_NOTIFICATION_ID, builder.build());
       }
   }

      
      





title content remoteMessage:







private static final String KEY_TITLE = "title";
private static final String KEY_CONTENT = "content";
      
      





:







 private static final String TYPE_NEW_CHILD = "add_child";
 private static final String TYPE_BIRTHDAY = "birthday";
      
      





, private NotificationCompat.Builder. VK , :









TeacherFirebaseMessagingReceiver god object`. . , - .









« ».







, core:







public class CoreFirebaseMessagingService extends FirebaseMessagingService {

   @Override
   public void onMessageReceived(RemoteMessage remoteMessage) {
       super.onMessageReceived(remoteMessage);
   }
}
      
      





CoreFirebaseMessagingService .







CoreNotification. , .







public abstract class CoreNotification {
   public static final String KEY_FROM_PUSH = "CoreNotification.FromNotification";

   private static final String KEY_TITLE = "title";
   private static final String KEY_CONTENT = "body";

   protected static final String STRING_EMPTY = "";

   protected RemoteMessage remoteMessage;

   public CoreNotification(RemoteMessage remoteMessage) {
       this.remoteMessage = remoteMessage;
   }

   protected String getTitleFromMessage() {
       Map<String, String> data = remoteMessage.getData();
       if (data.containsKey(KEY_TITLE)) {
           return data.get(KEY_TITLE);
       } else {
           return STRING_EMPTY;
       }
   }

   protected String getContentFromMessage() {
       Map<String, String> data = remoteMessage.getData();
       if (data.containsKey(KEY_CONTENT)) {
           return data.get(KEY_CONTENT);
       } else {
           return STRING_EMPTY;
       }
   }

   public String getTitle() {
       return getTitleFromMessage();
   }

   public String getContent() {
       return getContentFromMessage();
   }

   protected abstract PendingIntent configurePendingIntent(Context context);

   protected abstract @DrawableRes int largeIcon();

   protected abstract String getNotificationTag();
}
      
      





RemoteMessage.

. STRING_EMPTY , protected.







     « - . » , , Java- , CoreNotification , . . title content . , getTitleFromMessage() getContentFromMessage(). ( title content RemoteMessage.getData() , ). protected, title content - .







     CoreNotificationCreator. . CoreNotification.







public abstract class CoreNotificationCreator {

   private static final String KEY_NOTIFICATION_TAG = "CoreNotificationCreator.TagKey";
   private static final String DEFAULT_TAG = "CoreNotificationCreator.DefaultTag";

   private static final String KEY_TYPE = "type";

   private NotificationManager notificationManager;

   public CoreNotificationCreator(Context context) {
       notificationManager = ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE));
   }

   public void showNotification(Context context, RemoteMessage remoteMessage) {
       String notificationType = getNotificationType(remoteMessage);
       CoreNotification notification = factoryMethod(notificationType, remoteMessage);
       if (notification != null) {
           NotificationCompat.Builder builder = builderFromPushNotification(context, notification);
           notify(builder);
       }
   }

   private String getNotificationType(RemoteMessage remoteMessage) {
       Map<String, String> data = remoteMessage.getData();
       if (data.containsKey(KEY_TYPE)) {
           return data.get(KEY_TYPE);
       }
       return "";
   }

   @Nullable
   protected abstract CoreNotification factoryMethod(String messageType, RemoteMessage remoteMessage);

   private final static int DEFAULT_NOTIFICATION_ID = 15;

   private static final
   @DrawableRes
   int SMALL_ICON_RES_ID = R.drawable.ic_notification_small;

   protected NotificationCompat.Builder builderFromPushNotification(Context context, CoreNotification notification) {
       Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(), notification.largeIcon());
       NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
               .setSmallIcon(SMALL_ICON_RES_ID)
               .setAutoCancel(true)
               .setDefaults(NotificationCompat.DEFAULT_ALL)
               .setContentTitle(notification.getTitle())
               .setContentText(notification.getContent())
               .setLargeIcon(largeIcon);
       builder.getExtras().putString(KEY_NOTIFICATION_TAG, notification.getNotificationTag());
       builder.setContentIntent(notification.configurePendingIntent(context));
       return builder;
   }

   private void notify(@NonNull NotificationCompat.Builder builder) {
       final String notificationTag = getNotificationTag(builder);
       notificationManager.cancel(notificationTag, DEFAULT_NOTIFICATION_ID);
       notificationManager.notify(notificationTag, DEFAULT_NOTIFICATION_ID, builder.build());
   }

   private String getNotificationTag(NotificationCompat.Builder builder) {
       Bundle extras = builder.getExtras();
       if (extras.containsKey(KEY_NOTIFICATION_TAG)) {
           return extras.getString(KEY_NOTIFICATION_TAG);
       } else {
           return DEFAULT_TAG;
       }
   }
}
      
      





showNotification()public . . — .







Android







  public void showNotification(Context context, RemoteMessage remoteMessage) {
       String notificationType = getNotificationType(remoteMessage);
       CoreNotification notification = factoryMethod(notificationType, remoteMessage);
       if (notification != null) {
           NotificationCompat.Builder builder = builderFromPushNotification(context, notification);
           notify(builder);
       }
   }
      
      





showNotification() , remoteMessage. remoteMessage , CoreNotification.







factoryMethod() @Nullable , , . . .







    , , , . : NotificationCreator.













public class TeacherNotificationCreator extends CoreNotificationCreator {

   public TeacherNotificationCreator(Context context) {
       super(context);
   }

   @Nullable
   @Override
   protected CoreNotification factoryMethod(String messageType, RemoteMessage remoteMessage) {
       switch (messageType) {
           case NewChildNotification.TYPE:
               return new NewChildNotification(remoteMessage);
           case BirthdayNotification.TYPE:
               return new BirthdayNotification(remoteMessage);
       }
       return null;
   }
}
      
      





messageType , CoreNotification .







, :







class NewChildNotification extends CoreNotification {

   static final String TYPE = "add_child";

   private static final String KEY_CHILD_NAME = "child_name";

   NewChildNotification(RemoteMessage remoteMessage) {
       super(remoteMessage);
   }

   @Override
   protected PendingIntent configurePendingIntent(Context context) {
       Intent intent = new Intent(context, MainActivity.class)
               .setPackage(context.getApplicationContext().getPackageName())
               .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
       intent.putExtra(CoreNotification.KEY_FROM_PUSH, getAddChildInfo());
       return PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
   }

   @Override
   protected int largeIcon() {
       return R.drawable.ic_add_child;
   }

   @Override
   protected String getNotificationTag() {
       return getClass().getName() + getChildName();
   }

   private String getChildName() {
       Map<String, String> data = remoteMessage.getData();
       if (data.containsKey(KEY_CHILD_NAME)) {
           return data.get(KEY_CHILD_NAME);
       }
       return STRING_EMPTY;
   }

   private String getAddChildInfo() {
       return "New child " + getChildName() + " was added to your group";
   }
}
      
      





configurePendingIntent() , push-







:







public class ParentNotificationCreator extends CoreNotificationCreator {

   public ParentNotificationCreator(Context context) {
       super(context);
   }

   @Nullable
   @Override
   protected CoreNotification factoryMethod(String messageType, RemoteMessage remoteMessage) {
       switch (messageType) {
           case PickUpNotification.TYPE: 
               return new PickUpNotification(remoteMessage);
           case GradeNotification.TYPE:
               return new GradeNotification(remoteMessage);
           default:
               return null;
       }
   }
}
      
      





.







. , Firebase. , Android Studio : Tools → Firebase → Cloud Messaging — Gradle- firebase . FCM Android-









CoreNotificationCreator ( ) + , CoreNotification. . CoreNotification , - , . CoreNotification :









, , , , , , push- .









" " , "" Android-











. , . . , , Android- , .







— . . !








All Articles