---
title: "E-Learning"
canonical_url: "https://www.nutrient.io/guides/android/samples/e-learning-kotlin/"
md_url: "https://www.nutrient.io/guides/android/samples/e-learning-kotlin.md"
last_updated: "2026-05-15T19:10:04.916Z"
description: "Switch between documents while preserving view state, annotations, and bookmarks."
---

# E-Learning

Switch between documents while preserving view state, annotations, and bookmarks.

[Get Started](https://www.nutrient.io/sdk/android/getting-started.md)

[All Samples](https://www.nutrient.io/guides/android/samples.md)

[Download](https://www.nutrient.io/guides/android/downloads.md)

[Launch Demo](https://www.nutrient.io/demo/)

---

```kotlin

/*
 *   Copyright © 2020-2026 PSPDFKit GmbH. All rights reserved.
 *
 *   The PSPDFKit Sample applications are licensed with a modified BSD license.
 *   Please see License for details. This notice may not be removed from this file.
 */

package com.pspdfkit.catalog.examples.kotlin

import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.annotation.UiThread
import androidx.lifecycle.lifecycleScope
import com.pspdfkit.annotations.AnnotationType
import com.pspdfkit.bookmarks.Bookmark
import com.pspdfkit.catalog.R
import com.pspdfkit.catalog.SdkExample
import com.pspdfkit.catalog.tasks.ExtractAssetTask.extract
import com.pspdfkit.configuration.activity.PdfActivityConfiguration
import com.pspdfkit.configuration.page.PageLayoutMode
import com.pspdfkit.configuration.sharing.ShareFeatures
import com.pspdfkit.document.PdfDocument
import com.pspdfkit.preferences.PSPDFKitPreferences
import com.pspdfkit.ui.DocumentDescriptor
import com.pspdfkit.ui.PdfActivity
import com.pspdfkit.ui.PdfActivityIntentBuilder
import com.pspdfkit.ui.special_mode.controller.AnnotationTool
import com.pspdfkit.utils.getSupportParcelableExtra
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.EnumSet

/**
 * This example shows how to swap between documents and sync view state, annotations, and bookmarks.
 */
class ELearningExample(context: Context) : SdkExample(context, R.string.eLearningExampleTitle, R.string.eLearningExampleDescription) {
    override fun launchExample(context: Context, configuration: PdfActivityConfiguration.Builder) {
        // We'll disable redaction tool in annotation creation toolbar to prevent creation of redaction annotations.
        val annotationTools = mutableListOf(*AnnotationTool.values())
        annotationTools.remove(AnnotationTool.REDACTION)

        configuration
            // Turn off saving, so we have the clean original document every time the example is launched..autosaveEnabled(false)
            // Use single page mode..layoutMode(PageLayoutMode.SINGLE)
            // Disable all the menu items but annotations editing and bookmark list..outlineEnabled(false).documentInfoViewEnabled(false).annotationListEnabled(false).searchEnabled(false).settingsMenuEnabled(false).setEnabledShareFeatures(EnumSet.noneOf(ShareFeatures::class.java)).printingEnabled(false).thumbnailGridEnabled(false).setRedactionUiEnabled(false).enabledAnnotationTools(annotationTools)

        // The annotation creator written into newly created annotations. If not set, or set to null
        // a dialog will normally be shown when creating an annotation, asking you to enter a name.
        // We are going to skip this part and set it as "John Doe" only if it was not yet set.
        if (!PSPDFKitPreferences.get(context).isAnnotationCreatorSet) {
            PSPDFKitPreferences.get(context).setAnnotationCreator("John Doe")
        }
        // Extracts the documents from the assets and loads the teacher version first.
        extract("Teacher.pdf", title, context) { teacherDocumentFile ->
            extract("Student.pdf", title, context) { studentDocumentFile ->
                val teacherDocumentUri = Uri.fromFile(teacherDocumentFile)
                val studentDocumentUri = Uri.fromFile(studentDocumentFile)
                val intent =
                    PdfActivityIntentBuilder.fromUri(context, teacherDocumentUri).configuration(configuration.build()).activityClass(ELearningActivity::class).build()
                intent.putExtra(ELearningActivity.STUDENT_URI_KEY, studentDocumentUri)
                intent.putExtra(ELearningActivity.TEACHER_URI_KEY, teacherDocumentUri)
                context.startActivity(intent)
            }
        }
    }
}

class ELearningActivity : PdfActivity() {
    /** List of annotations in instant JSON format that will be copied over the new document.  */
    private val serializedAnnotationsToTransfer: MutableList<String> = mutableListOf()

    /** List of bookmarks that will be copied over the new document.  */
    private val bookmarksToTransfer: MutableList<Bookmark> = mutableListOf()

    /** Student document URI. */
    private lateinit var studentUri: Uri

    /** Teacher document URI. */
    private lateinit var teacherUri: Uri

    /** Job in charge of switching the document. */
    private var switchDocumentJob: Job? = null

    /** Job in charge of loading the annotation to the new document. */
    private var transferDataJob: Job? = null

    /** Fragment state containing current page, zoom, and scroll. */
    private var fragmentState: Bundle? = null

    /** Flag to keep track of visibility of bookmark list view. */
    private var isBookmarkListDisplayed: Boolean = false

    /**
     * Create a button to switch between teacher and student documents.
     */
    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        super.onCreateOptionsMenu(menu)
        if (document == null || serializedAnnotationsToTransfer.isNotEmpty()) {
            return false
        }
        // Add a new switch button.
        val switchItem = menu.add(0, SWITCH_ITEM_ID, 0, "Switch")
        switchItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM or MenuItem.SHOW_AS_ACTION_WITH_TEXT)

        return true
    }

    /**
     * Set the corresponding action for every button.
     */
    override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
        SWITCH_ITEM_ID -> {
            switchDocument()
            true
        }

        else -> {
            super.onOptionsItemSelected(item)
        }
    }

    override fun onPause() {
        switchDocumentJob?.cancel()
        transferDataJob?.cancel()
        super.onPause()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        intent.getSupportParcelableExtra(STUDENT_URI_KEY, Uri::class.java)?.let {
            studentUri = it
        }
        intent.getSupportParcelableExtra(TEACHER_URI_KEY, Uri::class.java)?.let {
            teacherUri = it
        }
    }

    @UiThread
    override fun onDocumentLoaded(document: PdfDocument) {
        // Take any serialized annotations that were stored upon switching, and add them to the loaded document.
        transferDataJob =
            lifecycleScope.launch {
                withContext(Dispatchers.IO) {
                    // Create annotations from instant JSON and add them to the document.
                    for (json in serializedAnnotationsToTransfer) {
                        document.annotationProvider.createAnnotationFromInstantJson(json)
                    }
                    // Once all annotations are transferred, we can clear the list.
                    serializedAnnotationsToTransfer.clear()

                    // Take any bookmarks that were stored upon switching, and add them to the loaded document.
                    bookmarksToTransfer.forEach { bookmark ->
                        document.bookmarkProvider.addBookmarkAsync(bookmark).blockingAwait()
                    }
                    // Once all bookmarks are transferred, we can clear the list.
                    bookmarksToTransfer.clear()
                }

                // Restore page index, scroll and zoom.
                fragmentState?.let {
                    requirePdfFragment().state = it
                    fragmentState = null
                }

                // Make sure the outline view shows the changes from transferring bookmarks and annotations.
                pspdfKitViews.outlineView?.setDocument(document, configuration.configuration)

                // Restore bookmark list view visibility.
                if (isBookmarkListDisplayed) {
                    pspdfKitViews.outlineView?.show()
                }

                invalidateOptionsMenu()
            }
    }

    /**
     * Switch the document when the button is tapped. This works in multiple steps:
     *  - Fetching all annotations asynchronously, and convert them to Instant JSON format.
     *  - Fetch all bookmarks.
     *  - Save the view state.
     */
    private fun switchDocument() {
        val document = document?: return

        // While the document switching is in progress, we disable all document interaction to
        // prevent changes to be made.
        requirePdfFragment().isDocumentInteractionEnabled = false

        // Run the collection of annotations and bookmarks asynchronously.
        switchDocumentJob =
            lifecycleScope.launch {
                // Clear previous data
                serializedAnnotationsToTransfer.clear()
                bookmarksToTransfer.clear()

                withContext(Dispatchers.IO) {
                    // Fetch all annotations, serialize them, and collect them in a list. We keep them around in
                    // memory, and will add them to the other document once it is loaded.
                    val annotations =
                        document.annotationProvider.getAllAnnotationsOfType(
                            AnnotationType.entries.toSet(),
                        )

                    annotations.forEach { annotation ->
                        val json = annotation.toInstantJson()
                        // For some unsupported annotation types (like popup annotations) we don't offer serialization.
                        // In these cases, `toInstantJson()` returns "null". We filter those from the serialized items.
                        if (invalidInstantJson(json)) {
                            serializedAnnotationsToTransfer.add(json)
                        }
                    }

                    // Fetch the bookmarks for synchronization and collect them in a list.
                    val bookmarks = document.bookmarkProvider.bookmarks
                    bookmarksToTransfer.addAll(bookmarks)
                }

                // Save current page index, scroll and zoom.
                fragmentState = requirePdfFragment().state

                // Save bookmark list view visibility.
                isBookmarkListDisplayed = pspdfKitViews.outlineView?.isDisplayed?: false

                // Swap out the current document to either the teacher or student version.
                if (document.documentSource.fileUri == teacherUri) {
                    documentCoordinator.setDocument(DocumentDescriptor.fromUri(studentUri))
                } else {
                    documentCoordinator.setDocument(DocumentDescriptor.fromUri(teacherUri))
                }
                invalidateOptionsMenu()
            }
    }

    companion object {
        private const val SWITCH_ITEM_ID = 1234
        const val STUDENT_URI_KEY = "TeacherStudentActivity.STUDENT_URI_KEY"
        const val TEACHER_URI_KEY = "TeacherStudentActivity.TEACHER_URI_KEY"
    }
}

private fun invalidInstantJson(it: String) = it!= "null"

```

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.

---

## Related pages

- [Application Policy](/guides/android/samples/application-policy-kotlin.md)
- [Custom Form Highlight Color](/guides/android/samples/custom-form-highlight-color-java.md)
- [Custom Page Templates](/guides/android/samples/custom-page-templates-java.md)
- [Digital Signature (Basic)](/guides/android/samples/digital-signature-basic-kotlin.md)
- [Disabled Annotation Property](/guides/android/samples/disabled-annotation-property-java.md)
- [Image Document](/guides/android/samples/image-document-kotlin.md)
- [Compose Image Document](/guides/android/samples/compose-image-document-kotlin.md)
- [Inline Multimedia](/guides/android/samples/inline-multimedia-kotlin.md)
- [JavaScript Form Filling](/guides/android/samples/javascript-form-filling-kotlin.md)
- [Overlay Visibility](/guides/android/samples/overlay-visibility-kotlin.md)
- [PdfFragment](/guides/android/samples/pdffragment-kotlin.md)
- [Reader View](/guides/android/samples/reader-view-kotlin.md)
- [Playground](/guides/android/samples/playground-kotlin.md)
- [JavaScript Calculator](/guides/android/samples/javascript-calculator-kotlin.md)
- [Text Field Suggestions](/guides/android/samples/text-field-suggestions-kotlin.md)
- [Thumbnail Bar Modes](/guides/android/samples/thumbnail-bar-modes-kotlin.md)
- [Signature Storage Database](/guides/android/samples/signature-storage-database-kotlin.md)
- [Selection Customization](/guides/android/samples/selection-customization-java.md)
- [Password Protected PDF](/guides/android/samples/password-protected-pdf-kotlin.md)
- [Scientific Paper](/guides/android/samples/scientific-paper-kotlin.md)
- [Try Instant](/guides/android/samples/try-instant-kotlin.md)
- [Merge Documents](/guides/android/samples/merge-documents-kotlin.md)
- [Annotation Rendering](/guides/android/samples/annotation-rendering-kotlin.md)
- [Custom Data Provider](/guides/android/samples/custom-data-provider-kotlin.md)
- [Annotations with Transparency](/guides/android/samples/annotations-with-transparency-kotlin.md)
- [Annotation Flags](/guides/android/samples/annotation-flags-kotlin.md)
- [AI Assistant (Multiple Documents, ViewPager)](/guides/android/samples/ai-assistant-multiple-documents-viewpager-kotlin.md)
- [Custom Sharing Menu](/guides/android/samples/custom-sharing-menu-java.md)
- [Add LTV to Existing Signature](/guides/android/samples/add-ltv-to-existing-signature-kotlin.md)
- [Custom Toolbar Grouping](/guides/android/samples/custom-toolbar-grouping-java.md)
- [Custom Layout](/guides/android/samples/custom-layout-kotlin.md)
- [Custom ActionBar Actions](/guides/android/samples/custom-actionbar-actions-kotlin.md)
- [Custom Activity Toolbars](/guides/android/samples/custom-activity-toolbars-java.md)
- [Custom Note Hinter](/guides/android/samples/custom-note-hinter-kotlin.md)
- [Custom Main Toolbar](/guides/android/samples/custom-main-toolbar-kotlin.md)
- [Annotation Configuration](/guides/android/samples/annotation-configuration-kotlin.md)
- [Annotation Selection Styling](/guides/android/samples/annotation-selection-styling-kotlin.md)
- [Custom Search UI (Compose)](/guides/android/samples/custom-search-ui-compose-kotlin.md)
- [Document Switcher](/guides/android/samples/document-switcher-java.md)
- [File Annotation Creation](/guides/android/samples/file-annotation-creation-kotlin.md)
- [Dynamic Pages on Scroll](/guides/android/samples/dynamic-pages-on-scroll-kotlin.md)
- [Custom Activity Form Editing](/guides/android/samples/custom-activity-form-editing-java.md)
- [Custom Stamp Annotations](/guides/android/samples/custom-stamp-annotations-java.md)
- [Custom Outline Provider](/guides/android/samples/custom-outline-provider-kotlin.md)
- [Compose Navigation](/guides/android/samples/compose-navigation-kotlin.md)
- [Fragment Runtime Configuration](/guides/android/samples/fragment-runtime-configuration-kotlin.md)
- [Annotation Overlay](/guides/android/samples/annotation-overlay-java.md)
- [Instant Document JSON](/guides/android/samples/instant-document-json-kotlin.md)
- [DocumentView Composable](/guides/android/samples/documentview-composable-kotlin.md)
- [Form Creation](/guides/android/samples/form-creation-kotlin.md)
- [Document Download](/guides/android/samples/document-download-kotlin.md)
- [JavaScript Actions](/guides/android/samples/javascript-actions-kotlin.md)
- [Instant JSON Attachment](/guides/android/samples/instant-json-attachment-kotlin.md)
- [Digital Signature (Manual)](/guides/android/samples/digital-signature-manual-kotlin.md)
- [Digital Signature (Third-Party)](/guides/android/samples/digital-signature-third-party-kotlin.md)
- [Inline Search](/guides/android/samples/inline-search-java.md)
- [Form Filling](/guides/android/samples/form-filling-kotlin.md)
- [Form Click Intercept (Compose)](/guides/android/samples/form-click-intercept-compose-kotlin.md)
- [Document Sharing](/guides/android/samples/document-sharing-java.md)
- [Custom Download Dialog](/guides/android/samples/custom-download-dialog-java.md)
- [Download Progress](/guides/android/samples/download-progress-kotlin.md)
- [Popup Toolbar Customization](/guides/android/samples/popup-toolbar-customization-kotlin.md)
- [Custom Sharing Dialog](/guides/android/samples/custom-sharing-dialog-java.md)
- [PDF from Image](/guides/android/samples/pdf-from-image-kotlin.md)
- [Digital Signature (Two-Step)](/guides/android/samples/digital-signature-two-step-kotlin.md)
- [Remote URL](/guides/android/samples/remote-url-kotlin.md)
- [PdfUiFragment](/guides/android/samples/pdfuifragment-kotlin.md)
- [Runtime Configuration](/guides/android/samples/runtime-configuration-kotlin.md)
- [Sound Extraction](/guides/android/samples/sound-extraction-kotlin.md)
- [Document from Canvas](/guides/android/samples/document-from-canvas-kotlin.md)
- [Tabbed Documents](/guides/android/samples/tabbed-documents-kotlin.md)
- [Watermarks](/guides/android/samples/watermarks-kotlin.md)
- [Programmatic Zoom](/guides/android/samples/programmatic-zoom-kotlin.md)
- [Signature Parcelize](/guides/android/samples/signature-parcelize-kotlin.md)
- [OCR](/guides/android/samples/ocr-kotlin.md)
- [Vertical Scrollbar](/guides/android/samples/vertical-scrollbar-java.md)
- [Split View](/guides/android/samples/split-view-java.md)
- [XFDF Import/Export](/guides/android/samples/xfdf-import-export-kotlin.md)
- [UI View Modes](/guides/android/samples/ui-view-modes-kotlin.md)
- [LTV Signature](/guides/android/samples/ltv-signature-kotlin.md)
- [Bookmark Highlighting](/guides/android/samples/bookmark-highlighting-kotlin.md)
- [Custom Annotation Inspector](/guides/android/samples/custom-annotation-inspector-java.md)
- [Annotation Sidebar](/guides/android/samples/annotation-sidebar-kotlin.md)
- [AI Assistant (Single Document)](/guides/android/samples/ai-assistant-single-document-kotlin.md)
- [AI Assistant (Multiple Documents, Compose)](/guides/android/samples/ai-assistant-multiple-documents-compose-kotlin.md)
- [Document Comparison](/guides/android/samples/document-comparison-kotlin.md)
- [Document Processing](/guides/android/samples/document-processing-kotlin.md)
- [Custom Annotation Creation Toolbar](/guides/android/samples/custom-annotation-creation-toolbar-java.md)
- [Custom Electronic Signature](/guides/android/samples/custom-electronic-signature-java.md)
- [Electronic + Digital Signing](/guides/android/samples/electronic-digital-signing-kotlin.md)
- [Generate PDF Report](/guides/android/samples/generate-pdf-report-kotlin.md)
- [Multimedia Annotations](/guides/android/samples/multimedia-annotations-kotlin.md)
- [Forms with JavaScript](/guides/android/samples/forms-with-javascript-kotlin.md)
- [External Document](/guides/android/samples/external-document-kotlin.md)
- [Overlay Views](/guides/android/samples/overlay-views-kotlin.md)
- [Kiosk Grid](/guides/android/samples/kiosk-grid-kotlin.md)
- [Search Indexing](/guides/android/samples/search-indexing-kotlin.md)
- [Annotation Creation](/guides/android/samples/annotation-creation-kotlin.md)
- [Filterable Thumbnail Grid](/guides/android/samples/filterable-thumbnail-grid-kotlin.md)
- [Tabbed Documents (Persistent)](/guides/android/samples/tabbed-documents-persistent-kotlin.md)
- [Measurement Tools](/guides/android/samples/measurement-tools-kotlin.md)
- [HTML-to-PDF Conversion](/guides/android/samples/html-to-pdf-conversion-kotlin.md)
- [AES Encrypted File](/guides/android/samples/aes-encrypted-file-java.md)
- [Construction Floor Plan](/guides/android/samples/construction-floor-plan-kotlin.md)
- [Hide and Reveal Areas](/guides/android/samples/hide-and-reveal-areas-kotlin.md)
- [Multiple Documents (Compose Pager)](/guides/android/samples/multiple-documents-compose-pager-kotlin.md)
- [Screen Reader](/guides/android/samples/screen-reader-java.md)
- [Custom Search UI (Views)](/guides/android/samples/custom-search-ui-views-java.md)

