# Mobile Application Development <!-- ### Tables of Contents - [Components of an Android App](#components-of-an-android-app) - [Android Project Structure](#android-project-structure) - [Layout Types](#layout-types) - [Activity Lifecycle Methods](#activity-lifecycle-methods) - [Views in Android](#views-in-android) - [Navigating between Activities](#navigating-between-activities) - [Adding Menu(s)](#adding-menus) - [Persistant Storage using SharedPreferences](#persistant-storage-using-sharedpreferences) - [Adding a Launcher Icon](#adding-a-launcher-icon) - [Units of Measurement in Android](#units-of-measurement-in-android) - [Database](#database) - [OOP](#oop) - [Appendix](#appendix) <br> <br> <br> --- <br> <br> <br> --> # Before Mid ## Components of an Android App 1. Activity. 2. Service. 3. Broadcast Receiver. 4. Content Provider. --- ## Android Project Structure ### manifests/AndroidManifest.xml - Contains metadata about the application. - The manifest file is the root of the Android application. - All android components are rgistered in the manifest file. - The manifest file contains the following: - Application name. - Application version. - Application package name. - Application icon. - Application description. - Application permissions. - Application activities. - Application services. - Application receivers. - Application content providers. ### java/ - Contains the source code/ backend for the application (Java Files). - Java files compile into classes (.class). ### res/ - Contains the resources for the application. - drawable, menu, mipmap, values, layout, etc. - **drawable:** images. - **menu:** menu xml files. - **mipmap:** icons. - **values:** strings. - **layout:** layout xml files. **All resources are compiled into R class.** **Dont use capital letters in resource names** --- ## Layout Types 1. Constraint Layout. 2. Linear Layout. 3. Table Layout. 4. Frame Layout. 5. Relative Layout (Legacy). 6. Grid Layout (Leagcy). ### Constraint Layout - Similar to position (absoulte, relative, ...) in CSS. - Postion of an element can be set releative to parent or sibling element. ```xml <!-- XML --> <ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/cl" > </ConstraintLayout> ``` ```java //JAVA ContraintLayout cl; // in onCreate() cl = findViewById(R.id.cl); ``` ### Linear Layout - Two types of layout: horizontal and vertical. - Horizontal layout: - Left to right. - Vertical layout: - Top to bottom. - Views are stacked after one another. ```xml <!-- XML --> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:id="@+id/vll" > </LinearLayout> ``` ```java //JAVA LinearLayout vll; // in onCreate() vll = findViewById(R.id.vll); ``` ### Table Layout - Similar to HTML table. - 2D layout. - Consists of rows. - Each row contains Views. ```xml <TableLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TableRow android:layout_width="match_parent" android:layout_height="match_parent"> </TableRow> </TableLayout> ``` ### Frame Layout - Only one view. --- ## Activity Lifecycle Methods 1. onCreate (Activity is created). 2. onStart (Activity is started). 3. onResume (Activity is resumed/ running/ in focus). 4. onPause (Activity is not in focus). 5. onStop(Activity is running in background, Home button pressed). 6. onRestart (Activity is restarted, in focus after onStop). 7. onDestroy (Removed from background). --- ## Views in Android - TextView - Button - EditText - ImageView ### TextView ```xml <!-- XML --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Hello World" android:id="@+id/tv" /> <!-- android:layout_width="match_parent" -> Defines width of the view same as its parent's --> <!-- android:layout_height="wrap_content" -> Defines height of the view so that it can wrap content inside it --> <!-- android:text="Hello World" -> Sets text to "Hello World" --> <!-- android:id="@+id/tv" -> Assigns id --> ``` ```java //in onCreate() //findViewById(id) TextView tv=findViewById(R.id.tv); String text=tv.getText().toString(); text=text+text; //setText(String) tv.setText(text); ``` <br> ### Button ```xml <!-- XML --> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btn" android:text="Click Me" android:layout_margin="10dp" android:layout_gravity="center" /> <!-- android:layout_margin="10dp" -> Adds 10dp margin on all sides --> <!-- android:layout_gravity="center" -> Defines the position of text inside the button --> ``` ```java //in onCreate() //findViewById(id) Button btn=findViewById(R.id.btn); //setOnClickListener(View.OnClickListener) btn.setOnClickListener(new View.OnClickListener() { //onClick(View) @Override public void onClick(View v) { btn.setText(btn.getText().toString()+"!"); } }); ``` <p style="font-weight:bold;font-size:32px">OR</p> Set onClick in XML. ```xml <!-- Set onClick Property in XML --> <Button ... android:id="@+id/btn" android:onClick="changeTextHandler" /> <!-- android:onClick="changeTextHandler" -> Adds a method which executes when the click event is triggered --> ``` Define changeTextHandler in Java. ```java public void changeTextHandler(View v){ Button btn=findViewById(R.id.btn); btn.setText(btn.getText().toString()+"!"); } ``` <br> ### EditText ```xml <!-- XML --> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/et" android:layout_margin="10dp" android:layout_gravity="center" android:hint="Enter Text" /> <!-- android:hint="Enter Text" Sets a placeholder text --> ``` ```java //in onCreate() //findViewById(id) EditText et=findViewById(R.id.et); String text=et.getText().toString(); ``` <br> ### ImageView ```xml <ImageView android:id="@+id/iv" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" tools:layout_editor_absoluteX="0dp" tools:layout_editor_absoluteY="16dp" tools:srcCompat="@drawable/ic_launcher_background" /> <!-- tools:srcCompat="@drawable/ic_launcher_background" -> Source of the image to be displayed in ImageView --> ``` --- ## Navigating between Activities ### Navigation using Intent - Intent is used for linking activities of same or separate applications. - Intent is used to navigate between activities. ```Java // Intent(Context, Class) Intent intent = new Intent(this, NextActivity.class); // startActivity(Intent) startActivity(intent); ``` ### Passing data using Intent - Intent can be used to pass data between activities. - putExtra() method is used to pass data. ```Java // putExtra(String, StringOrIntOrFloat...) intent.putExtra("name", "Hello World"); ``` - For passing multiple values, putExtra() can be used multiple times. - getStringExtra() method is used to get data. ```Java // getStringExtra(String) String recievedString=getIntent().getStringExtra("nameInString"); ``` --- ## Adding Menu(s) - For adding a menu: - Create a menu resource directory in res. - Add a menu resource file in res/menu (main_menu.xml). - Define the structure of menu in main_menu.xml. ```xml <!-- XML --> <!-- main_menu.xml --> <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/logout" android:title="Log Out"></item> </menu> ``` ### Types In android, there are 3 types of menu(s): 1. Options Menu (3 dots in App header). 2. Context Menu (opens on longpress). 3. Popup Menu (popups on click). #### Options Menu 1. Override onCreateOptionsMenu() method. ```java @Override public boolean onCreateOptionsMenu(Menu menu) { //inflate(menu resource id, menu) getMenuInflater().inflate(R.menu.main_menu,menu); return true; } ``` 2. Override onOptionsItemSelected() method. ```java @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { if(item.getItemId()==R.id.logout){ Intet intent = new Intent(this, FirstActivity.class); startActivity(intent); } return super.onOptionsItemSelected(item); } ``` #### Context Menu 1. Get the view that was longpressed. ```java TextView tv; //in onCreate() tv = findViewById(R.id.tv); ``` 2. Register the view with the context menu. ```java registerForContextMenu(tv); ``` 3. Override onCreateContextMenu() method. ```java @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); getMenuInflater().inflate(R.menu.main_menu,menu); } ``` 4. Override onContextItemSelected() method. ```java @Override public boolean onContextItemSelected(@NonNull MenuItem item) { if(item.getItemId()==R.id.logout){ Intet intent = new Intent(this, FirstActivity.class); startActivity(intent); } return true; } ``` #### Popup Menu 1. Add a button and set its onClick property. ```xml <!-- XML --> <!-- activity_main.xml --> <?xml version="1.0" encoding="utf-8"?> <ConstraitLayout ... > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnPopup" android:layout_margin="10dp" android:text="Show Popup" android:onClick="showPopup" /> </ConstraitLayout> ``` 2. define showPopup() method in MainActivity.java. ```java public void showPopup(View view){ } ``` 3. Create a PopupMenu, set the anchor view and inflate the menu using getMenuInfater().inflate() and show() the menu. ```java public void showPopup(View view){ //1. Create a PopupMenu //PopupMenu(Context, View) PopupMenu popupMenu = new PopupMenu(this,view); //2. Inflate the menu //inflate(menu resource id, menu) //getMenu() method is used to get the menu. getMenuInflater().inflate(R.menu.main_menu,popupMenu.getMenu()); //3. Show the menu popupMenu.show(); } ``` 4. Add a menu item click listener inside showPopup(). ```java public void showPopup(View view){ //1. Create a PopupMenu //2. Inflate the menu //3. Show the menu //setOnMenuItemClickListener(MenuItemClickListener) popupMenu.setOnMenuItemClickListener( new PopupMenu.OnMenuItemClickListener() { //onMenuItemClick(MenuItem) public boolean onMenuItemClick(MenuItem item) { if(item.getItemId()==R.id.red){ cl.setBackgroundColor(Color.RED); } return true; } }); } ``` --- ## Persistant Storage using SharedPreferences - For reading, SharedPreferences. - For writing, SharedPreferences.Editor. ### Reading Preferences 1. Create a SharedPreferences object. ```Java //in onCreate() //getSharedPreferences(String PrefernceName, int mode: 0||1) // 0 -> MODE_PRIVATE (Can only be accessed by the application) // 1 -> MODE_WORLD_READABLE SharePreferences sp = getSharedPreferences("MyPreferences", 0); ``` 2. Get the value of a preference. ```Java //getInt(String key, int defaultValue) color=sp.getInt("primary_color", 0); ``` ### Writing Preferences 1. Create a SharedPreferences.Editor object. ```Java SharedPreferences.Editor editor; //in onCreate() editor = sp.edit(); //in any method //putInt(String key, int value) editor.putInt("primary_color", Color.RED); //commit() method is used to save the changes. editor.commit(); ``` --- ## Adding a Launcher Icon 1. Right Click on the mipmap directory. 2. New -> Image Asset. 3. Configure the image. 4. Click Finish. 5. In AndroidManifest.xml, change the application icon to the image asset. ```XML android:icon="@mipmap/ic_launcher_2" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_2_round" ``` --- ## Units of Measurement in Android 1. Pixels (px) 2. Density-independent Pixels (dp) - 160 dp standard screen size. - 160dp is equivalent to one inch of physical screen size. 3. Scaled Pixels (sp) - Similar to dp and is recommended for specifying font sizes. 4. Point (pt) - 1 pt is 1/72 of an inch. 5. Inches (in) 6. Millimeters (mm) **Dots per Inch: dpi** --- ## OOP **Object** - Representation of a real world entity in programming. - Also called as an instance of a class. ```Java Person p=new Person(); ``` **Class** - A blueprint for creating objects. ```java public class Person{ } ``` **Interface** - An abstract class that defines methods that must be implemented by any class that implements it. - All methods in an interface are public and abstract by default. - "implements" keyword is used to implement an interface. ```java interface Man{ public void speak(); public boolean isMan(); } public class Person implements Man{ } ``` **Abstract Class** - A class that can't be instantiated. - Contains at least one abstract method. ```java public abstract class Male{ } public class Person extends Male{ } ``` **Abstract Method** - A method without body. ```java public abstract class Male{ public void getName(); } ``` **Instance Method** - A method that belongs to an object. - Must be called on an object. - Can be overridden by subclasses. ```java public class Person{ public void setName(String name){ this.name=name; } } ``` **Static Method** - A method that belongs to a class. - Can be called on a class (without initializing an object). ```java public class Person{ public static int count=0; public static void getCount(){ return count; } } ``` **Constant** - A variable that can't be changed. ```java public class Person{ public static final int MAX_AGE=100; } ``` **Inheritance** - "is a" relationship. - parent child relationship. - public and protected access. - "extends" keyword. ```Java public class Person{ } public class Student extends Person{ } ``` **Constructor** - A method that is called when an object is created. - Used for initializing the object. - Of two types: 1. Default constructor. 2. Parameterized constructor. - Default constructor is called when no constructor is defined. - If a constructor is defined, the default constructor is not called. - Default contructor has to be defined if any other constructor is defined. ```Java public class Person{ public Person(){ //Default constructor } public Person(String name){ //Parameterized constructor this.name=name; } } ``` **this** - refers to caller/calling object. ```java public class Person{ public void setName(String name){ this.name=name; } } ``` **super** - refers to constructor of the super/parent class. ```Java public class Person{ public Person(){ this.name=""; } } public class Student extends Person{ public Student(){ super(); } } ``` **Polymorphism** - The ability of an object to take on many forms. - Same method name with different parameters in same class (Overloading). - Same method name with different implementation in different classes (Overriding). **Enumerator OR Enum** - Collection of constant values. - Key/ Value pair. ```Java enum Levels{ LOW, MEDIUM, HIGH } ``` --- # After Mid ## Database ### SQLite Database 1. Extend class from `SQLiteOpenHelper`. 2. Create a parameterized constructor of class. 3. Overrride onCreate and onUpgrade. #### Querying Database For Reading data: ```java SQLiteDatabase db=this.getReadableDatabase(); ``` For Writing data: ```java SQLiteDatabase db=this.getWriteableDatabase(); ``` `SQLiteDatabase` provides built-in methods for inserting, updating and deleting data. For reading, raw queries are passed. 1. Insert ```java //db.insert(tbl_name<String>,nullValueReplacement, cv<ContentValues>); long result=db.insert("tbl_name",null,cv); //result= -1-> failed to insert, //result= 0-> 0 rows changed, //result n-> n rows changed ``` 2. Update ```java //db.update(tblName<String>,cv<ContentValues>,where_string<String>,new String[]{whereArgs<String>}); int result=db.update("tbl_name",cv,"col_1=?",new String[]{String.valueOf(col_1)}); //result= -1-> failed to update, //result= 0-> 0 rows changed, //result n-> n rows changed ``` 3. Delete ```java //db.update(tblName<String>,where_string<String>,new String[]{whereArgs<String>}); int result=db.delete("Student","col_1=?",new String[]{String.valueOf(col_1)}); //result= -1-> failed to delete, //result= 0-> 0 rows changed, //result n-> n rows changed ``` 4. Read ```java //db.rawQuery("query"<String>,new String[]{whereArgs<String>}); Cursor csr=db.rawQuery("Select * from tbl_name where col_1=?", new String[]{String.valueOf(col_1)}); ``` #### Example ```java class DB extends SQLiteOpenHelper{ //parameterized constructor public DB(Context context){ //super(context,db-name,factory,version); super(context,"Db_Name.db",null,1); } //Override onCreate public void onCreate(SQLiteDatabase db){ //db.execSQL("SQL Query"); db.execSQL("Create table if not exists tbl_name(col_1 data_type autoIncrement Primary Key, col_2 data_type unique)"); } //Override onUpgrade public void onUpgrade(SQLiteDatabase db, int i, int i1) { db.execSQL("Drop table if exists tbl_name"); } //Create a method for inserting data public boolean createData(String col_1, int col_2){ ContentValues cv=new ContentValues(); //put("key <String>", value); cv.put("col_1",col_1); cv.put("col_2",col_2); SQLiteDatabase db=this.getWritableDatabase(); //db.insert(tbl_name <String>, nullValueReplacement, ContentValues); long result=db.insert("tbl_name",null,cv); //result= -1-> failed to insert, result= 0-> 0 rows changed, result n-> n rows changed return result != -1; } //Create a method for updating data public boolean updateData(String col_1,int col_2){ ContentValues cv=new ContentValues(); cv.put("col_1",col_1); cv.put("col_2",col_2); SQLiteDatabase db=this.getWritableDatabase(); //db.update("tbl_name",ContentValues,"where_string like col_1=?",new String[]{col_1, col_2}); int result=db.update("tbl_name",cv,"col_1=?",new String[]{String.valueOf(col_1)}); //result= -1-> failed to insert, result= 0-> 0 rows changed, result n-> n rows changed return result != -1; } //Create a method for deleting data public boolean deleteData(int col_1){ SQLiteDatabase db=this.getWritableDatabase(); //db.delete("tbl_name","where_string",new String[]{col_1}) int res=db.delete("Student","col_1=?",new String[]{String.valueOf(col_1)}); //result= -1-> failed to insert, result= 0-> 0 rows changed, result n-> n rows changed return result != -1; } //Create a method for reading data public Cursor readUser(String col_1, int col_2){ SQLiteDatabase db=this.getReadableDatabase(); //db.rawQuery("SQL Query where col_1=? AND col_2=?",new String[]{col_1,col_2}); Cursor csr= db.rawQuery("Select * from tbl_name where col_1=?", new String[]{col_1}); return csr; } } ``` --- ## Layouts ## Views 0. (ArrayAdapter) 2. Spinner (Static + Dynamic) 3. ListView (Static + Dynamic) 4. RadioButton & RadioGroup 5. TimePicker 6. SeekBar 7. ProgressBar 8. RatingBar 9. DatePicker ### ArrayAdapter - Modifies an array into the array of widgets or something else. - Follows Adapter design pattern. ### Spinner - The Spinner Items can be set statically, in xml by assigning a string array to `entries` property and dynamically, in java by creating a Array of Spinner List Items using `ArrayAdapter`. ```xml <!-- XML --> <Spinner android:id="@+id/spinner2" android:layout_width="409dp" android:layout_height="wrap_content" /> ``` ```java //JAVA String[] cities = {"A","B","C","D"}; String selectedCity; Spinner sp=findViewById(R.id.spinner2); ArrayAdapter<String> a1=new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,cities); sp.setAdapter(a1); sp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { selectedCity = adapterView.getItemAtPosition(i).toString(); } @Override public void onNothingSelected(AdapterView<?> adapterView) { } }); ``` ### ListView ```xml <!-- XML --> <ListView android:id="@+id/lv" android:divider="@color/black" /> ``` ```java //JAVA String[] cities = {"A","B","C","D"}; ListView lv=findViewById(R.id.lv); ArrayAdapter<String> a1=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1 , android.R.id.text1,cities); lv.setAdapter(a1); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { //i is the index of item. Toast.makeText(MainActivity.this, cities[i], Toast.LENGTH_SHORT).show(); } }); ``` ### RadioButton & RadioGroup ```xml <!-- XML --> <RadioGroup android:id="@+id/rgGender" android:layout_width="0dp" android:layout_height="wrap_content" > <RadioButton android:id="@+id/rbMale" android:layout_width="wrap_content" android:layout_height="55dp" android:checked="true" android:text="Male"/> <RadioButton android:id="@+id/rbFemale" android:layout_width="wrap_content" android:layout_height="55dp" android:checked="false" android:text="Female" /> </RadioGroup> ``` ```java //JAVA radioGroup = findViewById(R.id.rgGender); radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int i) { if(radioGroup.getCheckedRadioButtonId()==R.id.rbMale) gender="Male"; else if(radioGroup.getCheckedRadioButtonId()==R.id.rbFemale) gender="Female"; } }); ``` ### TimePicker ```xml <!-- XML --> <TimePicker android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/tp"/> ``` ```java //JAVA TimePicker tp=findViewById(R.id.tp); tp.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() { @Override public void onTimeChanged(TimePicker timePicker, int i, int i1) { Toast.makeText(MainActivity.this,timePicker.getHour()+":"+timePicker.getMinute(), Toast.LENGTH_LONG).show(); } }); ``` ### SeekBar ```xml <!-- XML --> <SeekBar android:id="@+id/sb" android:layout_width="match_parent" android:layout_height="wrap_content" /> ``` ```java //JAVA SeekBar sb=findViewById(R.id.sb); sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { Toast.makeText(MainActivity.this, ""+i, Toast.LENGTH_SHORT).show(); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); ``` ### ProgressBar ```xml <!-- XML --> <ProgressBar android:id="@+id/pb" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" /> ``` ```java //JAVA ProgressBar pb=findViewById(R.id.pb); pb.setProgress(50); Toast.makeText(MainActivity.this, ""+pb.getProgress(), Toast.LENGTH_SHORT).show(); ``` ### RatingBar ```xml <!-- XML --> <RatingBar android:id="@+id/rb" android:layout_width="wrap_content" android:layout_height="wrap_content" android:stepSize="0.5" /> ``` ```java //JAVA RatingBar rb=findViewById(R.id.rb); rb.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() { @Override public void onRatingChanged(RatingBar ratingBar, float v, boolean b) { Toast.makeText(MainActivity.this, ""+ratingBar.getRating(), Toast.LENGTH_SHORT).show(); } }); ``` ### DatePicker ```xml <!-- XML --> <DatePicker android:id="@+id/dp" android:layout_width="match_parent" android:layout_height="0dp" /> ``` ```java //JAVA DatePicker dp=findViewById(R.id.dp); Calendar c=Calendar.getInstance(); dp.init(c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH), new DatePicker.OnDateChangedListener() { @Override public void onDateChanged(DatePicker datePicker, int i, int i1, int i2) { //i2=Day //i1=Month //1=Year Toast.makeText(MainActivity.this, i2+"/"+(i1+1)+"/"+i, Toast.LENGTH_SHORT).show(); } }); ``` ## Debugging - `Log` class is used for showing logs in Logcat console. - `Log` ## Activity Lifecycle Methods ![](https://i.imgur.com/ZlMaglz.png) ## Fragments - Mutliple screens on one Activity. - One fragment can be reused on multiple Activities. - Views can be added in a fragment. - A fragment has its own xml and java file. - A fragment also has a lifecycle. - A fragment can be added statically or dynamically. ### Creating a fragment - Create a new fragment. - Right click on MainActivity.java - Goto New -> Fragment -> Fragment(Blank) - Add Fragment Details and click Finish. This will create a java and a xml file for the Fragment. ### Adding a fragment #### Placing a fragment statically ```xml <!-- In activity_main.xml, --> <!-- add a FramLayout and a fragment in it--> <FrameLayout android:id="@+id/fl" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <fragment android:layout_width="match_parent" android:layout_height="match_parent" android:name="com.mad.BlankFragment" /> <!-- android:name-> Refernce to the java file of Fragment (statically placed) --> </FrameLayout> ``` #### Placing a fragment dynamically 1. Add a FrameLayout in Activity. ```xml <!-- in activity_main.xml --> <FrameLayout android:id="@+id/fl" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> </FrameLayout> ``` 2. Place/ Change fragment dynamically from java file. For performing opertaions on fragments dynamically, we need an instance of `FragmentTransaction` which is octained from `FragmentManager`. ```java FragmentManager manager=getSupportFragmentManager(); FragmentTransaction transaction=manager.beginTransaction(); //add(ContainerId<int>,<Fragment>) -> adds Fragment on top. transaction.add(R.id.fl,new FragmentNew()); //Completes the transaction transaction.commit(); //Other transaction methods // transaction.remove(<Fragment>); --Removes a fragment // transaction.replace(ContainerId<int>,<Fragment>) -> replaces top Fragment with another Fragment. ``` __Fragments & Activites work on Stack. When back button is pressed the top fragment is poped out from the Fragment Stack and the new top fragment is displayed. Similarly, when a new Fragment is opened from a button on Previous Fragment, the New Fragment is pushed into Fragment Stack and becomes top Fragment.__ ### Fragment Lifecycle Methods ![](https://i.imgur.com/lwwZo3w.png) --- ## Services - Services are the tasks/ processes running in the background. - Two main Types: 1. Starting Service. 1. Foreground Service. 2. Background Service. 2. Bound Service. - Service Lifecycle Methods. ### Service Lifecycle Methods ![Service Lifecycle](https://developer.android.com/images/service_lifecycle.png) #### 1. Creating a Service - Create a ServiceClass extended from `Service` - Override: - `onBind` (for Bound Service). - `onStartCommand` (for Starting Service). - `onUnbind` (for unbinding a Bound Service). - `onDestroy` (for stoping a service). ```java class ServiceClass extends Service{ public IBinder onBind(Intent intent) { return null; } public void onCreate() { super.onCreate(); } public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } public void onDestroy() { super.onDestroy(); } } ``` #### 2. Registering a Service. - In AndroidManifest.xml ```xml <service android:name=".FirstService" android:exported="false"/> ``` #### 3. Starting a Service. - In MainActivity.java, ```java //Create a new Intent Intent serviceIntent=new Intent(this, ServiceClass.class); ``` - In MainActivity.java, In onStart, ```java //Start Service using Intent startService(serviceIntent); // startService will call onCreate + onStartCommand or onBind ``` #### 4. Stoping a Service. - In MainActivity.java, In onStop, ```java //Stop Service using Intent stopService(serviceIntent); // startService will call onDestroy ``` ##### Service Example ```java public class FirstService extends Service { MediaPlayer player; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); player=MediaPlayer.create(this,R.raw.mp3file); } @Override public int onStartCommand(Intent intent, int flags, int startId) { player.start(); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); player.stop(); } } ``` ### Foreground Service - Foreground services perform operations that are noticeable to the user. - Foreground services show a status bar notification, so that users are actively aware that your app is performing a task in the foreground and is consuming system resources. - The notification cannot be dismissed unless the service is either stopped or removed from the foreground. - Examples of apps that would use foreground services include the following: - A music player app that plays music in a foreground service. The notification might show the current song that is being played. - A fitness app that records a user's run in a foreground service, after receiving permission from the user. The notification might show the distance that the user has traveled during the current fitness session. #### 1. Add Permission in the App for Foreground Service - In AndroidManifest.xml ```java <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> ``` #### 2. Create a Service - Override the `onStartCommand` to start a notification. If this step is missed, Android will kill the service after around a 1 minute of execution time. ```java public int onStartCommand(Intent intent, int flags, int startId) { Intent notificationIntent= new Intent(this, MainActivity.class); PendingIntent pi=PendingIntent.getActivity(this,0,notificationIntent,0); //Check if OS version is Android 8 or above. if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.O){ //Create a Notification Channel NotificationChannel channel=new NotificationChannel("channel_id","channel_name", NotificationManager.IMPORTANCE_DEFAULT); //Set channel description channel.setDescription("Hello World"); //Register channel NotificationManager manager=getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } NotificationCompat.Builder builder=new NotificationCompat.Builder(this,"channel_id"); builder.setContentTitle("Forground Service"); builder.setContentText("Running..."); builder.setSmallIcon(R.drawable.ic_launcher_foreground); builder.setContentIntent(pi); startForeground(121212,builder.build()); return super.onStartCommand(intent, flags, startId); } ``` #### 3. Start the forground Service - In MainActivity, ```java Intent i = new Intent(context, ForegroundService.class); // Check if Android version is 8 or above if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(i); } else { startService(i); } ``` ### Bound Service - A bound service is the server in a client-server interface. - It allows components (such as activities) to bind to the service, send requests, receive responses. - A bound service typically lives only while it serves another application component and does not run in the background indefinitely. - To provide binding for a service, the `onBind()` method must be implemented. This method returns an `IBinder` object that defines the programming interface that clients can use to interact with the service. - For allowing a client to bind to the service, call `bindService()`. - Bound Service must be explicitly stopped by the service by calling `stopSelf()` or `stopService()`. --- ## Broadcast Reciever ### Global Broadcast Reciever #### Creating a Reciever class ```java public class FirstBroadcastReciever extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Airplane Mode Chnaged", Toast.LENGTH_LONG).show(); } } ``` #### Register the global braodcast reciever statically (in Android Manifest) - In AndroidManifext.xml ```xml <receiver android:name=".FirstBroadcastReciever" android:exported="true"> <intent-filter> <action android:name="android.intent.action.AIRPLANE_MODE"/> </intent-filter> </receiver> ``` #### Register the global broadcast dynamically (in java) ```java //In MainActivity, in onCreate, // Create instance of FirstBroadcastReciever FirstBroadcastReciever reciever= new FirstBroadcastReciever(); //Create an Intent Filter IntentFilter intentFilter = new IntentFilter(); //Register an Action intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); //Register the boradcast Reciever and action registerReceiver(reciever, intentFilter); ``` ### Local Broadcast Reciever #### Creating a Reciever class ```java public class FirstBroadcastReciever extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String log=intent.getStringExtra("log"); Toast.makeText(context, log, Toast.LENGTH_LONG).show(); } } ``` #### Creating and Sending a Local Broadcast ```java //in MainActivity, in onCreate LocalBroadcastManager m=LocalBroadcastManager.getInstance(this); Intent localIntent=new Intent("LOCAL_ACTION"); //Attaching data with local broadcast localIntent.putExtra("log","Data attached with Local broadcast"); //Sending local broadcast m.sendBroadcast(localIntent); ``` - Local broadcast reciever can be registered in java only. #### Listening to the local broadcast ```java //In OtherActivity, in onCreate, // Create instance of FirstBroadcastReciever FirstBroadcastReciever reciever= new FirstBroadcastReciever(); //Create intent-filter IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("LOCAL_ACTION"); //Register BroadcastReciever LocalBroadcastManager m=LocalBroadcastManager.getInstance(this); m.registerReceiver(reciever, intentFilter); ``` --- ## Notifications 1. Register Notification Channel (A Notification Channel is like a Notification Category). 2. Build Notification. 3. Setup Action on Noification (The actions perform on Notifications are handled by OS. We need to tell Os how to handle these actions. For that `PendingIntent` is used. `PendingIntent` is an `Intent` that is triggered by OS). 4. Trigger a Notification. #### 1. Registering a Notification Channel Notification Channels are available in Android 8 or above. ```java //Check if OS version is Android 8 or above. if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){ //Create a Notification Channel NotificationChannel channel=new NotificationChannel("channel_id","channel_name", NotificationManager.IMPORTANCE_DEFAULT); //Set channel description channel.setDescription("Hello World"); //Register channel NotificationManager manager=getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } ``` #### 2. Building a Notification ```java //Build Notification NotificationCompat.Builder builder=new NotificationCompat.Builder(this,"channel_id"); builder.setContentTitle("Notification Title"); builder.setContentText("Notification Content"); builder.setSmallIcon(R.drawable.ic_launcher_foreground); ``` ##### Adding a Button ```java //Create a pending intent PendingIntent pi=PendingIntent.getActivity(this,0,i,0); //Add Button and add PendingIntent to that button. //PendingIntent will be triggered when the button on notification will be pressed. //addAction(iconId<int>,ButtonText<String>,<PendingIntent>) builder.addAction(R.drawable.ic_btn,"Press Me",pi); ``` #### 3. Setting up Action on Notification For setting up action on a notification `Pending Intent` is used. A `PendingIntent` is an intent that is triggered by the OS. ##### Creating a PendingIntent ```java //Perform Action On Notification Intent i=new Intent(this,MainActivity.class); //getActivity(<Context>, requestCode<int>, i<Intent>, flags<int>) PendingIntent p=PendingIntent.getActivity(this,0,i,0); ``` ##### Adding PendingIntent to Notification ```java //setContentIntent(p<PendingIntent>) builder.setContentIntent(p); ``` #### 4. Triggering a Notification ```java NotificationManagerCompat manager=NotificationManagerCompat.from(this); //void notify(id<int>,notification<Notification>) manager.notify(121212,builder.build()); //build() builds and returns the Notification instance based on the configurations set using builder ``` --- ## Appendix **Activity** - A collection of views that are displayed together on the screen. - An activity is a single screen that is displayed to the user. - Consists of a java file and an xml file. **Service** - Service is a background process that runs in the background. **AppCompatActivity** - It is used to extend the Activity class. - Life cycle methods are declared in AppCompatActivity. **Toast.makeText** - Static Method (Can be called directly from the class). **Toast.LENGTH_LONG** - Static Constant. **In Programming, It is a convention to declare the constants in CAPITAL LETTERS.** **R** - All resources are compiled into R class. - R.id contains all the ids of the views. **Color** - Color class contains all the color constants (RED, GREEN, etc). **findViewById(id)** - It is used to get the view by its id. - Then the view is further stored in a variable of the same type. **setText(String)** - It is used to set the text of the view. **getText()** - returns the text of the view as an Editable object which is then converted to String. **setBackgroundColor(int)** - It is used to set the background color of the view. **Context** - It is used to get the context of the activity. - Context means the environment in which the activity is running. **setOnClickListener(View.OnClickListener)** - It is used to set the OnClickListener of the view. **View.OnClickListener** - An interface. - Has to be implemented at the moment of creating the object. **onClick(View)** - It is called when the view is clicked.