Net Android Networking Library

repository·master·Indexed 24 days ago

https://github.com/liangjingkanji/net

A non-intrusive Android networking library built on OkHttp and Kotlin Coroutines. Net provides high-level abstractions for concurrency, pagination, error handling, and lifecycle management while maintaining compatibility with all OkHttp APIs. Key features include automatic loading dialogs via scopeDialog, integrated pagination with addData(), state management for Loading/Empty/Error views via StateLayout and BRV, and flexible caching options using DiskLruCache and HTTP Cache protocols.

Tokens
29.5K
Snippets
85
Records
146
Agent score
84%

What's inside Net

  1. Overview of Net features and capabilities

    master

    Net is a non-intrusive Android network request library built on top of OkHttp and Kotlin Coroutines. It is designed to be compatible with all OkHttp APIs while providing high-level abstractions for common Android networking tasks.

    Key Capabilities:

    • Concurrency Management: Supports Concurrent, Serial, Queue, and Synchronous request modes. Includes built-in support for returning the fastest result from concurrent requests.
    • Lifecycle Awareness: Automatic request cancellation based on lifecycle and ViewModel support.
    • Data Handling: Generic type support for network returns and converters for various data formats (JSON, Protobuf, etc.).
    • UI Integration: Automatic handling of Pull-to-Refresh, Load-More, Pagination, Loading Dialogs, and Toast error messages.
    • Advanced Networking: Support for HTTPS configuration, Cookie persistence, timed/time-limited requests, and complex caching strategies (Cache-then-Network, LRU, etc.).
    • Monitoring: Detailed upload/download progress monitoring (speed, time remaining, etc.).
  2. Understand the difference between tags and extra data

    master

    Net provides two ways to carry data throughout the entire request lifecycle (Request, Interceptor, and Converter):

    1. Tags (tag): Uses a HashMap<Class<*>, Any?>. Use this when you want to associate data with a specific class type.
    2. Extra Data (extra): Uses a HashMap<String, Any?>. Use this when you want to associate data using a unique string key.

    Choose between them based on whether your key should be a Class or a String.

  3. Understand request parameter types

    master

    Request parameters are categorized into two types based on the HTTP method used:

    1. UrlRequest: Used for GET, HEAD, OPTIONS, and TRACE. Parameters are located in the URL (Query parameters).
    2. BodyRequest: Used for POST, DELETE, PUT, and PATCH. Parameters are sent in the request body as a stream.

    Parameter Helper Functions

    FunctionDescription
    paramFor UrlRequest, it acts as a Query parameter. For BodyRequest, it acts as Form/File data.
    jsonSets the request body as a JSON string.
    setQuery/addQuerySets/adds Query parameters in the URL. For UrlRequest, this is equivalent to param.
    setHeader/addHeaderSets or adds HTTP request headers.
    scopeNetLife {
        val userInfo = Post<UserInfoModel>(Api.LOGIN) {
            param("username", "用户名")
            param("password", "6f2961eb44b12123393fff7e449e50b9de2499c6")
        }.await()
    }
  4. How index management works in automatic pagination

    master

    The index variable is managed automatically by the pagination system:

    • Pull-to-refresh: When the list is refreshed via a downward pull, the index is reset to PageRefreshLayout.startIndex.
    • Pull-to-load-more: When the user pulls up to load more data, the index is automatically incremented by 1 (index++).
  5. Perform synchronous and concurrent requests

    master

    Within a scopeNetLife block, you can manage multiple requests in different ways:

    Synchronous Requests

    Requests are executed sequentially. The second request will only start after the first one completes. You can use the result of the first request as a parameter for the second.

    Concurrent Requests

    To execute requests in parallel, initiate the request objects without calling .await() immediately. This allows multiple requests to be sent simultaneously. You then call .await() on each to retrieve their respective results.

    Scope Management

    • Multiple requests in the same scope can be managed together.
    • If requests are completely unrelated, you can create multiple separate scopes.
    // Synchronous: B waits for A
    scopeNetLife {
        val userInfo = Get<UserInfo>(Api.USER).await() // A
    
        val config = Get<Config>(Api.CONFIG) { // B
            param("userId", userInfo.id) // Uses result from A
        }.await()
    }
    
    // Concurrent: Both start at the same time
    scopeNetLife {
        val getUserInfoAsync = Get<UserInfo>(Api.USER)
        val getConfigAsync = Get<Config>(Api.CONFIG)
    
        val userInfo = getUserInfoAsync.await() 
        val config = getConfigAsync.await()
    }
  6. Understand the scopeDialog lifecycle

    master

    The scopeDialog lifecycle manages the visibility and execution of network tasks as follows:

    Dialog StateScope Behavior
    ShownThe dialog is displayed immediately when executing the scopeDialog block.
    HiddenThe dialog is hidden automatically when the tasks within the scope finish.
    Manually CancelledCancelling the scope will cancel all active network requests within it.
  7. Handle errors in Child Scopes (launch)

    master

    When using launch inside a scopeXX function, the relationship is hierarchical.

    • Execution Order: If an error occurs in the launch block, the invokeOnCompletion callback (A) executes before the outer scope's .catch block (B).
    • Error Propagation:
      • If the scopeNet (outer scope) encounters an error, the request inside the launch (child) is cancelled.
      • If the launch (child) encounters an error, it triggers an error in the scopeNet (outer scope).
    scopeNet {
        val await = Post<String>("path").await()
    
        launch {
           val task = Post<String>("path/error").await()  // Error occurs here
        }.invokeOnCompletion {
            // A
        }
    }.catch {
         // B
    }
    scopeNet {
        val await = Post<String>("path").await()
    
        launch {
           val task = Post<String>("path/error").await()  // 此时发生请求错误
        }.invokeOnCompletion {
            // A
        }
    }.catch {
         // B
    }
  8. Leverage OkHttp knowledge for Net implementation

    master
    Net is built to perfectly support all functional components of OkHttp, which is the mainstream networking solution for Android. If you encounter a feature that is not explicitly implemented in Net, you can find the implementation pattern by searching for "OkHttp如何实现XX" (How OkHttp implements XX) on Google. You can then easily apply that OkHttp pattern within Net.
  9. Configure Interval types (Count-limited, Infinite, and Countdown)

    master

    The Interval class provides three primary modes of operation based on how you initialize it:

    1. Limit by count/interval: Specify a fixed number of executions. Use .life(lifecycleOwner) to bind the interval to a lifecycle (e.g., an Activity or Fragment) so it cancels automatically when the page is destroyed.
    2. Infinite execution: Provide only the period. The callback will trigger repeatedly and will not end automatically.
    3. Countdown: Provide a start value, an end value, and a period. If start > end and end != -1, the interval acts as a countdown.

    Note: Due to system restrictions, the library cannot guarantee continuous execution when the application is running in the background.

  10. Best practices for network requests in ViewModel

    master

    When using Net within a ViewModel, follow these recommendations:

    • Avoid unnecessary ViewModel usage: Network requests do not have to be written in the ViewModel if they don't require lifecycle management or state preservation.
    • Avoid interface callbacks: Do not use traditional interface callbacks for network requests; prefer coroutines and await().
    • Direct Activity returns: In some simple cases, you can return request results directly in the Activity.
  11. Handle missing or null fields in JSON

    master

    Use the explicitNulls property to control how missing or null fields are handled:

    • Enabling Default Values: When coerceInputValues = true, if a JSON field is null and the data class field is non-nullable, the field's default value is used. If no default value exists, set explicitNulls = false to assign null.
    • Missing Fields: If a field is missing in the JSON, setting ignoreUnknownKeys = true will cause the data class to use its default values. If no default value exists, set explicitNulls = false to assign null.
    • Serialization: When explicitNulls = false, fields that are null in the data class will be omitted from the resulting JSON.
  12. Use the `tag` field for custom error metadata

    master

    Net's built-in exceptions include a tag field of type Any. This field allows you to pass arbitrary objects (like error codes) through the exception to your error handler for precise decision-making.

    A common pattern is using ResponseException to signal backend business errors, passing the specific business error code via the tag parameter.