1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/catchpig-kmvvm

Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

Технические моменты

  • Поддержка Flow + Retrofit + OkHttp для реализации цепочечных HTTP-запросов

  • Поддержка RxJava + Retrofit + OkHttp для реализации цепочечных HTTP-запросов

  • Глобальная настройка страницы с ошибкой загрузки сети и поддержка повторной загрузки данных

  • Глобальная конфигурация пустой страницы списка

  • Создание базовых классов: BaseActivity, BaseVMActivity, BaseFragment, BaseVMFragment, RecycleAdapter, BaseViewModel

  • Внедрение LifeCycle, связывание жизненного цикла ViewModel и Activity

  • Использование библиотеки startup для переноса инициализации в KotlinMvvmInitializer, что позволяет избежать создания подкласса BaseApplication

  • KSP (аннотации времени компиляции) для создания аннотаций: Title, OnClickFirstDrawable, OnClickFirstText, OnClickSecondDrawable, OnClickSecondText, Prefs, PrefsField, StatusBar, FlowError, GlobalConfig, ServiceApi

  • Создание классов расширения инструментов: CalendarExt, ContextExt, DateExt, EditTextExt, GsonExt, RxJavaExt, StringExt, SnackbarExt

Архитектура

Минимальная совместимость: 21

Версия выпуска

Gitee

Github

Журнал изменений

Gradle

1. В корневом файле build.gradle добавьте:

plugins {
    id 'org.jetbrains.kotlin.jvm' version "1.8.0" apply false
    id 'org.jetbrains.kotlin.multiplatform' version '1.8.0' apply false
    id 'org.jetbrains.kotlin.plugin.serialization' version '1.8.0' apply false
    id 'com.google.devtools.ksp' version '1.8.21-1.0.11' apply false
}

2. В файле app/build.gradle добавьте:

plugins {
    id 'kotlinx-serialization'

    id 'com.google.devtools.ksp'
}

3. В файл app/gradle.properties добавьте:

  • Отключить инкрементную компиляцию ksp
ksp.incremental=false

4. В разделе android файла app/build.gradle добавьте:

buildFeatures {
    viewBinding = true
}

5. Добавьте зависимости:

implementation "com.github.catchpig.kmvvm:mvvm:last_version"
ksp "com.github.catchpig.kmvvm:compiler:last_version"

Для использования функции загрузки необходимо отдельно добавить следующую зависимость:

implementation "com.github.catchpig.kmvvm:download:last_version"

Использование

1. Настройка всех параметров

interface IGlobalConfig {
    /**
     * Высота строки заголовка
     * @return Int
     */
    @DimenRes
    fun getTitleHeight(): Int

    /**
     * Ресурсы кнопки возврата строки заголовка
     * @return Int
     */
    @DrawableRes
    fun getTitleBackIcon(): Int

    /**
     * Цвет фона строки заголовка
     * @return Int
     */
    @ColorRes
    fun getTitleBackground(): Int

    /**
     * Цвет текста строки заголовка
     * @return Int
     */
    @ColorRes
    fun getTitleTextColor(): Int

    /**
     * Стиль шрифта строки заголовка
     * @return Int
     */
    @TextStyle
    fun getTitleTextStyle(): Int

    /**
     * Требуется ли горизонтальная линия под строкой заголовка
     * @return Boolean
     */
    fun isShowTitleLine(): Boolean

    /**
     * Цвет горизонтальной линии под строкой заголовка
     * @return Int
     */
    @ColorRes
    fun getTitleLineColor(): Int

    /**
     * Цвет индикатора загрузки
     * @return Int
     */
    @ColorRes
    fun getLoadingColor(): Int

    /**
     * Цвет фона индикатора загрузки
     * @return Int
     */
    @ColorRes
    fun getLoadingBackground(): Int

    /**
     * ViewBinding для пустой страницы RecyclerView
     * @param parent ViewGroup
     * @return ViewBinding
     */
    fun getRecyclerEmptyBanding(parent: ViewGroup): ViewBinding

    /**
     * Отображение страницы при ошибке сетевого запроса
     * @param layoutInflater LayoutInflater
     * @param any Any BaseActivity или
``` Вот перевод текста на русский язык:

**BaseFragment**
    * @return ViewBinding
    */
    fun getFailedBinding(layoutInflater: LayoutInflater, any: Any): ViewBinding?

    /**
     * Страница ошибки, требующая повторной загрузки, идентификатор события клика
     * @return Int
     */
    @IdRes
    fun onFailedReloadClickId(): Int
    
    /**
     * Размер страницы при каждой загрузке
     * @return Int
     */
    fun getPageSize(): Int

    /**
     * Индекс начальной страницы (некоторые настройки бэкенда равны 0, некоторые — 1)
     */
    fun getStartPageIndex(): Int
}

+ Реализовать интерфейс **IGlobalConfig** (./annotation/src/main/java/com/catchpig/annotation/IGlobalConfig.kt) и добавить аннотацию **GlobalConfig** к классу реализации (./annotation/src/main/java/com/catchpig/annotation/GlobalConfig.kt).

> Пример использования:

```kotlin
@GlobalConfig
class MvvmGlobalConfig : IGlobalConfig {
    override fun getTitleHeight(): Int {
        return R.dimen.title_bar_height
    }

    override fun getTitleBackIcon(): Int {
        return R.drawable.back_black
    }

    override fun getTitleBackground(): Int {
        return R.color.colorPrimary
    }

    override fun getTitleTextColor(): Int {
        return R.color.white
    }

    override fun getTitleTextStyle(): Int {
      return TextStyle.BOLD
    }

    override fun isShowTitleLine(): Boolean {
        return true
    }

    override fun getTitleLineColor(): Int {
        return R.color.color_black
    }

    override fun getLoadingColor(): Int {
        return R.color.color_black
    }

    override fun getLoadingBackground(): Int {
        return R.color.white
    }

    override fun getRecyclerEmptyBanding(parent: ViewGroup): ViewBinding {
        return LayoutEmptyBinding.inflate(LayoutInflater.from(parent.context), parent, false)
    }
    
    override fun getFailedBinding(layoutInflater: LayoutInflater, any: Any): ViewBinding? {
        return when (any) {
            is BaseActivity<*> -> {
                LayoutActivityErrorBinding.inflate(layoutInflater)
            }
            is BaseFragment<*> -> {
                LayoutFragmentErrorBinding.inflate(layoutInflater)
            }
            else -> {
                null
            }
        }
    }

    override fun onFailedReloadClickId(): Int {
        return R.id.failed_reload
    }

    override fun getPageSize(): Int {
        return 16
    }

    override fun getStartPageIndex(): Int {
        return 1
    }
}

2. Activity

  • Использовать MVVM и наследовать от BaseVMActivity.
  • Не использовать MVVM и наследовать от BaseActivity.

2.1 Использование аннотаций для заголовка

Пример использования

Другие параметры аннотации Title см. ниже в разделе «Аннотации»

//Установка текста заголовка
@Title(R.string.child_title)
class ChildActivity : BaseVMActivity<ActivityChildBinding, ChildViewModel>() 

Если текст заголовка должен отображаться по-разному в зависимости от интерфейса, есть также интерфейс для настройки

class ChildActivity : BaseVMActivity<ActivityChildBinding, ChildViewModel>() {
    @OnClickFirstDrawable(R.drawable.more)
    fun clickFirstDrawable(v: View) {
        updateTitle("Изменение заголовка")
    }
}

2.2 Использование аннотаций для строки состояния

Пример использования

Параметры аннотации StatusBar см. ниже в разделе «Аннотации»

//Отказаться от аннотации
@StatusBar(hide = true)
class FullScreenActivity : BaseActivity<ActivityFullScreenBinding>()

2.3 Использование аннотаций для правого текста или значка кнопки заголовка

Пример использования

Метод с аннотацией может принимать параметр View или не иметь параметров, в зависимости от ваших потребностей

@Title(R.string.child_title)
class ChildActivity : BaseVMActivity<ActivityChildBinding, ChildViewModel>() {
    @OnClickFirstDrawable(R.drawable.more)
    fun clickFirstDrawable(v: View) {
        SnackbarManager.show(bodyBinding.root, "Эффект нажатия на первую кнопку с изображением")
        updateTitle("nihao")
    }

    @OnClickFirstText(R.string.more)
    fun clickFirstText() {
        SnackbarManager.show(bodyBinding.root, "Эффект нажатия на первый текстовый элемент")
        updateTitle("12354")
    }

    @OnClickSecondDrawable(R.drawable.more)
    fun clickSecondDrawable(v: View) {
        SnackbarManager.show(bodyBinding.root, "Эффект нажатия на вторую кнопку с изображением")
        updateTitle("nihao")
    }

    @OnClickSecondText(R.string.more)
    fun clickSecondText() {
        SnackbarManager.show(bodyBinding.root, "Эффект нажатия на второй текстовый элемент")
        updateTitle("12354")
    }
}

2.4 Подсказка

  • После Android 11 Toast больше не поддерживает пользовательские тосты, а собственные Toast выглядят плохо.
  • В этом фреймворке используется SnackBar для отображения подсказок.

Пример использования

@OnClickSecondDrawable(R.drawable.more)
fun clickSecondDrawable(v: View) {
    snackBar("Эффект нажатия на вторую кнопку с изображением")
}
``` **2.5 Страница с ошибкой загрузки**

* Сетевой запрос завершается неудачно  можно отобразить страницу ошибки, а также предоставить кнопку для повторной загрузки данных.

* В расширенной функции lifecycleLoadingView класса BaseView устанавливается значение showFailedView в true, если запрос данных завершился неудачно, то будет показана страница ошибки.

* Повторно вызвать сетевой запрос интерфейса можно в замыкании onFailedReload (см. файл BaseView.kt), чтобы повторно загрузить данные.

```kotlin
/**
 * Показывает страницу с ошибкой после неудачной загрузки, пользователь может нажать на кнопку обновления на этой странице, чтобы запросить данные снова.
 * @param autoFirstLoad Boolean указывает, следует ли автоматически загружать данные при первом обращении.
 * @param block [@kotlin.ExtensionFunctionType] Function1<View, Unit>
 */
fun onFailedReload(autoFirstLoad: Boolean = true, block: View.() -> Unit){
    .....
}
override fun initFlow() {
    onFailedReload {
        loadingViewError(bodyBinding.root)
    }
}

fun loadingViewError(v: View) {
    viewModel.loadingViewError().lifecycleLoadingView(this, showFailedView = true) {
        snackBar(this)
    }
}

3. Фрагмент

  • Используйте MVVM и наследуйте от BaseVMFragment.
  • Если не используете MVVM, наследуйтесь от BaseFragment.

3.1 Тост-сообщение

  • После Android 11 использование Toast для создания пользовательских сообщений становится затруднительным. В этом фреймворке используется SnackBar для отображения сообщений.

Пример использования:

snackbar.setOnClickListener {
    snackBar("Сообщение")
}

3.2 Страница с ошибкой загрузки

  • При неудачном сетевом запросе можно показать страницу с ошибкой и предоставить кнопку обновления для повторной попытки загрузки данных.
  • В функции расширения lifecycleLoadingView установите значение showFailedView равным true, чтобы отобразить страницу с ошибкой при неудаче запроса данных.
  • Чтобы повторно загрузить данные, вызовите интерфейс сетевого запроса в замыкании onFailedReload (файл BaseView.kt).
/**
 * Отображает страницу с ошибкой после неудачи при загрузке, пользователь может обновить страницу, нажав на соответствующую кнопку, чтобы повторить попытку загрузки данных.
 * @param autoFirstLoad Boolean определяет, должна ли загрузка происходить автоматически при первом обращении.
 * @param block [@kotlin.ExtensionFunctionType] Function1<View, Unit>
 */
fun onFailedReload(autoFirstLoad: Boolean = true, block: View.() -> Unit){
    .....
}
override fun initFlow() {
    onFailedReload {
        loadBanners()
    }
}

private fun loadBanners(){
    viewModel.queryBanners().lifecycleLoadingDialog(this, true) {
        val images = mutableListOf<String>()
        this.forEach {
            images.add(it.imagePath)
        }
        bodyBinding.banner.run {
            setImages(images)
            start()
        }
    }
}

4. RecycleView

  • Адаптер можно наследовать от RecycleAdapter (файл RecyclerAdapter.kt) для использования. RecycleAdapter использует ViewBinding, необходимо реализовать только два метода.

Пример использования:

class UserAdapter(iPageControl: IPageControl) :
    RecyclerAdapter<User, ItemUserBinding>(iPageControl) {

    override fun viewBinding(parent: ViewGroup): ItemUserBinding {
        return ItemUserBinding.inflate(LayoutInflater.from(parent.context), parent, false)
    }

    override fun bindViewHolder(holder: CommonViewHolder<ItemUserBinding>, m: User, position: Int) {
        holder.viewBanding {
            name.text = m.name
        }
    }
}

5. Обновление страницы с помощью RefreshRecyclerView

  • RefreshRecyclerView объединяет RefreshLayoutWrapper и RecyclerView.
  • Не нужно беспокоиться о логике разбиения на страницы, логика обновления разбиения на страницы реализована в RefreshLayoutWrapper.
  • Необходимо установить LayoutManager и RecyclerAdapter, доступны методы setLayoutManager и setAdapter.
  • Вызывайте метод updateData при получении данных.
  • Вызовите метод updateError при неудаче получения данных.
  • Если используется lifecycleRefresh, не нужно заботиться о методах updateData и updateError.
  • Предоставляется настраиваемое свойство recycler_background для установки цвета фона RecyclerView. Текст запроса:

app:recycler_background="#445467"> </com.catchpig.mvvm.widget.refresh.RefreshRecyclerView>

bodyBinding.refresh.run {
    setOnRefreshLoadMoreListener { nextPageIndex ->
        viewModel.queryArticles(nextPageIndex).lifecycleRefresh(this@ArticleFragment, this)
    }
}

Перевод:

Приложение: recycler_background = "#445467" > </com.catchpig.mvvm.widget.refresh.RefreshRecyclerView>

bodyBinding.refresh.run {
    setOnRefreshLoadMoreListener { nextPageIndex ->
        viewModel.queryArticles(nextPageIndex).lifecycleRefresh(this@ArticleFragment, this)
    }
}
``` ### 7. Журналирование

+ Не нужно инициализировать в приложении, так как LogUtils уже инициализирован в KotlinMvvmInitializer (./mvvm/src/main/java/com/catchpig/mvvm/initializer/KotlinMvvmInitializer.kt).
+ Можно использовать LogUtils.getInstance().i, LogUtils.getInstance().d для печати журналов (не рекомендуется).
+ Также можно использовать методы расширения LogExt для печати журналов (рекомендуется).

### 8. Использование аннотаций (REMARD_ANNOTATION.md)

### 9. Менеджер загрузки файлов (REMARD_DOWNLOAD_MANAGER.md)

### 10. Библиотека утилит (utils/README.md)

**Обфускация**

```properties
-keep class com.catchpig.annotation.enums.**
-keep class com.google.android.material.snackbar.Snackbar {*;}
-keep @com.catchpig.annotation.ServiceApi class * {*;}
-keep public class **.databinding.*Binding {*;}
-keep class **.*_Compiler {*;}
# Сериализация обфускации
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
static <1>$Companion Companion;
}
# Сохраняем serializer() на сопутствующих объектах (как по умолчанию, так и с именем) сериализуемых классов.
-if @kotlinx.serialization.Serializable class ** {
static **$* *;
}
-keepclassmembers class <1>$<3> {
kotlinx.serialization.KSerializer serializer(...);
}
# Сохраняем INSTANCE.serializer() сериализуемых объектов.
-if @kotlinx.serialization.Serializable class ** {
public static ** INSTANCE;
}
-keepclassmembers class <1> {
public static <1> INSTANCE;
kotlinx.serialization.KSerializer serializer(...);
}
# @Serializable и @Polymorphic используются во время выполнения для полиморфной сериализации.
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault

Сторонние библиотеки

SmartRefreshLayout — компонент обновления (https://github.com/scwang90/SmartRefreshLayout)

Immersionbar — статусная панель (https://github.com/gyf-dev/ImmersionBar)

RxJava3

RxAndroid

OkHttp

Retrofit

Gson

kotlinpoet — инструмент генерации кода kt (https://github.com/square/kotlinpoet)

AndroidUtilKTX — набор инструментов (https://github.com/lulululbj/AndroidUtilCodeKTX)

LoadingView — анимация загрузки (https://github.com/catch-pig/LoadingView)

coroutines — сопрограммы (https://github.com/Kotlin/kotlinx.coroutines)

serialization — сериализация (https://github.com/Kotlin/kotlinx.serialization)

Прочее

Группа общения QQ (228014675)

Добро пожаловать к обсуждению вопросов в issue, я буду периодически просматривать их и решать проблемы.

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

MVVM-фреймворк, основанный на Kotlin, Flow, Retrofit, OKHttp, ViewBinding, ViewModel и LiveData, поддерживает доступ к сетевым запросам с использованием сопрограмм. Используется новейший фреймворк компиляции Kotlin KSP. Можно задать глобальную страницу загрузки при ошибке, а также поддерживать время нажатия для глобального обновления данных. К... Развернуть Свернуть
Apache-2.0
Отмена

Обновления (47)

все

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/catchpig-kmvvm.git
git@api.gitlife.ru:oschina-mirror/catchpig-kmvvm.git
oschina-mirror
catchpig-kmvvm
catchpig-kmvvm
master