-
Notifications
You must be signed in to change notification settings - Fork 1
/
Notes
234 lines (220 loc) · 15 KB
/
Notes
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
API level 11 - fragment more dynamic and flexible UI on large screen size such as tablet
OS can only open activity
Activity inherit from Context class but fragment not so we have to use context property from fragment to have access to app
data typically associated with the context such as string and image resource
ActivityCompat extends ContextCompat
open class Fragment : ComponentCallbacks
Fragment have same back stack as activity except that the entire stack contained in activity
Fragment contain arguments in the form of bundle which is key value store also known as dictionary or associative array data
structure
safe args is gradle plugin that gurantee both side match up while transferring data from fragment a and fragment b
Android allows us to navigate between activities both within your app and to activities provided by other applications for eg
we can launch system camera activity to capture photos or launch a contact app to choose from
Intent can be
Explicit - use to launch an activity using the target activity class and mostly used to launch other activities within your app
navigation component do this for us when we navigate to other activities from naviagtion graph in our app
Implicit - Implicit intent provide abstract description of the operation to be performed and they often used to launch activities
that are exposed by other applications. each implicit intent must have an action e.g ACTION_VIEW, ACTION_DIAL, ACTION_EDIT
in addition to action implicit intent have category and datatypes to further describe the action e.g CATEGORY_APP_MUSIC,
CATEGORY_APP_GALLERY, CATEGORY_APP_CALENDER also include data type MIME DATA TYPE like text or jpeg which allows to choose
app based on data they can accept
activities that are launched explicitely can be only declared just with activity tag in manifest while implicit lanuch activity
require intent fiter, intent filter is used to expose that your activity can responsd to implicit intent with certain action
categoty and data type
val args = GameWonFragmentArgs.fromBundle(arguments)
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.setType("text/plain")
.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_success_text, args.numCorrect, args.numQuestions))
return shareIntent
}
implicit launch activity required intent filter while normal activity can declared with <activity> tag only
Intent extra is like key value data similar we use in fragment used to provide argument for intent some argument have predefined
key such as to add strin we have Intent.EXTRA_TEXT key
private fun getShareIntent() : Intent {
val args = GameWonFragmentArgs.fromBundle(arguments!!)
return ShareCompat.IntentBuilder.from(activity)
.setText(getString(R.string.share_success_text, args.numCorrect, args.numQuestions))
.setType("text/plain")
.intent
}
if (null == getShareIntent().resolveActivity(activity!!.packageManager)) {
//package manager knows about every activity that registered in manifest across every application
// hide the menu item if it doesn't resolve
menu?.findItem(R.id.share)?.setVisible(false)
}
ShareCompat fluent api to handle sharing
Navigation listener in on create they called whenever destination changes
// prevent nav gesture if not on start destination
navController.addOnDestinationChangedListener { nc: NavController, nd: NavDestination, args: Bundle? ->
if (nd.id == nc.graph.startDestination) {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
} else {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
}
}
Every activity or every fragment have lifecycle
resumed
|
started
|
created
|
initialize destroy
why all this matter and what the use of lifecycle - to know all about this we can manage situtation like which resource to
available in background or to pause as we have to give smoth experience to user do program proactively which means clean
unused resource and defensively in case os does something like restart
MotionLayout is a library that lets you add rich motion into your Android app. It's based upon ConstraintLayout and lets you
animate anything that you can build using ConstraintLayout.
Navigation Controller class manages navigation within our navigation host fragment
navigation host fragment is the parent in our view hierarchy of current fragment it means we can traverse up this heirarchy
to find nav host fragment from any view in our fragment
Navigation.findNavController(view).navigate(R.id.action_titleFragment_to_gameFragment)
Kotlin Extension function allow a class to extend the functionality of an existing class without subclassing it KTX has an
extension function for an android view class so with kotlin extension we can use
view.findNavController().navigate(R.id.action_titleFragment_to_gameFragment)
Android application provide onscreen back button which handle back stack just like back button in android device
Terminating a process
Make sure you are using a device or emulator running at least API level 28. This is easier to set up for an emulator.
Make sure adb is installed. If not, see instructions below.
Make sure your app is in the background - this only happens when the app is in the background. You can do this by hitting
the home button.
Run the command:
adb shell am kill com.example.android.dessertpusher
This will stop the process as-if it had been stopped by the Android operating system.
Adding ADB to your path
If you try running adb in a terminal and you see something similar to the message below, read on:
Command Line Interface showing "command not found" after typing adb
ADB (Android Debug Bridge) is command line tool, and if you want to use it from the command line, it needs to be part of
your path. First you’ll find where the adb executable
lives, then you’ll add that to your path.
1. Find the platform-tools folder which contains adb:
Adb is part of the Android SDK, which is downloaded as part of Android Studio. You can find the location of this SDK by
going to Tools -> SDK Manager
ADB is located in this location, followed by platform-tools/ so in the example above, you could find adb in:
/Users/lmf/Library/Android/sdk/platform-tools/
2. Add adb to your path:
Adding a variable to your path varies by platform, follow the instructions below to add the platform-tools
location you located above.
Windows
Go to Advanced system settings:
Windows 8 and 10: Search -> System (Control Panel) -> Advanced system settings
Windows 7: Right-click Computer -> Properties -> Advanced system settings
Windows Vista: Right click My Computer -> Properties -> Advanced system settings
Windows XP: Start -> Control Panel -> System -> Advanced tab
Click Environment Variables
Find the System Variables section and then look to see if you have a PATH environment variable:
If you find one, click Edit
If you do not find one, click New to add one
Add ;<Path to platform-tools> to the end of the Variable value box
Click OK on all windows to save
Ensure you can run adb by typing:
adb
You should see output, including something like:
text showing Android Debug Bridge version 1.0.40 Version 4986621
Mac/Linux
Adding a path variable is done using the terminal on Mac/Linux.
Open a Terminal
Create a .bash_profile file if you don’t have one already. This is a configuration file for bash) - it’s executed when you start bash:
touch ~/.bash_profile
Open up the ~/.bash_profile file in your preferred text editor:
open ~/.bash_profile
Add the following to your .bash_profile file and save:
export PATH=<Path to platform-tools>:$PATH
Either restart your terminal, or enter:
source ~/.bash_profile
Ensure you can run adb by typing:
adb
You should see output, including something like:
UiController(actiivty/fragment)
|
--[livedata]viewmodel
live data classes is crucial for communicating for the viewmodel to the ui controller that it should update and redraw the screen
viewmodel is an abstract class that holds app's ui data and survives configuration changes
best part is viewmodel has not restriction on size as in case of savedinstancestate which is 100k bytes
never construct viewmodel yourself if we did we end up constructing viewmodel everytime fragment were recreated which not solve
our rotation issue insteade lifecycle library created viewmodel for us with requesting viewmodelproviders
The ViewModel is a stable place to store the data to display in the associated UI controller.
The Fragment draws the data on screen and captures input events. It should not decide what to display on screen or process
what happens during an input event.
The ViewModel never contains references to activities, fragments, or views.
androidTest folder which require emulating android frameworks
test folder which run test without emulating android frameworks
Observer Pattern - We have an object called a subject which keeps track of a list of other object known as observers
observers watch or observe the subject when status of the subject changes it notifies the observer by calling a method in
observer. In livedata case subject is livedata object and observers are the ui controllers the state changes whenever data
wrapped inside of livedata changes
UIController ----> LiveData uicontroller observer for livedata value changes
UIController <---- LiveData livedata observer for uicontroller with lifecycleobserver
MutableLiveData which can be mutated but LiveData which we can read not modify not able to call set value used for encapsulation
Lifecycle Awareness -
uicontroller offscreen no updates
uicontoller backonscreen get updates
new uicontroller observes get current data
uicontroller destroyed, it cleans up connection
In some cases we need to pass data to viewmodel on initializations so general idea to create a viewmodelfactory
factories are the classed that knows how to instantiate classes
databinding - means taking data and bind it to the view object
DateUtils.formatElapsedTime(newTime) this formatting belongs to view modelto do simple manipulation to live data such as
changing integer to string we usemethod called transformation.map so we have LiveData A we apply transformations and then
resul to LiveData B which we observer
for complex transformation we have switch map or mediator live data
Mobile device have processor and these days most of them have multiple hardware processor that each run processes concurrently
this is called multiprocessing to use processor more efficiently the operating system can enable an application to create more
than one thread of execution within a process this is called multithreading.
/* Multithreading and Coroutines */
Mobile device have processor and these days most of them have multiple hardware processor
that each run processes concurrently this is called multiprocessing to use processor more
efficiently the operating system can enable an application to create more than one thread
of execution within a process this is called multithreading eg think of reading multiple book
at same time switching between books after each chapter eventually finishing all books
but we can't read in more than one book at the same time in this case reader represents
processor and each book represents code than needs to be executed and the act of reading
each book represent thread of execution.
scheduler it takes into account things such as priorities and makes sure all thread
get to run and finish and dispatcher which sets up threads that is it sends your books that
you need to read and specify the context for that to happen think context as separate
specialized reading room.
In android main thread is a single thread that handles all the updates to the UI and main
thread is also the thread that calls all click handlers and other UI and lifecycle callbacks
this is why it also called UI thread or default thread meaning unless you explicitly switch
threads or class runs on different threads everything you do is on main thread.
UI thread has to runs smoothly for great user experience app to display user without any pauses
main thread has to update the screens every 16ms or 60 frames per second.
so to get work done away from main thread a pattern for performing long running tasks without
blocking the main thread is callbacks by using callbacks we can start long running tasks on
a background thread when task complete callback supplied as an argument is calls to inform
of the result on the main thread but they have drawback callback become hard to read and they
while code look sequential the callback run at some asynchronous in future and callback
don't allow to use language features such as exceptions
In kotlin we have coroutines to handle long running tasks elegantly and efficiently.
in kotlin coroutines lets you convert callback based code to sequential code which make more
readable and even use language features such as exceptions.
coroutines are -
1.asynchronous 2.non blocking 3.sequential code - use suspend function to make asynchronous
code sequential - asynchronous means coroutines runs independently rom from the main
execution steps of the program.
one of the important aspect of async is that we cannot expect the result is available to us
until we explicitly wait for it. eg lets say we want an answer of a questions that requires
some research and we ask a colleague they go off and work on it which is if synchronously
and on separate thread unless we wait for answer we can continue to do other work that
doesn't not depend on their answer until they come back and tell you what the answer is.
Non-blocking means the system is not blocking the main or UI thread. because our coroutine
code is compiled from sequential code we don't need to specify callbacks and compiler will
makes sure that the results of coroutines are available before continuing and resuming.
Suspend is kotlin way of marking a function or function type available to coroutines. when
a coroutines called a functions marked with suspend instead of blocking untill the function
returns like normal function calls it suspend executions until the result is ready then it
resumes where it left off with the results while it suspends waiting for the result it
unblocks the threads that's it running on so other functions or coroutines can run. suspend
keyword doesn't specify thread code runs on suspend functions may runs on background thread
or main thread.
To use coroutines in kotlin we need
1.Job 2.Dispatcher 3.Scope
Job - a job is anything that can be cancelled all coroutines have a job and we can use this
to cancel the coroutines. jobs can be arranged in parent child hierarchy so cancellation
of parent leads to immediate cancellation of all its children.
Dispatcher - dispatcher sends off coroutines to run on various threads. Dispatcher.MAIN runs
task on main thread and Dispatcher.IO for offloading blocking of i/o task to shared pool of thread.
Scope - scope combines information, including a job and dispatcher, to define a context in
which coroutines runs. scope keeps track of coroutines when we launch a coroutines it's in
scope which means we said which scope keeps track of coroutines