Common Orientation Change Bugs in Logistics Apps: Causes and Fixes

Orientation changes trigger Android’s activity recreation cycle. When a device rotates, the framework destroys the current activity, calls onSaveInstanceState(), and then recreates the activity from s

May 04, 2026 · 4 min read · Common Issues

What Causes Orientation Change Bugs in Logistics Apps

Orientation changes trigger Android’s activity recreation cycle. When a device rotates, the framework destroys the current activity, calls onSaveInstanceState(), and then recreates the activity from scratch. In logistics applications the following technical gaps often surface during this cycle:

Root causeTypical symptomWhy it matters for logistics
State not persistedOrder or cart data disappears after rotationUsers lose inventory selections, leading to duplicate shipments.
Heavy work in onCreate()UI freezes, ANR, or crashBarcode scans or map queries block the main thread, stalling dispatch workflows.
Improper use of static fieldsShared view references become nullSingleton services (e.g., GPS tracker) hold references to destroyed views, causing null‑pointer crashes.
Layout overreliance on fixed dimensionsUI elements overlap or truncateDelivery lists or maps mis‑align, making it hard to locate pickup points.
Unrestored fragment back‑stackNavigation state resetsUsers returning to a confirmation screen find the back button missing, confusing the delivery flow.
Race conditions in async API callsInconsistent data after rotationOrder status updates may arrive after UI rebuild, causing stale ETA displays.

These gaps are amplified in logistics apps because they mix real‑time data (GPS, barcodes, order status) with complex navigation flows (pickup → scan → route → delivery). A single orientation change can ripple through the entire workflow, breaking the user experience.

---

Real‑World Impact

These metrics underscore that orientation bugs are not cosmetic—they directly hurt the bottom line.

---

5‑7 Specific Manifestations in Logistics Apps

#ManifestationExample UIUnderlying defect
1Order details vanishOrder screen shows item list; after rotation the list clears.Missing onSaveInstanceState() for ViewModel data.
2Map resets to default viewDelivery route map reverts to home screen, GPS lock lost.Fragment recreation without preserving map controller.
3Barcode scanner stallsScan button disappears or throws “Camera not available.”Camera resource released in onPause() but not re‑initialized properly.
4Checkout progress lostUser halfway through payment returns to first step after rotation.Static navigation logic not tied to activity lifecycle.
5Delivery ETA overlay stuckPopup overlay remains after rotation, covering critical UI.Overlay view added to a destroyed window token.
6List scroll position resetsIn the inventory list, user was at item #235; rotation jumps to top.RecyclerView state not restored.
7Payment form fields clearCredit‑card fields empty post‑rotation.Form data stored in non‑persisted member variables.

Each of these problems can occur in real‑world scenarios: a driver rotates the phone to read a label, a dispatcher toggles orientations to view both map and list, or a customer checks the status on a tablet that often switches between portrait and landscape.

---

How to Detect Orientation Change Bugs

Tool/TechniqueWhat to Look ForHow SUSA Helps
Manual rotation testsCrashes, ANR, UI glitchesFast, but limited coverage.
Automated rotation in UI testsActivityScenario with setOrientationLeft()/Right()Detects state loss, layout issues.
SUSA autonomous explorationAuto‑rotates while navigating flows, records failuresNo manual scripts; captures crashes, dead buttons, accessibility violations.
Coverage analyticsPer‑screen element coverage before/after rotationHighlights elements lost in rotation.
Flow trackingPASS/FAIL verdicts for login → scan → route → deliverShows where flows break on orientation.
JUnit XML outputCrash stack traces, ANR logsIntegrates into CI pipelines.
CI/CD integration (GitHub Actions)Run SUSA in CI; fail build on new orientation bugsKeeps regression tests up‑to‑date.

Key signals to watch:

SUSA’s automatic test script generation (Appium + Playwright) can be leveraged to create incremental regression tests that specifically rotate between flows, ensuring a repeatable detection process.

---

Fixing Each Example

1. Persist Order Details


// ViewModel holds order data
class OrderViewModel : ViewModel() {
    val orderLiveData = MutableLiveData<Order>()
}

// Activity
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val vm = ViewModelProvider(this).get(OrderViewModel::class.java)
    vm.orderLiveData.observe(this, Observer { render(it) })
}

Why it works: ViewModel survives configuration changes, so the order list is re‑rendered without refetching.

2. Preserve Map State


class MapFragment : Fragment() {
    private var mapState: MapState? = null

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putParcelable("MAP_STATE", mapState)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mapState = savedInstanceState?.getParcelable("MAP_STATE")
    }
}

Why it works: The map controller’s state (camera position, markers) is stored in a Parcelable, restored on recreation.

3. Re‑initialize Barcode Scanner


@Override
protected void onResume() {
    super.onResume();
    camera.start();   // re‑open camera
}

@Override
protected void onPause() {
    camera.stop();
    super.onPause();
}

Why it works: Ensures the camera is opened every time the activity resumes, preventing “Camera not available” after rotation.

4. Tie Navigation to Activity Lifecycle


class CheckoutActivity : AppCompatActivity() {
    private var currentStep = 0

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putInt("STEP", currentStep)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        currentStep = savedInstanceState?.getInt("STEP") ?: 0
        showStep(currentStep)
    }
}

Why it works: The current checkout step is persisted, so rotation does not reset the wizard.

5. Remove Overlays on Destroy


override fun onDestroyView() {
    super.onDestroyView()
    // Remove any floating views
    overlayContainer.removeAllViews()
}

Why it works: Prevents orphaned overlays that reference a destroyed window token.

6. Restore RecyclerView Position


override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putParcelable("LAYOUT_STATE",
        recyclerView.layoutManager?.onSaveInstanceState())
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)
    recyclerView.layoutManager?.onRestoreInstanceState(
        savedInstanceState.getParcelable("LAYOUT_STATE"))
}

Why it works: Keeps scroll position across rotations.

7. Persist Payment Form Data


override fun onSaveInstanceState(outState: Bundle) {
    outState

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free