android_5.0_viewdemo

repository·master·Indexed 19 days ago

https://github.com/aiirux/android_5.0_viewdemo

A collection of demonstration projects for Android 5.0, 6.0, and N. It features implementations of high-performance Gaussian blur using RenderScript and the BlurredView custom control, as well as architectural patterns for reducing boilerplate in lists via a generic CommonAdapter and CommonViewHolder using SparseArray for memory-efficient view caching.

Tokens
27K
Snippets
47
Records
68
Agent score
68%

What's inside android_5.0_viewdemo

  1. Overview of Android 5.0/6.0/N Feature Demos

    master
    This repository is a collection of small demonstration cases focusing on new features introduced in Android 5.0 (Lollipop), 6.0 (Marshmallow), and Android N. It provides practical implementations for various Android components, architectural patterns, and UI effects to help developers understand and implement modern Android features.
  2. Overview of HelloCharts capabilities

    master

    HelloCharts is a chart control library for Android. This demo showcases several types of visualizations and customization options available through the library:

    • Basic Charts: Standard implementations of common chart types.
    • Line Charts: Visualizing data trends over time.
    • Column Charts: Representing data using vertical bars.
    • Combo Charts: Combining different chart types (e.g., Line and Column) in a single view.
    • Advanced Customization: High-level configuration of modules, attributes, and visual effects.

    Note: This demo is intended for Android 5.0 and above.

  3. What is RxJava and the ReactiveX concept

    master

    Rx (ReactiveX) is a library that allows developers to compose asynchronous and event-based programs using observable sequences and LINQ-style query operators.

    RxJava is the Java implementation of this concept. It is essentially a library for implementing asynchronous operations using observable sequences on the Java VM. It is a programming paradigm used to create asynchronous, event-driven programs.

  4. Understand the RxJava execution flow (create vs subscribe)

    master

    In RxJava, the relationship between an Observable and a Subscriber (or Observer) is established through a two-step process: creation and subscription.

    1. create(): This method creates an Observable instance and attaches an OnSubscribe object to it. The OnSubscribe object contains the logic that defines how data is emitted.
    2. subscribe(): This method triggers the execution. When you call subscribe(subscriber), RxJava executes the call(subscriber) method stored within the Observable's onSubscribe property. This call method is what actually invokes the onNext, onCompleted, and onError methods of your subscriber.

    Crucial Execution Order: The subscribe() method initiates the process, but the actual logic inside the OnSubscribe.call() method (where your data emission happens) is executed as a result of the subscription. In a synchronous setup, the subscribe call will block until the call method completes its execution.

    // 1. Create the Observable
    Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            subscriber.onNext("Hello");
            subscriber.onNext("World");
            subscriber.onCompleted();
            Log.i("Execution Order", " call completed ");
        }
    });
    
    // 2. Subscribe to trigger the logic
    observable.subscribe(new Observer<String>() {
        @Override
        public void onNext(String s) {
            Log.i("onNext", s);
        }
    
        @Override
        public void onCompleted() {
            Log.i("onCompleted", "done");
        }
    
        @Override
        public void onError(Throwable e) {
            Log.i("onError", e.toString());
        }
    });
  5. Understand Gson core components: JsonParser, JsonElement, and TypeToken

    master

    When working with GSON for manual or complex parsing, understand these three key components:

    1. JsonParser: A utility class used to parse JSON strings into structured GSON objects. Use .parse(string).getAsJsonObject() for objects or .parse(string).getAsJsonArray() for arrays.
    2. JsonElement: An abstract base class representing any element in a JSON string. It can be a JsonObject, JsonArray, or JsonPrimitive. When iterating through a JsonArray, each item is returned as a JsonElement.
    3. TypeToken<T>: A utility used to capture generic type information (like List<UserBean>) at runtime. Because of Java's type erasure, TypeToken allows GSON to use reflection to understand the specific type T inside a generic container.
  6. How the RxJava Observer Pattern works

    master

    RxJava extends the traditional Observer pattern. In this model, an Observer reacts to changes in an Observable through a subscription relationship established via subscribe().

    Key Differences in RxJava:

    • Subscription: Achieved via the subscribe() method.
    • Event Callbacks: There are three primary lifecycle events:
      • onNext(): Emits the next item in the sequence.
      • onCompleted(): Signals the end of the event queue. A correctly running sequence should call onCompleted() or onError() exactly once, and it must be the last event.
      • onError(): Signals an error in the event processing. This terminates the sequence immediately.

    Observable Types:

    • Cold Observable: Only emits items when at least one Observer has subscribed.
    • Hot Observable: Emits items regardless of whether there are active subscribers.
  7. Understand FuncX and ActionX interfaces

    master

    RxJava uses FuncX and ActionX interfaces to wrap functional logic. The primary difference is that FuncX returns a value, while ActionX does not.

    ActionX (No return value)

    Used to wrap methods that perform an action without returning a result. They are often used in subscribe() to provide incomplete callback definitions:

    • Action0: Wraps onCompleted() (zero arguments).
    • Action1<T>: Wraps onNext(T) and onError(Throwable) (one argument).
    • Action2, Action3, etc.: Wrap methods with more arguments.

    FuncX (With return value)

    Used to wrap functions that transform data and return a result:

    • Func1<T, R>: Takes one argument of type T and returns a result of type R. This is the standard interface used with the map operator.
  8. Parse highly complex/nested JSON using JsonReader

    master

    For extremely complex, deeply nested JSON structures where creating full Bean models is impractical or inefficient, use JsonReader. This approach is similar to XML parsing: you navigate the JSON tree node-by-node based on keys.

    Mental Model:

    • Use beginObject() and endObject() to enter and exit JSON objects.
    • Use beginArray() and endArray() for arrays.
    • Use nextName() to retrieve the current key/tag.
    • Use nextString(), nextInt(), etc., to retrieve values.
    • Use skipValue() to ignore fields you don't care about, which prevents unnecessary processing.

    Warning: This method is more verbose and requires manual management of the parsing state, but it is highly efficient for selective parsing.

    /**
     * Example of manual node-based parsing with JsonReader
     */
    private void parseComplexJArrayByReader() throws IOException {
        String strByJson = "...json_string...";
        JsonReader reader = new JsonReader(new StringReader(strByJson));
        try {
            reader.beginObject();
            String tagName = reader.nextName();
            if (tagName.equals("group")) {
                readGroup(reader);
            }
            reader.endObject();
        } finally {
            reader.close();
        }
    }
    
    private void readGroup(JsonReader reader) throws IOException {
        reader.beginObject();
        while (reader.hasNext()) {
            String tagName = reader.nextName();
            if (tagName.equals("user")) {
                readUser(reader);
            } else if (tagName.equals("info")) {
                readInfo(reader);
            } else {
                reader.skipValue(); // Skip unknown nodes
            }
        }
        reader.endObject();
    }
    
    private void readUser(JsonReader reader) throws IOException {
        reader.beginObject();
        while (reader.hasNext()) {
            String tag = reader.nextName();
            if (tag.equals("name")) {
                String name = reader.nextString();
                // Use name...
            } else if (tag.equals("age")) {
                String age = reader.nextString();
                // Use age...
            } else {
                reader.skipValue(); // Skip irrelevant fields
            }
        }
        reader.endObject();
    }
  9. Evaluate the Pros and Cons of Android Data Binding

    master

    When deciding whether to use Data Binding in your Android project, consider the following trade-offs:

    Advantages

    • Reduces Boilerplate: Eliminates the need to manually assign IDs to views and perform findViewById calls.
    • Safety: Helps prevent NullPointerException related to view lookups.
    • Efficiency: Provides a fast way to handle simple data-to-view mappings.

    Disadvantages

    • Complexity: Handling highly complex layouts or intricate logic within XML can become difficult and hard to maintain.
    • Tooling: IDE support may not be as seamless as other libraries (like ButterKnife).
    • Learning Curve: Requires understanding the specific XML syntax and lifecycle of binding objects.
  10. Implement a CommonViewHolder for efficient view recycling

    master

    A CommonViewHolder uses a SparseArray<View> to cache views by their ID, reducing the need for repeated findViewById calls. It manages the lifecycle of a convertView and provides a fluent API for setting view properties.

    Key Responsibilities:

    • Caching: Uses SparseArray to store and retrieve views by ID.
    • Lifecycle: Handles inflation of the layout and manages the convertView via setTag.
    • Fluent API: Supports method chaining (e.g., .setText(...).setImageResource(...)) to simplify view updates.

    Core Methods:

    • get(Context, View, ViewGroup, int, int): Static method to retrieve an existing ViewHolder from a convertView tag or create a new one.
    • getView<T>(int viewId): Retrieves a view of type T from the cache or performs a findViewById if not cached.
    • getConvertView(): Returns the underlying View for use in the Adapter's getView method.
    // Example of using CommonViewHolder in an Adapter's getView method
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 1. Get the ViewHolder
        CommonViewHolder viewHolder = CommonViewHolder.get(context, convertView, parent, R.layout.item_list, position);
    
        NewsBean bean = list.get(position);
    
        // 2. Set content using fluent API
        viewHolder.setText(R.id.tv_title, bean.getTitle())
                .setText(R.id.tv_desc, bean.getDesc())
                .setText(R.id.tv_time, bean.getTime())
                .setText(R.id.tv_phone, bean.getPhone());
    
        // 3. Return the recycled view
        return viewHolder.getConvertView();
    }
  11. Implement a Three-Level Cache mechanism (ImageLoader pattern)

    master

    For optimal performance in image loading, it is recommended to combine different caching strategies into a single ImageLoader class. This is known as a Three-Level Cache mechanism:

    1. Memory Cache (LruCache): Provides the fastest access to recently used Bitmaps in RAM.
    2. Disk Cache (DiskLruCache): Provides persistent storage for images on the device disk, preventing re-downloads after app restarts.
    3. Network/Source: The fallback mechanism to fetch data when both memory and disk caches miss.

    By encapsulating these into an ImageLoader, you can manage Bitmap compression and seamless transitions between cache levels automatically.

  12. Understand Scheduler operators: subscribeOn vs observeOn

    master

    RxJava uses Schedulers to control concurrency. Two primary operators manage thread switching:

    • subscribeOn(Scheduler): Specifies the thread on which the subscribe() method (and consequently the call() method of the source Observable) executes. It defines the thread where the event is produced.
    • observeOn(Scheduler): Specifies the thread on which the Observer callbacks (like onNext(), onError(), and onCompleted()) execute. It defines the thread where the event is consumed.