July 2, 2023

Android - Jetpack Compose tutorial

The old way of doing Android UI layout was to use XML files. The new way seems to be using "Jetpack Compose". My book calls the former the "imperative approach" and the latter the "declarative approach". It is nice to have fancy words for all this. Maybe these are better than "old" and "new". As usual I launch "studio" and create a new project "Compose Tutorial" based on an Empty Activity. I rip out most of what is there so that I see only what they want me to start with.

The import list up top shows an abbreviated ... but if I double click it expands to show me reality. They say that Jetpack Compose uses a Kotlin compiler plugin -- interesting that a compiler would have plugins and be extensible. I try just this code, building it and running it on a Pixel 6 API 33 virtual device.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text ( "Hello Tombstone")
        }
    }
}
This works just fine! It does take a while for the virtual device to boot up.
Next I add a composable function. They tell me that composable functions can only be called from other composable functions (or a setContent block apparently).
@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}
This also works. Now they have me add this. They say @Preview functions may not have arguments.
@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
I am supposed to now get a preview window and a "split" view (design/code), but I don't get that at all. Maybe having a virtual device bypasses all of that.

I discover something interesting as I experiment around. I can click on a tiny "window" icon at the top right of the device manager and it becomes its own independent window I can move around. I can "redock" it by clicking on that same window icon that moves with the window.

I use View -- Tool Windows and look for Preview. It ain't there. So I'll just have to continue the tutorial and ignore all this stuff about Preview.

I discover later if I click the "_" (underscore) at the upper right of device manager, it goes away and reveals the Code/Split/Design trio. I find that with the size display I am using that Split just shoves "Design" (which apparently is the long lost preview window) right off on the right side. So clicking either Code or Design to show one or the other works well. If I ran Android Studio full screen, Split might work just fine.

I'll also note that whenever I rebuilt or restart my project, the Pixel 6 virtual device pops back into its original spot.

Column

This lets Text be one above the other. I had to add the import as shown to all of the othe stuff already imported.
import androidx.compose.foundation.layout.Column

data class Message ( val author: String, val body: String )

val n = Message ( "Levi", "Tombstone")
MessageCard ( n )

@Composable
fun MessageCard( msg: Message) {
    Column {
        Text(text = "Hello " + msg.author)
        Text(text = "Goodbye " +  msg.body )
    }
}

Row (and an image)

There is also "Box". They want me to use "Resource Manager" to import an image. I download their demo image as girl.png, then find Resource Manager under Tools. From Resource Manager, I click the "+" at the upper left, select "import Drawables" from the bottom of the drop down menu, and navigate to girl.png in my filesystem
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.ui.res.painterResource

@Composable
fun MessageCard(msg: Message) {
    Row {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
        )

       Column {
            Text(text = msg.author)
            Text(text = msg.body)
        }

    }

}
This leaves me wondering (and android studio also) as to where profile_picture is defined. At this point the tutorial has pretty much come unglued. Don't they all? Why don't the people writing them actually try them?

At some point I could research this "painter" business along with the R.drawable stuff and try to sort out how to make the connection. My bet is that the code above is just fine, but something else needs to be done to make profile_picture exist and point to girl.png

With some digging around I find girl.png in app/res/drawable. On disk, she is in app/build/intermediates/packaged_res/debug/drawable-tom and app/src/main/res/drawable-tom (all very mysterious).

More digging leads to a different method besides Resource manager. Go to app->res and right click. From the menu that appears select New, and from the next menu "Image Asset"

More digging leads to this enlightening statement:

When your Android application is compiled, a R class gets generated, which contains resource IDs for all the resources available in your res/ directory. You can use R class to access that resource using sub-directory and resource name or directly resource ID.
Something for another day ...........
Have any comments? Questions? Drop me a line!

Adventures in Computing / tom@mmto.org