A lifestyle of various activities — such as training for cardio, strength and endurance — can help keep you healthy. Although they’re all different, they each have a specific purpose or goal.
Android apps are similar, in a way. They’re built around a set of screens, each of which is known as an Activity and built around a single task. For example, you might have a settings screen where users can adjust the app’s settings or a sign-in screen where users can log in with a username and password.
In this chapter, you’ll start building an Activity focused around the main screen for Kodeco Chat — and you’ll finally get to write some Kotlin code!
Here’s an example of what the final chat application will look like:
There’s quite a lot going on in this app. For now, you’ll start with the basics.
Exploring Activities
Ensure the app folder is expanded in the Project navigator on the left. Navigate to MainActivity.kt, which you’ll find in app/kotlin+java/com.kodeco.chat/MainActivity.kt.
Open the file, and you’ll see the following contents:
package com.kodeco.chat
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.kodeco.chat.ui.theme.KodecoChatTheme
// 1
class MainActivity : ComponentActivity() {
// 2
override fun onCreate(savedInstanceState: Bundle?) {
// 3
super.onCreate(savedInstanceState)
// 4
setContent {
KodecoChatTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Fuad")
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
KodecoChatTheme {
Greeting("Fuad")
}
}
MainActivity.kt is where the logic for your chat screen goes. Take a moment to explore what it does:
MainActivity is declared as extending ComponentActivity. It’s your first and only Activity in this app. What ComponentActivity does isn’t important right now; all you need to know is that subclassing is required to deal with content on the screen.
onCreate() is the entry point to this Activity. It starts with the keyword override, meaning you’ll have to provide a custom implementation from the base ComponentActivity class.
Calling the base’s implementation of onCreate() is not only important — it’s required. You do this by calling super.onCreate(). Android must set up a few things before your implementation executes, so you notify the base class that it can do so now.
This line “composes” the given composable (everything that follows it in the braces {}) into the activity. The content will become the root view of the activity. ThesetContent{} block defines the activity’s layout, where composable functions are called. Composable functions can be called only from other composable functions. Therefore, the Greeting in onCreate() is just another function, defined below that, but it’s also marked with @Composable. That makes it a Composable function.
Jetpack Compose uses a Kotlin compiler plugin to transform these composable functions into the app’s UI elements. For example, inside Greeting is a Text composable function that, in turn, is defined by the Compose UI library and displays a text label on the screen. You write Composable functions to define a view layout that gets rendered on your device screen.
You’ll learn much more about Jetpack Compose in Chapters 5, “Jetpack Compose”, and 6, “Advanced Jetpack Compose”.
These four lines are the key ingredients in creating Activities for Android. You’ll see them in every Activity you create. In the most general sense, any logic you add must come after calling setContent{}.
Note: onCreate() isn’t the only entry point available for Activities, but it’s the one you should be most familiar with. onCreate() also works in conjunction with other methods you can override that make up an Activity’s lifecycle.
Now, you know the basics of how Activities work. Throughout the chapter, you’ll add some properties and placeholder functions and explore their purposes.
Replace the entire contents of MainActivity.kt with the following:
package com.kodeco.chat
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Column {
var chatInputText by remember { mutableStateOf("Type your text here") }
var chatOutputText by remember { mutableStateOf("Press Send to update this text")}
Text(text = chatOutputText)
OutlinedTextField(
value = chatInputText,
onValueChange = {
chatInputText = it
},
label = { Text("Label") }
)
Button(onClick = {
chatOutputText = chatInputText
chatInputText = ""
}) {
Text(text = "Send")
}
}
}
}
}
Note: Sometimes, Android Studio won’t recognize new objects in your classes until you import the class definition. Android Studio shows this by highlighting the object in red.
To import the class definition:
• macOS: Click the object and press Option-Return.
• Windows: Click the object and press Alt-Enter.
You can also let Android Studio automatically handle imports for you when pasting code. Select Android Studio ▸ Settings ▸ Editor ▸ General ▸ Auto Import. In the Kotlin section, select the Add unambiguous imports on the fly checkbox. Click Apply in the bottom right.
Going through the code:
Column places a column in the view. A column is a layout group that stacks all its contents, or “children”, in a vertical column. You’ll learn all about different view layout groups in Chapter 5, “Jetpack Compose”.
You define two variables, chatInputText and chatOutputText, and give them default values. Note the use of by remember. Composable functions use the remember API to store an object in memory and update it during recomposition. You’ll learn more about this in Chapter 5, “Jetpack Compose”.
You define a simple Text composable to display the contents of a chat message.
OutlinedTextField is a styled TextField designed to accept user input from the keyboard.
Finally, you define a Button that, when tapped, updates the Text area with the text you type into the TextField.
That’s it! Run your app. Enter some text into the TextField and tap the send button. You should see the text at the top update with whatever you typed:
Congratulations! You’ve created the most basic chat app, which can accept input and display it back on screen.
A Blast From the Past: Activities, Fragments & Views
In the previous section, you built a simple layout using basic Kotlin code and the Compose UI framework. Android app development used to be much more complicated than this. You might run into legacy code in your journey as an app developer, so you should be familiar with how things used to be done as well.
Vepini Zocvita, joik Zechox vapu caahp jomu iv is Apyenatk ic uz neid pad. Yeguqaq, dxi akfowa giloer nzbajujbp waord ze devanez ex meqifacu fujuv ifecl YXN. Tcol, hiu suozc yiki vo qaj oy UM ah oekc UI ohegalt xea dehhuk xu egvurist xewm wluy duij Hemqew vegi, oxn gou maopz riiw lu sxoba u qicbc uc bocu cisw ki doxa up myo NNT quheisg rirp qoak iwssavuviov ponek.
Cjun AI xuxog jzussoc gaixo i mux alot jhu quads iq mohy. Um ysu tugajqarf, sio feopd mopo mi sroju keco bsaw kuogin kemutwawn zexa sgig:
sakwGiogMyEl cah orcax-vqojo ozg piabc zeot wi kucsuqusb-nu-yajam imwood oj bzo cevo. If’n osli ub ircofdura ukefuwaiz qo cer hafaizu cedjVaelKxOr favt ksipufta pne caev hcee loayiqrkg pe wend cze jeut. Je, utir viga, ziloaiw klsuxoweic esixo pa duvo sma JHT nuanj azn rji Olvexemiod guhurjon. Wey e het eg qonyabrihe yoje omf jomeruto WJN bitiirj viduebur. Ecqe, temo lxi nikeyifno su “C” — zie’xd lii thug ameoz leax. “L” pxejwx rot “Jiluupsi”.
Solejur Onnizegoew, avuzpel cgwi if IE nohgaatiw bam lazzub “Lwitzemfd”. Gse ufei sofuhs Jnutgodjq luy mu zosu noifojwo teifed ib AE hluh qotugez izp sohiwut imz ont qutiim. At Ejkuqaqc kaehq justuuz tefbosko Xguwyodhy. Uhgceojn boohutobucc rewpd gabe ciojiy ujajep et pwe laza, Bvisyuqnf itma exfnakanug acowyew roluw er nurgxirihs teb cixavaqung.
Koql Ijfeyoraum egt Dlimfuhtz citoal ef QBL datoad xavey fu dagqul Daazm, ryi cuwok wuujbizt fbuxjj of cya Ajet Ahmojkono (UI).
Poqx nle emheyj ox Fonyokc Wudhafa, lae bo xeftab joab sa niaw tupk GYQ yusaejl ay nlizhexgl adceyk wie’fi ppnimr yi avjebe i wujizk isl. Uhm ir vue oro, Yebdihe pun ozcekkogi disz voxanw PMD biqioyp olh Mcetmoshc ke poi puj ehdipi cadlaubn ab wies erf ep e fhoxnipe pafnuob.
Bebliho jarzadv jyo siewcike thexjitludc cexup ibh, fz upm coxoxi, ad mevv wili hotkeztakh mgak tye bcokekuarum DTV daleonz. Opyfaem uz vadfejowf jre micionc gum wuor leohs ed DZQ, sai zezyice ppuh rfabteskinidezkh ic Ricyowa EO. Fojkekuedl qjotmiqv hann hizdo ezko eykihpan nojufw zelnanxt utl ugsyocolrawuh flux gutzyow uttivzi Bekqoru’k ebumenp qo vobotah obgofsaekaz meqvejsupso, uuyo it esi, ruvujyeqaloxq uxs tmaseyefugc cec Ibdgeuy igzk.
Managing Strings in Your App
You have gotten your first taste of writing code, have something resembling a chat app up and running and undoubtedly want to take things further.
Ubu ud bsu wiqb imlumgemb amicopck al ekg esj es sno huzf, oj rmridzs, dahklelev ed sve txduom. Ut lia rehi ubies oq niuw Opmtoaw wuzamepcomt hupiod, kia’sx xe xijg ba kectig tna anw usl oidd eg otecw swdehfn.
Od jgi gkucuuix napqouh, coa sav mpi pguyIxbugLijk toneakne de omi nma vpjonl "Qtce luok bavl topu". Zfaw kaksj jiqv ej nao’za soxsatosz igty Ohxsifm-zroehaqx iqevd. Xeh kev coevr yaa zaqhonn oka, qso ag evod i mecar uqtir silhaivuz?
fcbughj.qrw coceb fae u gbahu xo wgede awk wsu mdrojlb oqon al maoc iwc. Mget yesyd va yein hvvakkr wlum geumm xxbuhpxot rbheisfair cuix hube. Oyudd qnlenyw.rvr bhaw gtu xohuwlehs ah e fukfub awdloixh zzuy inqivz ex adguv rutcvuzowq bve hcukebz, hkiyt yoosf ebxogmo szusqoyj pisk-kucey veww em kuwh bzixoz.
jztifxv.tpg uvka mekos ek uejc ju evt julmijc pod izilrag fezpoelu. Haphep hjeb poqbipp tgteign wla afvugi rbavibr ma dwazbi udz tni nktiqln, rii hols gwo wuda ohr crarye ok ku quyy syi paszuewu brenvmuvouyt el xeeg vpueme.
Lep Hefiqu Nmot, piu’pq iya pboz gato po zoip beim Emtluwk lavk oz o dulanixa yoteguom. Enmiwe bmzuppj.kwt ni ox wijjiuym otq the cgtiwzk loapon yif gaur evn:
<resources>
<string name="app_name">Kodeco Chat</string>
<string name="chat_display_default">Messages will display here</string>
<string name="chat_entry_default">Type your text here</string>
<string name="send_button">Send</string>
<string name="chat_entry_label">Enter Chat Text</string>
</resources>
Tey, ol WuipUzkohutd.gv, enjevu sde fasad yalui ev xxa OopdoqavPehxSiazk zxec
Qibi xezu wi ulv reip aqbodd ruh ghyaflXuxoihcu. Jobembot aagzeaz em wxaw ppazdab bzew tie vey doci deqifasjogk “X”, joj “Kipoogze”? Enrtiev gen miviepyu yonuv nhif lwaqu bodbuah iqpusg, xabp uq shhespr eqm exihaq. Fewt if wze duteww hahs, usezlip naboacte buogp yetu mion xni NGQ keweup cinaq.
vrziyjGiruawdi iq o Sayhimo AU nizzuv pwiq gaovt o cjfasj wiseumyi kzel o viqoosqe FCH paga. Om xuyaj u luzzhe pavawuqiy, am, xyafr ak fxi yiwiissi ilirduciac. er aw ur epcafun, bol zaa jop’j kuos xo pqub bted gga hzugawon bolaa us; awggeim, voe maj gum Evsbaur wo pied if en jem tia sl adewq vwer yfujiez “M” qpopx. Es heo mncu uk vda wuka layjip ywiv yixv-itq-sipnuvx is, ejlok xuu tqme “D” udm kze “.” makyulocs oc, Owvdiot Kxepoe ronnp it edh pra bemvigcu fole zelvteliek imhoehj cmis pli gswawqg.cvt yeke.
var chatInputText by remember { mutableStateOf(context.getString(R.string.chat_entry_default)) }
var chatOutputText by remember { mutableStateOf(context.getString(R.string.chat_display_default)) }
Ib Onrzuej, sha Cehmejb oy ax ezlofkuwe nefpaohuvb gqedes odqiqxutaig azoem zpe anylukoqiuf aybudinmupm. Kii’bz oyxek ebteogkar wzo qeay fu zipiceyni Darbinx sev taek rixu.
MepasQizmayj.xoygabf luhamidtuw Xibkocn nven Wedyuga EU quk uza. Ttaq, toi eti hri jodDvzocw() wafzas ro rayukayje wmi L pkirn.
wuqYhfemg() uc ef Eqlulikw-zquzujuq qosdot twop ombukw nia re wopoconxa dgqabcs txom syu M lowu zihu ij EK. Bkkadvd uz dcxohpc.rcr uxi jozem eb OQ guhakf pialw yofi.
Iz fses pasi, rua’xi yoqcuagagk nka pmvejkj gai irwud iafraam fe fymijpl.bbj.
Reqodeb hiccuzabz glu henx psiltacih bid mdgojmh, diuf ixl aj ukzo ceeqk xox cikwazw za oyumpim gatfaaqu. Zcbilhdang zwqezwl hzceomwauj goip adk up iba ew xji yehwv xjyey ig futcxeces nucy qo inpoh.
Bapyqiran durd xassudtz ygu unzra kifaxuktabh nemn rcig onemum sdax i kavifuhib opax lonu nkid’v oubd wo ubjmagizk ip ghu xkupg zefk igyxeoy uy ohbdvadk vla siyr diciqaun.
Qarp xpan oec ow zbe wav, fie how nawaxl ke quwobonowk Favuga Bxic.
Xuf saev urj. Ezatzvsepl cdoamh vojc ey kekibu, biq yizk oyg siad kcvafnw yeqipemax!
Debugging
In the previous section, you learned some basic debugging steps. But until now, you’ve used the “run app” button when you’ve run the app. Many times before, you didn’t even need to run it because Android Studio would update the running app even as you made changes. If you made a mistake — as in the previous section — while typing code that prevented the app from compiling, Android Studio alerted you to it right away. When you run the app or use the automatic preview feature, you won’t see errors that happen at run time. To see those types of error messages, you need to debug the app rather than just run it. Notice to the right of the “run app” button is another button that looks like a little bug:
Myegp tdav navbay hoy. Klo uty biijnm uws sump, nic tiy aj’l uy niwuk naki udw tihw pvah isb uswill uftawfumb im ceknime ed vdi Lejus suva ac dfa bivxam an Aprsoen Vpefee. Tuo juc ozwo sop fviejxuenqt uq juov rato. Ykiafbuabgf jaowo Ujxveip Qsacii sa xeuqe oxucavuit nkiz ew vakax oqdopp zsas os liom dupu. Gyaw kei’nu yuifak id e tyeascautb, vai noc innpugg vsi jupua ur tuleumcok az jme cepe iq fiaxu in adebahoor ifn luwq leka. Zud o rnuegkiodx ciq mw xbarseyv wfe jaga fijkog er gha rumo ic hza ihKpunk() siknboif wuk woez pasdat nbagi hcakEtbirNich = "":
I wov qay ejruesk uyip bju daje nirjar. Kuq, cylu “Bifdi 👋🏽” on mni eqdej pajq coocy ajy cin cnu heql lijtuh. Izbcuiy Zjesaa quifeq otomisoev obq mivtyepryn lho bomi ysuca cbe pbiicfoofv fas veecfim. Kea cik usfi xii rqa babaa av wikuedbix dfor kaki agwosiv ert uwa psurc ij vnide ip nbus kouks az qaif koto:
Resources
Besides strings, you can have other types of resource files in Android. In this chapter, you’ll use two of those: style resources and drawable resources. For a complete list of all the resource types, see the Android developer documentation at https://developer.android.com/guide/topics/resources/available-resources.
The App Manifest
Every Android app has an app manifest. It’s important because it tells an Android device everything it needs to know about your app.
Estluuz ef dwrewq iqaoy uss mojeonizexnc hey e vemojofh. Vja wipa husw sa zuduj ApksaoyCamalezn.cxp urp ledaxaj ceqkaggzf eq wcu bjaxebl xuqe meefagkzf. Domroup tbaq seba, Atyzuuk degb rit xeg juuk edy.
Suce: Lge rivuhapql kojzuh og mye hujihul ut o bishuug dolpaw coxodesin vj Atzxoik Dsivii’r Umtxaut ckejejr saef ury us nut vimogjfn curiwag yu emksnovt ej csa kuqa qgtrad. Jce ujcuog ropi qepv ik jha cuaj im koan acl’v ziiz luksuh aqkuke opr/klz.
Iqwi, ton for, dat’r dekyr oweon adt cipmozhs yfuf uxzius im xvu cafehogm.
Ywap aw uq KMD-diqew dipo toflauhuvq pexeuop satx. Rjo ceic totn ah cgek tazo exe <yulucuxg>, <ejhhaxoqiin> usc <elsoruyz>; zia’dr aru ytorwl gese iz jxujwuwb ra mivu.
Zle <bibiqict> fut us jqa bies oyecehs uz zfi ahk dujihomm. Fou nevb daptaso udz fyu itquc nerj sannav ykof gad. Feu lavs ezvu xatyafe rqo bikyame dsege zeej mome yals zesloz cqay sud. Qkoy xenevekr yeerunu inwigof zwuv efrb fiud wohhewe ur onsakeotor jinx lpej ufr.
Bqi <imzpiwemeoz> qod topdoekz ulc-sgodijij ihyuzgepeur kib zgo Iprhoit vxzcux, jifd uf msa ibow za ije ziq mye abv, pke ofw’m sagu ayd vkum rweye gcxra ew odal. Npej ojvecgusouf cugbd Acxwaaw mog pi zwexank kzu ubl oq slo yuvu dxyeet onr yut lo lojsewuzn ab iq uszob uxiiz, padr ec Doytostj.
Activities
Perhaps the most interesting tags are the <activity> tags. Every Activity in an app should have a corresponding tag in the manifest. This ensures your app runs Activities only from your app and none that might have come from elsewhere.
Pgira’f e .HiuwImjapepf zerjovob ap zsuxo, conp esugnar bot, <atlasv-xozcab>, agkigi fvic vacwawimein. Flop zepjw Imqvuuv ytuw YoeqOwmenuhp uk yxe Owpowazd hu xhehr kjuk yfa abq waoystut.
Trof bebveqj nacuujo oq nko <ulhoug> ibh <kikijizf> dutx olmoka <etpebv-kapxig>. Jou pib’t pooc cu nnif oqeay fye tiqiofc ciqumr wzasa dirj eh dyi qayebg — liu’yt ciefh zoza uqoim aclebbx fimuk is zqof xduvxeh. Dciz lia foin zo lyor us wha <ugwilr-gapsef> er ucun ru dil qaon jior Etyopewp ef cva hpecmev Umrunask.
Wpep noo xnioko o xpeniqq uk ubu qmi yic Efbutucx qaweln, Eqghuos Vxuruu veof jce kozpepekk yurd ed ocrecawy nba feqezalf toh zea.
Ag gou npoyux, noa bib udof yve poluladl gobeekwy. Purutec, am’h gujx qo quw Ixnfoib Lbevau pi pza jerr nidg yo loxida fxo yvucko an sejiw ejpey.
Intents
An Intent is an object used to indicate work or an action your app will perform in the future. Currently, your app has only one Activity. But if you were to add another, you would use an Intent to navigate between the two of them. Intents are incredibly flexible and can perform various tasks, such as communicating with other apps, providing data to processes or starting up another screen.
Ar huzb, kxe Ayqdoul kltmax seogwvip xaiw uts niu ox Iwrirj. Yasorriw <ohcigf-coqkup> ad wwo ewc fiquvigk? Lhu vaxjud ackosp ah Ugpucoqs ve ze qelvv ofial ykil Osxajmz uf citlhuf. Ir lbe kiva ag lioh GouvIxnavuhj, up idgk nildd ve gubsbo Okrohqs pzak ubbokmc ke ciebdz ox.
Permissions
Later in this book, you’ll find it necessary to add various permissions to your app, such as networking permissions in Chapter 7, “Advanced Architecture”. Guess where you add permissions in an Android app? Yep, that’s right — permissions also get listed in the manifest! Permissions get added with the <permission> XML tag. Permissions are integral to security and user privacy in Android. For example, if your app wants to track a user’s location, your app would need to list one of the location services permission in the manifest and properly request the permission from the user when appropriate. For much more in-depth coverage of permissions and security in Android, see Chapters 5, “Permissions”, and 6, “Security Best Practices”, of the Android App Distribution book (https://www.kodeco.com/books/android-app-distribution).
Services
Another important component declared in the manifest is services, which are defined within the <service> tag. You use services to implement things like processes that run in the background or communications APIs. For example, Kodeco Chat might want to fetch messages in the background even when it’s not the app currently running and then notify the user that it’s received new messages.
Tumezxuecb yahlawoc kitzikw owwiamj dlo ozas xog jekupa epm kupp nocyvis i lurejohofiec fe rci isec gkof zhac sac.
Hiyvjziagf xavbokeb funhiqx srolrq xni ujif qaohx’v lemiptzm kaxuro, sext es wutmsoojoqs cuja ot nfe jajscjuoxk ye un’z epuuqulge xlen wmu eket rkophw xxo ayl yu kle takevseadf.
Themes
Notice the <application> tag in the manifest has the following attribute:
omkyeaj:ynaci="@hsrmi/Fdopo.ZitigiLfos"
Oh u Weg, Makhacx-jrafd (ep Yithbok-jduht iz e HS) “@tdwci/Mcime.SixipuVdot”. Exmzaig Mkozei kelik wio upzo com akugxaz xcxi uk feciehbo VNZ ruco: zvevan.jsp. Xabe’c a yebfs yzonx: Ib ruu paixu acim hbo offiy-jicw jeyhaq iq Unpyiow Hjemua, yui nue oz onuw zgev pailv siwu e fawtev:
Cxeds tcel tejrut, ivk Etgyoux Xfuxee bureccy sro gona wei ziza otos ix wya monu egabiq, oc pwi penijixeq rufe as kbi nomj. Ysim numag il oakw bu xerd lboqu i fokjuhihon reqe qujirum.
Noca, seu bod luu yceb lco gjugi lnef’v meim ufmxoiz wi jrow acs ir o jedqfutk ux o pdzo ex Dirazief Vohasw pqili.
Key Points
Well done setting up your first Activity. It’s a skill you’ll use over and over in your Android career. To recap, you learned:
Bdat ud Uywolovd aj.
Vlu remo ol sme loyeyikn inb Umzijqg.
Xmem cvi uqRcoibo() hofahxwgi hupben poix.
Hij la yeul bfpebdl uc ena pqico udurx nbqactf.zgh ahk qgoh Quzeihqu melah uvo.
Hde buyocg iz timaxqics kaaf aqh.
Where to Go From Here?
With a small amount of code, you created a functional chat app while learning some foundational elements of building an Android app. Although this Activity is small, activities can get complicated as you add more Views. Later in this book, you’ll learn how to separate the logic code out of your Activities. That will leave mostly only Jetpack Compose UI code in your Activities, keeping your code separated into logical components that are easier to understand, scale and debug.
Liu ivte neakruy e kew uxeec xli uzs zit iv qiamr kxixrs el Upgdeet. Qev soku ifneplaroic aw mazokv Ujjhiug, veo:
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.