Creating PhotoGallery

Create a new Android application project. As you have done before, choose Phone and Tablet as the target form factor and select the option to add no activity. Name the project PhotoGallery. Make sure the Package name is com.bignerdranch.android.photogallery, the Language is Kotlin, and the Minimum API level is API 21: Android 5.0 (Lollipop). Check the box to Use AndroidX artifacts.

Once the project has initialized, click on app in the project tool window and add an empty activity (FileNewActivityEmpty Activity) named PhotoGalleryActivity. Check the box to make PhotoGalleryActivity a Launcher Activity.

PhotoGalleryActivity will host a PhotoGalleryFragment, which you will create shortly. First, open res/layout/activity_photo_gallery.xml and replace the auto-generated contents with a single FrameLayout. This frame layout will serve as the container for the hosted fragment. Give the frame layout an ID of fragmentContainer. When you are done, the contents of activity_photo_gallery.xml should match Listing 24.1.

Listing 24.1  Adding a fragment container (res/layout/activity_photo_gallery.xml)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/fragmentContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".PhotoGalleryActivity"/>

In PhotoGalleryActivity.kt, update onCreate(…) to check whether a fragment is already hosted in the fragment container. If not, create an instance of PhotoGalleryFragment and add it to the container. (Bear with the error that this code will cause for the moment. It will go away after you create the PhotoGalleryFragment class.)

Listing 24.2  Setting up the activity (PhotoGalleryActivity.kt)

class PhotoGalleryActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_photo_gallery)

        val isFragmentContainerEmpty = savedInstanceState == null
        if (isFragmentContainerEmpty) {
            supportFragmentManager
                .beginTransaction()
                .add(R.id.fragmentContainer, PhotoGalleryFragment.newInstance())
                .commit()
        }
    }
}

In CriminalIntent, you checked whether a fragment was already hosted in the container by calling findFragmentById(…) on the fragment container ID. This check was necessary because the fragment manager automatically creates and adds hosted fragments back to the activity after a configuration change or after a system-initiated process death. You only want to add the fragment to the container if there is not already a fragment there.

PhotoGalleryActivity takes a different approach to determining whether a fragment is already hosted: It checks to see whether the savedInstanceState bundle passed to onCreate(…) is null. Recall that, if the bundle is null, this is a fresh launch of the activity and you can safely assume no fragments were automatically restored and rehosted. If the bundle is not null, it means the activity is being reconstructed after a system-initiated destruction (such as rotation or process death) and any fragments that were hosted before the destruction were re-created and added back to their respective containers.

Either approach works to find out whether a fragment is already hosted in the activity’s single container, and you will likely see the check done both ways out in the wild. Which to use is mostly a matter of style preference.

Checking savedInstanceState allows you to use information you already have to determine whether a fragment is hosted. However, it assumes the reader of your code understands how savedInstanceState and fragment restoration across configuration changes works.

Checking for the fragment’s existence using supportFragmentManager.findFragmentById(R.id.fragment_container) is more explicit and easier to parse for people new to Android. However, it involves unnecessarily interacting with the fragment manager in the scenario where a fragment already exists in the container.

Now set up the fragment’s view. PhotoGallery will display its results in a RecyclerView, using the built-in GridLayoutManager to arrange the items in a grid. First, add the RecyclerView library as a dependency, as you did in Chapter 9. Open the app module’s build.gradle file and add the recycler view Gradle dependency (Listing 24.3). After you make these changes, sync the Gradle file using Android Studio’s prompt.

Listing 24.3  Adding a RecyclerView dependency (app/build.gradle)

dependencies {
    ...
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
    implementation 'androidx.recyclerview:recyclerview:1.0.0'
    ...
}

Next, right-click the res/layout folder in the project tool window and select NewLayout resource file. Name this file fragment_photo_gallery.xml and enter androidx.recyclerview.widget.RecyclerView as the root element. When the file is created, set the recycler view’s android:id to @+id/photo_recycler_view. Fold the closing tag into the opening tag, since you will not be placing anything between them. When you are done, the contents of res/layout/fragment_photo_gallery.xml should match Listing 24.4.

Listing 24.4  Adding a recycler view to the fragment layout (res/layout/fragment_photo_gallery.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/photo_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

Finally, create the PhotoGalleryFragment class. Inflate the layout you just created and initialize a member variable referencing the RecyclerView. Set the recycler view’s layoutManager to a new instance of GridLayoutManager. For now, hardcode the number of columns to 3. (In the section called Challenge: Dynamically Adjusting the Number of Columns at the end of this chapter, you will be tasked with adapting the number of columns to suit the screen width.) When you are done, your fragment code should match Listing 24.5.

Listing 24.5  Setting up the fragment (PhotoGalleryFragment.kt)

class PhotoGalleryFragment : Fragment() {

    private lateinit var photoRecyclerView: RecyclerView

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val view = inflater.inflate(R.layout.fragment_photo_gallery, container, false)

        photoRecyclerView = view.findViewById(R.id.photo_recycler_view)
        photoRecyclerView.layoutManager = GridLayoutManager(context, 3)

        return view
    }

    companion object {
        fun newInstance() = PhotoGalleryFragment()
    }
}

Run PhotoGallery to make sure everything is wired up correctly before moving on. If all is well, you will have a very nice blank screen.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.234.177.119