Mobile App Development Lifecycle
Inception > Design(UX->UI) > Development > Stabilization > Distribution |
IDEs for Mobile App Development
Android Studio (Java/Kotilin), XCode (Objective C/Swift, can only run on MacOS), Microsoft XNA (C#, for Windows Phone apps), cocos2d(multi-language and platform, for games), Unity (C#, cross-platform), React Native (JS, cross-platform), Flutter (Dart language), Apache Cordova (HTML5, CSS3 and JS, cross-platform), MiniProgram (for making lightweight apps that don't require installation and occupy little memory/space) |
UI Design
Principles: User familiarity, consistency, minimal surprise, recoverability, user guidance, user diversity |
Broadcasts
Broadcasts are messages sent whenever an event of interests occurs from the Android System or from apps. Apps can register to receive certain broadcasts. They must be defined programatically in the code in addition to being declared in the manifest with intent filters. <intent-filter><action android:name="ACTION"/></intent-filter>
BroadcastReceivers have an onReceive() function to check intent.action. |
Server Connection
Must include the following permissions:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
WebView is a View that can be display web pages in your app. |
|
|
Java vs Kotilin
Functionspublic fun sum(a: Int, b: Int): Int { return a + b }
|
Variables//val is immutable. var is mutable// val a: Int = 1 val b: String = “tim”{nl} //Types Int, String are optional and can be excluded//
|
Nullable variable var str S2? = "hku" str = null
Null safety var str: S2? = "hku" val I = S2?.length //if S2 is null, I is set o null
|
Arrays val num = arrayOf(1, 2, 3, 4) //implicit type declaration val num = arrayOf<Int>(1, 2, 3, 4) //explicit type declaration for (i in 0..num.size-1) { print(num[i]) }
|
Classesclass Person(val name: String, val age: Int? = null) //Declares class and constructor in one line! val person1 = Person(“Sam”, 20) //No new keyword
|
UI Elementsval edit_text1 = findViewById<View>(R.id.editText1) as EditText val button1 = findViewById<View>(R.id.button1) as Button val listener = View.OnClickListener {edit_text1.setText("hello!")} button1.setOnClickListener(listener)
|
Android Layout
Inflate the layout file in OnCreate():
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);}
FrameLayout: Display a single item at a time. All elements are positioned based on top left of the screen, and multiple elements will overlap.
LinearLayout: Organizes elements along a single line, either horizontal or vertical (defined in XML property android:orientation="horizontal"
)
RelativeLayout: android:layout_above/below/toLeftOf/toRightOf android:layout_alignBaseline/Bottom/Left/Right/Top
TableLayout: <TableLayout><TableRow><Element android:layout_column="1"/></TableRow>...</TableLayout>
ConstraintLayout: Constrain a component to be in a position relative to another element. For example, app:layout_constraintLeft_toRightOf="@+id/element"/>
would constrain the left side of the target to the right side of the other element. Rember, it is app:layout, NOT android:layout.
Use sp for font size, as it scales with user font preferences, and dp for others as it changes based on different screen density. |
Concurrency
A process is an instance of a program that is being executed or processed. They don't share resources. Switching between process is expensive. Threads are segments of processes and share memory. Thread{...}.start()
Main Thread is the UI thread which renders everything onscreen. Two rules of Android UI: Do not block the UI thread. Do not access the UI toolkit from outside the UI thread.
Runnable is a class that can be run inside a Thread with just 1 method: run(). Remember to use myUIElement.post{ Runnable } to force the Runnable object to join a queue so as to not break the rule. Handlers can also be used to update the UI thread ( handler.post{ Runnable }
). Remember, Threads cannot update UI, only Handlers. Before running post() using Handler, call handler.removeCallbacks(runnable) to remove any pending posts of the runnable in the queue so as to avoid repeated task. handler.postDelayed(runnable, time) delays the runnable from starting until after the specified time. |
|
|
Intents and Filters
Intents are messages sent between Activity, Service and Broad Receivers. Explicit intents are used within the application for tasks such as switching between activities. They specify which component should be called. Kotilin: intent = Intent(this, FooActivity::class.java) startActivity(intent); Implicit intents only specify the action to be performed, and are sent to the Android system which chooses which component should be used. Kotilin: intent = Intent(Intent.ACTION_VIEW, Uri.parse(URLStr)); startActivity(intent);
Activity needs Intent Filter to receive implicit intents. <intent-filter> <action android:name = "hkucs.myintentfilter" /> <category android:name = "android.intent.category.DEFAULT" /> </intent-filter> Passing extra data: Sender: myIntent.putExtra("ID", 6963)
Recpient: val bundle: Bundle? = intent.extras bundle?.let {bundle.apply { val inputString: String? = getString(“ID") // id = 6963}}
|
Fragment
Must implement: onCreate() - called when creating the fragment, should initialize essential components you want to retain when the fragment is paused or stopped, then resumed. onCreateView - called when the fragment draws its user interface for the first time. Optional: onPause() - called when the user is leaving the fragment.
Kotilin implementation
val manager: FragmentManager = supportFragmentManager val ft: FragmentTransaction = manager.beginTransaction() if (fragment != null) ft.replace(<ID of region in main layout>, <class name of fragment>(), <number tag to represent fragment>); ft.commitAllowingStateLoss();
|
Service
StartService(): runs indefinitely even if caller app dies. Simple, single task. No return result. Cannot be called back or modified after it is sent out.
BindService(): Can be bound to multiple components. Terminates if all callers die. Can be modified after being sent out.
A service can be both started and bound simulatenously.
Activating service: val intent = Intent(this, HelloService::class.java); startService(Intent);
Return value of onStartCommand():
START_NOT_STICKY: Do not recreate after kill. Caller can restart unfinished jobs
START_STICKY: Recreate, but do not redeliver last intent. Continuous work but stateless, e.g. media players.
START_REDELIVER_INTENT: Recreate, and redeliver last intent. Actively performing a job, e.g. file download |
Storage
SharedPreferences: Private primitive data in key-value pairs (persistent storage)
Bundles: Private primitive data in key-value pairs (temp storage for activity-fragment transfer)
Internal storage: Private data on device memory
External storage: Public data on internal or shared external storage, e.g., SD card
SQLite database: Structured data (table) in a private database |
|