<|start_filename|>app/src/main/java/com/king/mvvmframe/app/adapter/BindingHolder.java<|end_filename|>
package com.king.mvvmframe.app.adapter;

import android.view.View;

import com.king.base.adapter.holder.ViewHolder;

import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;

/**
 * @author <a href="mailto:<EMAIL>">Jenly</a>
 */
public class BindingHolder<VDB extends ViewDataBinding> extends ViewHolder {

    VDB mBinding;

    public BindingHolder(View convertView) {
        super(convertView);
        mBinding = DataBindingUtil.bind(convertView);

    }

    public VDB getBinding(){
        return mBinding;
    }
}


<|start_filename|>app/src/main/java/com/king/mvvmframe/util/RandomUtils.java<|end_filename|>
package com.king.mvvmframe.util;

import android.graphics.Color;

import java.util.Random;

import androidx.annotation.ColorInt;
import androidx.annotation.IntRange;

/**
 * @author <a href="mailto:<EMAIL>">Jenly</a>
 */
public enum  RandomUtils {
    INSTANCE;

    private Random mRandom = new Random();

    @ColorInt
    public int randomColor(@IntRange(from=0,to=255) int min, @IntRange(from=0,to=255) int max){
        return Color.rgb(random(min,max),random(min,max),random(min,max));
    }

    public int random(int min,int max){
        return mRandom.nextInt(max - min + 1) + min;
    }
}

<|start_filename|>lib/src/main/java/com/king/frame/mvvmframe/base/ILoading.java<|end_filename|>
package com.king.frame.mvvmframe.base;

/**
 * @author <a href="mailto:<EMAIL>">Jenly</a>
 */
public interface ILoading {
    /**
     * 显示加载
     */
    void showLoading();

    /**
     * 隐藏加载
     */
    void hideLoading();

}


<|start_filename|>app/src/main/java/com/king/mvvmframe/dao/AppDatabase.java<|end_filename|>
package com.king.mvvmframe.dao;


import com.king.mvvmframe.bean.SearchHistory;

import androidx.room.Database;
import androidx.room.RoomDatabase;

/**
 * @author <a href="mailto:<EMAIL>">Jenly</a>
 */
@Database(entities = {SearchHistory.class}, version = 1,exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {

    public abstract SearchHistoryDao searchHistoryDao();
}


<|start_filename|>lib/src/main/java/com/king/frame/mvvmframe/data/IDataRepository.java<|end_filename|>
package com.king.frame.mvvmframe.data;

import android.content.Context;

import java.lang.Class;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.room.Room;
import androidx.room.RoomDatabase;

/**
 * 统一管理数据业务层，实现类见{@link DataRepository}
 * @author <a href="mailto:<EMAIL>">Jenly</a>
 */
public interface IDataRepository {
    /**
     * 提供上下文{@link Context}
     * @return {@lik Context}
     */
    Context getContext();
    /**
     * 传入Class 通过{@link retrofit2.Retrofit#create(Class)} 获得对应的Class
     * @param service
     * @param <T>
     * @return {@link retrofit2.Retrofit#create(Class)}
     */
    <T> T getRetrofitService(@NonNull Class<T> service);

    /**
     * 传入Class 通过{@link Room#databaseBuilder},{@link RoomDatabase.Builder<T>#build()}获得对应的Class
     * @param database
     * @param dbName
     * @param <T>
     * @return {@link RoomDatabase.Builder<T>#build()}
     */
    <T extends RoomDatabase> T getRoomDatabase(@NonNull Class<T> database, @Nullable String dbName);

}

<|start_filename|>lib/src/main/java/com/king/frame/mvvmframe/base/IModel.java<|end_filename|>
package com.king.frame.mvvmframe.base;


import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

/**
 * @author <a href="mailto:<EMAIL>">Jenly</a>
 */
public interface IModel extends LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestroy();

}


<|start_filename|>lib/src/main/java/com/king/frame/mvvmframe/base/ContentActivity.java<|end_filename|>
package com.king.frame.mvvmframe.base;

import android.content.Intent;
import android.os.Bundle;

import com.king.frame.mvvmframe.R;

import androidx.annotation.IdRes;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import androidx.fragment.app.Fragment;

/**
 * 用于容纳Fragment的通用Activity，相当于一个Fragment容器，通过{@link Intent} 传递参数和标识，然后实现{@link #switchFragment}处理对应的逻辑
 * @author <a href="mailto:<EMAIL>">Jenly</a>
 */
public abstract class ContentActivity extends BaseActivity<DataViewModel, ViewDataBinding> {


    @Override
    public int getLayoutId() {
        return R.layout.mvvmframe_content_activity;
    }

    @Override
    public void initData(@Nullable Bundle savedInstanceState) {
        switchFragment(getIntent());
    }

    /**
     * 不使用DataBinding {@link DataBindingUtil}
     * @return
     */
    @Override
    public boolean isBinding() {
        return false;
    }

    /**
     *  通过{@link #getSupportFragmentManager()}将布局替换成{@link Fragment}，如在{@link #switchFragment(Intent)}方法中使用
     * @param fragment
     */
    protected void replaceFragment(Fragment fragment){
        replaceFragment(R.id.fragmentContent,fragment);
    }

    /**
     *  通过{@link #getSupportFragmentManager()}将布局替换成{@link Fragment}
     * @param fragment
     */
    protected void replaceFragment(@IdRes int id, Fragment fragment) {
        getSupportFragmentManager().beginTransaction().replace(id, fragment).commit();
    }

    /**
     * 切换Fragment
     * @param intent 通过{@link Intent} 传递参数和标记来判断对应展示某个{@link Fragment}
     */
    protected abstract void switchFragment(Intent intent);
}

<|start_filename|>lib/src/main/java/com/king/frame/mvvmframe/bean/Resource.java<|end_filename|>
package com.king.frame.mvvmframe.bean;


import com.king.frame.mvvmframe.base.livedata.StatusEvent;

import androidx.annotation.Nullable;

/**
 * @author <a href="mailto:<EMAIL>">Jenly</a>
 */
public class Resource<T> {

    @StatusEvent.Status
    public int status;

    @Nullable
    public String message;

    @Nullable
    public T data;

    @Nullable
    public Throwable error;

    public Resource(@StatusEvent.Status int status) {
        this(status,null);
    }

    public Resource(@StatusEvent.Status int status, @Nullable String message) {
        this(status,message,null);
    }

    public Resource(@StatusEvent.Status int status, @Nullable String message, @Nullable T data) {
        this(status,message,data,null);
    }

    public Resource(@StatusEvent.Status int status, @Nullable String message, @Nullable T data, @Nullable Throwable error) {
        this.status = status;
        this.message = message;
        this.data = data;
        this.error = error;
    }

    public boolean isLoading(){
        return status == StatusEvent.Status.LOADING;
    }

    public boolean isSuccess(){
        return status == StatusEvent.Status.SUCCESS;
    }

    public boolean isFailure(){
        return status == StatusEvent.Status.FAILURE;
    }

    public boolean isError(){
        return status == StatusEvent.Status.ERROR;
    }

    public static <T> Resource<T> loading() {
        return new Resource<>(StatusEvent.Status.LOADING);
    }

    public static <T> Resource<T> loading(@Nullable T data) {
        return new Resource<>(StatusEvent.Status.LOADING, null,data);
    }

    public static <T> Resource<T> success(@Nullable T data) {
        return new Resource<>(StatusEvent.Status.SUCCESS,null,data);
    }

    public static <T> Resource<T> failure(String msg) {
        return new Resource<>(StatusEvent.Status.FAILURE, msg);
    }

    public static <T> Resource<T> error(Throwable t) {
        return error(t,null);
    }

    public static <T> Resource<T> error(Throwable t,String msg) {
        return new Resource<>(StatusEvent.Status.ERROR, msg,null,t);
    }

}


<|start_filename|>lib/src/main/java/com/king/frame/mvvmframe/util/Preconditions.java<|end_filename|>
package com.king.frame.mvvmframe.util;

import java.lang.String;
import java.lang.Object;
import java.lang.IllegalStateException;
import java.lang.IllegalArgumentException;
import java.lang.NullPointerException;

import androidx.annotation.Nullable;

/**
 * @see <a href="https://github.com/google/guava/blob/b86fe4fc7ec511d78507c3ba32c789d1f250f827/guava/src/com/google/common/base/Preconditions.java">guava</a>
 * @author <a href="mailto:<EMAIL>">Jenly</a>
 */
public final class Preconditions {
    private Preconditions() {}

    /**
     * Ensures the truth of an expression involving one or more parameters to the calling method.
     *
     * @param expression a boolean expression
     * @throws IllegalArgumentException if {@code expression} is false
     */
    public static void checkArgument(boolean expression) {
        if (!expression) {
            throw new IllegalArgumentException();
        }
    }

    /**
     * Ensures the truth of an expression involving one or more parameters to the calling method.
     *
     * @param expression a boolean expression
     * @param errorMessage the exception message to use if the check fails; will be converted to a
     *     string using {@link String#valueOf(Object)}
     * @throws IllegalArgumentException if {@code expression} is false
     */
    public static void checkArgument(boolean expression, @Nullable Object errorMessage) {
        if (!expression) {
            throw new IllegalArgumentException(String.valueOf(errorMessage));
        }
    }

    /**
     * Ensures the truth of an expression involving one or more parameters to the calling method.
     *
     * @param expression a boolean expression
     * @param errorMessageTemplate a template for the exception message should the check fail. The
     *     message is formed by replacing each {@code %s} placeholder in the template with an
     *     argument. These are matched by position - the first {@code %s} gets {@code
     *     errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
     *     square braces. Unmatched placeholders will be left as-is.
     * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
     *     are converted to strings using {@link String#valueOf(Object)}.
     * @throws IllegalArgumentException if {@code expression} is false
     */
    public static void checkArgument(
            boolean expression,
            @Nullable String errorMessageTemplate,
            @Nullable Object... errorMessageArgs) {
        if (!expression) {
            throw new IllegalArgumentException(lenientFormat(errorMessageTemplate, errorMessageArgs));
        }
    }

    /**
     * Ensures the truth of an expression involving the state of the calling instance, but not
     * involving any parameters to the calling method.
     *
     * @param expression a boolean expression
     * @throws IllegalStateException if {@code expression} is false
     */
    public static void checkState(boolean expression) {
        if (!expression) {
            throw new IllegalStateException();
        }
    }

    /**
     * Ensures the truth of an expression involving the state of the calling instance, but not
     * involving any parameters to the calling method.
     *
     * @param expression a boolean expression
     * @param errorMessage the exception message to use if the check fails; will be converted to a
     *     string using {@link String#valueOf(Object)}
     * @throws IllegalStateException if {@code expression} is false
     */
    public static void checkState(boolean expression, @Nullable Object errorMessage) {
        if (!expression) {
            throw new IllegalStateException(String.valueOf(errorMessage));
        }
    }

    /**
     * Ensures the truth of an expression involving the state of the calling instance, but not
     * involving any parameters to the calling method.
     *
     * @param expression a boolean expression
     * @param errorMessageTemplate a template for the exception message should the check fail. The
     *     message is formed by replacing each {@code %s} placeholder in the template with an
     *     argument. These are matched by position - the first {@code %s} gets {@code
     *     errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
     *     square braces. Unmatched placeholders will be left as-is.
     * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
     *     are converted to strings using {@link String#valueOf(Object)}.
     * @throws IllegalStateException if {@code expression} is false
     */
    public static void checkState(
            boolean expression,
            @Nullable String errorMessageTemplate,
            @Nullable Object... errorMessageArgs) {
        if (!expression) {
            throw new IllegalStateException(lenientFormat(errorMessageTemplate, errorMessageArgs));
        }
    }

    /**
     * Ensures that an object reference passed as a parameter to the calling method is not null.
     *
     * @param reference an object reference
     * @return the non-null reference that was validated
     * @throws NullPointerException if {@code reference} is null
     */
    
    public static <T> T checkNotNull(T reference) {
        if (reference == null) {
            throw new NullPointerException();
        }
        return reference;
    }

    /**
     * Ensures that an object reference passed as a parameter to the calling method is not null.
     *
     * @param reference an object reference
     * @param errorMessage the exception message to use if the check fails; will be converted to a
     *     string using {@link String#valueOf(Object)}
     * @return the non-null reference that was validated
     * @throws NullPointerException if {@code reference} is null
     */

    public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {
        if (reference == null) {
            throw new NullPointerException(String.valueOf(errorMessage));
        }
        return reference;
    }

    /**
     * Ensures that an object reference passed as a parameter to the calling method is not null.
     *
     * @param reference an object reference
     * @param errorMessageTemplate a template for the exception message should the check fail. The
     *     message is formed by replacing each {@code %s} placeholder in the template with an
     *     argument. These are matched by position - the first {@code %s} gets {@code
     *     errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
     *     square braces. Unmatched placeholders will be left as-is.
     * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
     *     are converted to strings using {@link String#valueOf(Object)}.
     * @return the non-null reference that was validated
     * @throws NullPointerException if {@code reference} is null
     */
    
    public static <T> T checkNotNull(
            T reference, @Nullable String errorMessageTemplate,@Nullable Object... errorMessageArgs) {
        if (reference == null) {
            throw new NullPointerException(lenientFormat(errorMessageTemplate, errorMessageArgs));
        }
        return reference;
    }

    public static String lenientFormat(
            @Nullable String template, @Nullable Object... args) {
        template = String.valueOf(template); // null -> "null"

        if (args == null) {
            args = new Object[] {"(Object[])null"};
        }

        // start substituting the arguments into the '%s' placeholders
        StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
        int templateStart = 0;
        int i = 0;
        while (i < args.length) {
            int placeholderStart = template.indexOf("%s", templateStart);
            if (placeholderStart == -1) {
                break;
            }
            builder.append(template, templateStart, placeholderStart);
            builder.append(args[i++]);
            templateStart = placeholderStart + 2;
        }
        builder.append(template, templateStart, template.length());

        // if we run out of placeholders, append the extra args in square braces
        if (i < args.length) {
            builder.append(" [");
            builder.append(args[i++]);
            while (i < args.length) {
                builder.append(", ");
                builder.append(args[i++]);
            }
            builder.append(']');
        }

        return builder.toString();
    }
    

}