반응형

IObserver<T> interface와 IObservable<T> interface를 이용해 Observer Design Pattern을 구현해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Observer
{
    class Program
    {
        static void Main(string[] args)
        {
            LocationTracker provider = new LocationTracker();
            // Provider 생성
 
            LocationReporter reporter1 = new LocationReporter("FixedGPS");
            reporter1.Subscribe(provider);
            // Observer(FixedGPS) 생성 및 Provider에 등록
 
            LocationReporter reporter2 = new LocationReporter("MobileGPS");
            reporter2.Subscribe(provider);
            // Observer(MobileGPS) 생성 및 Provider에 등록
 
            provider.TrackLocation(new Location(47.6456-122.1312));
            // FixedGPS: The current location is 47.6456, -122.1312
            // MobileGPS: The current location is 47.6456, -122.1312
 
            reporter1.Unsubscribe();
            // FixedGPS unsubscribed.
 
            provider.TrackLocation(new Location(47.6677-122.1199));
            // MobileGPS: The current location is 47.6677, -122.1199
 
            provider.TrackLocation(null);
            // MobileGPS: The location cannot be determined.
 
            provider.EndTransmission();
            // MobileGPS unsubscribed.
            // The Location Tracker has completed transmitting data to MobileGPS.
        }
    }
 
    // 위치 정보를 담고 있는 데이터 클래스
    public struct Location
    {
        double lat, lon;
 
        public Location(double latitude, double longitude)
        {
            lat = latitude;
            lon = longitude;
        }
 
        public double Latitude
        {
            get { return lat; }
        }
 
        public double Longitude
        {
            get { return lon; }
        }
    }
 
    // Provider 클래스 (등록된(subscribe) Observer에 Notification을 보낸다)
    // IObservable<out T> 인터페이스는 IDisposable Subscribe(IObserver<T> observer)를 구현해야 한다.
    public class LocationTracker : IObservable<Location>
    {
        private List<IObserver<Location>> observers;
 
        public LocationTracker()
        {
            observers = new List<IObserver<Location>>();
        }
 
        // Subscribe()는 LocationTracker 클래스에서 호출되지 않는다. LocationReporter.Subscribe()에서 호출
        public IDisposable Subscribe(IObserver<Location> observer)
        {
            if (!observers.Contains(observer))
                observers.Add(observer);
 
            return new Unsubscriber(observers, observer);
        }
 
        private class Unsubscriber : IDisposable
        {
            private List<IObserver<Location>> _observers;
            private IObserver<Location> _observer;
 
            public Unsubscriber(List<IObserver<Location>> observers, IObserver<Location> observer)
            {
                _observers = observers;
                _observer = observer;
            }
 
            public void Dispose()
            {
                if (_observer != null && _observers.Contains(_observer))
                    _observers.Remove(_observer);
            }
        }
 
        public void TrackLocation(Nullable<Location> loc)
        {
            // observers 순회하는 예 1
            foreach (IObserver<Location> observer in observers)
            {
                if (!loc.HasValue)
                    observer.OnError(new LocationUnknownException());
                else
                    observer.OnNext(loc.Value);
            }
        }
 
        public void EndTransmission()
        {
            // observers 순회하는 예 2
            foreach (IObserver<Location> observer in observers.ToArray())
                if (observers.Contains(observer))
                    observer.OnCompleted();
 
            observers.Clear();
        }
    }
 
    // LocationTracker.TrackLocation()에 Location 정보가 없을때 보내는 예외 클래스
    public class LocationUnknownException : Exception
    {
        internal LocationUnknownException() : base("The location cannot be determined.")
        { }
    }
 
    // Observer 클래스 (Provider에 등록(subscribe)하고 Notification을 받는다)
    // IObserver<in T> 인터페이스는 아래 3개의 매소드를 구현해야 한다.
    // void OnCompleted(), void OnError(Exception error), void OnNext(T value);
    public class LocationReporter : IObserver<Location>
    {
        private IDisposable unsubscriber;
        private string instName;
 
        public LocationReporter(string name)
        {
            instName = name;
        }
 
        public string Name
        { get { return instName; } }
 
        public virtual void Subscribe(IObservable<Location> provider)
        {
            if (provider != null)
                unsubscriber = provider.Subscribe(this);
        }
 
        public virtual void OnCompleted()
        {
            Unsubscribe();
            Console.WriteLine("The Location Tracker has completed transmitting data to {0}.", Name);
        }
 
        public virtual void OnError(Exception e)
        {
            Console.WriteLine("{0}: {1}", Name, e.Message);
        }
 
        public virtual void OnNext(Location value)
        {
            Console.WriteLine("{2}: The current location is {0}, {1}", value.Latitude, value.Longitude, Name);
        }
 
        public virtual void Unsubscribe()
        {
            unsubscriber.Dispose();
            Console.WriteLine("{0} unsubscribed.", Name);
        }
    }
}
 

 

소스를 입력하고 빌드한다.

 

위치정보 Notification이 잘 전달된다.

 

※참고

The IObserver<T> and IObservable<T> interfaces provide a generalized mechanism for push-based notification, also known as the observer design pattern.

 

반응형
Posted by J-sean
:
반응형

A notification is a message that Android displays outside your app's UI to provide the user with reminders, communication from other people, or other timely information from your app. Users can tap the notification to open your app or take an action directly from the notification.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
public class MainActivity extends AppCompatActivity {
 
    NotificationManager notificationManager;
 
    private static String CHANNEL1_ID = "Channel1_ID";
    private static String CHANNEL1_NAME = "Channel1_NAME";
 
    private static String CHANNEL2_ID = "Channel2_ID";
    private static String CHANNEL2_NAME = "Channel2_NAME";
 
    private final int RequestCode = 101;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ShowNotification1();
            }
        });
 
        Button button2 = findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ShowNotification2();
            }
        });
    }
 
    public void ShowNotification1() {
        notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        NotificationCompat.Builder builder = null;
 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (notificationManager.getNotificationChannel(CHANNEL1_ID) == null) {
                notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL1_ID, CHANNEL1_NAME, NotificationManager.IMPORTANCE_DEFAULT));
                builder = new NotificationCompat.Builder(this, CHANNEL1_ID);
            } else {
                builder = new NotificationCompat.Builder(this, CHANNEL1_ID);
            }
        } else {
            builder = new NotificationCompat.Builder(this);
            // This package is part of the Android support library which is no longer maintained.
        }
 
        builder.setContentTitle("Simple notification");
        builder.setContentText("Message for simple notification");
        builder.setSmallIcon(android.R.drawable.ic_menu_view);
 
        Notification notification = builder.build();
 
        notificationManager.notify(1, notification);
        // Post a notification to be shown in the status bar. If a notification with the same id has already been posted by your application and has not yet
        // been canceled, it will be replaced by the updated information.
        // - Parameters
        // id: An identifier for this notification unique within your application.
        // notification: A Notification object describing what to show the user. Must not be null.
    }
 
    public void ShowNotification2() {
        notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        NotificationCompat.Builder builder = null;
 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (notificationManager.getNotificationChannel(CHANNEL2_ID) == null) {
                notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL2_ID, CHANNEL2_NAME, NotificationManager.IMPORTANCE_DEFAULT));
                builder = new NotificationCompat.Builder(this, CHANNEL2_ID);
            } else {
                builder = new NotificationCompat.Builder(this, CHANNEL2_ID);
            }
        } else {
            builder = new NotificationCompat.Builder(this);
        }
 
        Uri uri = Uri.parse("https://s-engineer.tistory.com");
        Intent intent = new Intent(ACTION_VIEW, uri);
        // ACTION_VIEW: Display the data to the user. This is the most common action performed on data -- it is the generic action you can use on a piece of
        // data to get the most reasonable thing to occur. For example, when used on a contacts entry it will view the entry; when used on a mailto: URI it
        // will bring up a compose window filled with the information supplied by the URI; when used with a tel: URI it will invoke the dialer.
        PendingIntent pendingIntent = PendingIntent.getActivity(this, RequestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
 
        builder.setContentTitle("Notification with PendingIntent");
        builder.setContentText("Message for notification with PendingIntent");
        builder.setSmallIcon(android.R.drawable.ic_menu_view);
        builder.setAutoCancel(true);
        // Setting this flag will make it so the notification is automatically canceled when the user clicks it in the panel.
        builder.setContentIntent(pendingIntent);
        // Supply a PendingIntent to send when the notification is clicked.
 
        Notification notification = builder.build();
 
        notificationManager.notify(2, notification);
    }
}




Run the app and click "SIMPLE NOTIFICATION" button.


A simple notification appears as an icon in the status bar. Users can swipe down on the status bar to open the notification drawer, where they can view more details and take actions with the notification.


Go back to the app and click "NOTIFICATION WITH PENDINGINTENT" button. Then click the notification again.


It will take you to a great blog.


반응형
Posted by J-sean
:
반응형

Add a vibration and a ringtone notification to your android application.


<AndroidManifest.xml>

1
    <uses-permission android:name="android.permission.VIBRATE"/>



<MainActivity.java>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
 
                if (Build.VERSION.SDK_INT >= 26) {
                    vibrator.vibrate(VibrationEffect.createOneShot(100010));
                    // - public static VibrationEffect createOneShot (long milliseconds, int amplitude)
                    // Create a one shot vibration. One shot vibrations will vibrate constantly for the specified period of time at the specified amplitude, and then stop.
                    // milliseconds long: The number of milliseconds to vibrate. This must be a positive number.
                    // amplitude int: The strength of the vibration. This must be a value between 1 and 255, or DEFAULT_AMPLITUDE.
                } else {
                    vibrator.vibrate(1000);
                    // Vibrate constantly for the specified period of time.
                    // This method was deprecated in API level 26. Use vibrate(android.os.VibrationEffect) instead.
                }
            }
        });
 
        Button button2 = findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
                // - public static Uri getDefaultUri (int type)
                // Returns the Uri for the default ringtone of a particular type. Rather than returning the actual ringtone's sound Uri, this will return the symbolic Uri
                // which will resolved to the actual sound when played.
                // - public static final int TYPE_NOTIFICATION
                // Type that refers to sounds that are used for notifications.
                // Constant Value: 2 (0x00000002)
 
                Ringtone ringtone = RingtoneManager.getRingtone(getApplicationContext(), uri);
                // Returns a Ringtone for a given sound URI.
                // If the given URI cannot be opened for any reason, this method will attempt to fallback on another sound. If it cannot find any, it will return null.
 
                ringtone.play();
                // Plays the ringtone.
            }
        });
 
        Button button3 = findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.media);
                // Convenience method to create a MediaPlayer for a given resource id. On success, prepare() will already have been called and must not be called again.
                // When done with the MediaPlayer, you should call release(), to free the resources. If not released, too many MediaPlayer instances will result in an exception.
 
                mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        mp.release();
                        // Releases resources associated with this MediaPlayer object. It is considered good practice to call this method when you're done using the MediaPlayer.
                    }
                });
                // Interface definition for a callback to be invoked when playback of a media source has completed.
 
                mediaPlayer.start();
                // Starts or resumes playback. If playback had previously been paused, playback will continue from where it was paused. If playback had been stopped, or never
                // started before, playback will start at the beginning.
            }
        });
    }
}




Add a media file for MediaPlayer.


Run the app and click the buttons.


반응형
Posted by J-sean
: