Создать обобщенную c функцию высшего порядка в kotlin - PullRequest
2 голосов
/ 11 марта 2020

У меня есть интерфейс GalleryImagesDataCallback, который я использую для передачи данных из фонового потока в поток пользовательского интерфейса, чтобы избежать вызова runOnUiThread() из каждого переопределенного метода GalleryImagesDataCallback, я использовал kotlin функцию более высокого порядка .

interface GalleryImagesDataCallback {

fun fetchedList(list: ArrayList<ImageGalleryItemModel>)

@JvmDefault
fun callMethodOnUIThreadForFetch(mContext: Context, list:ArrayList<ImageGalleryItemModel>,func: (ArrayList<ImageGalleryItemModel>) -> Unit) {
   (mContext as BaseActivity).runOnUiThread {
     Logger.error("TEST_ABC","callMethodOnUIThreadForFetch Enter")
     func(list)
   }
}

fun deleteList()

@JvmDefault
fun callMethodOnUIThreadForDelete(mContext: Context, func: () -> Unit) {
(mContext as BaseActivity).runOnUiThread {
   Logger.error("TEST_ABC","callMethodOnUIThreadForDelete Enter")
   func()
 } 
}    

}

Вызов из фонового потока:

callback.callMethodOnUIThreadForFetch(mContext,list) {list:ArrayList<ImageGalleryItemModel> -> callback.fetchedList(list)}  // callback is reference of GalleryImagesDataCallback

callback.callMethodOnUIThreadForDelete(mContext) {callback.deleteList()}

Проблема:

Прямо сейчас у меня есть 2 отдельных метода callMethodOnUIThreadForDelete() и callMethodOnUIThreadForFetch(). Есть ли способ в kotlin создать один обобщенный метод c (скажем, callMethodOnUIThread()), который я могу использовать для вызова deleteList() и fetchedList() и без изменений в определении функции?

1 Ответ

1 голос
/ 11 марта 2020

Сначала, чтобы ответить на ваш буквальный вопрос, ваша функция callMethodOnUIThreadForFetch имеет ненужное перенаправление аргумента list. Зачем делать список аргументом функции высшего порядка только для того, чтобы передать его обратно в аргумент функции? Вы можете использовать вашу функцию callMethodOnUIThreadForDelete для любой цели, но предположим, что мы переименовали ее и удалили небезопасное приведение к Activity с помощью обработчика:

// In interface:
fun callMethodOnUIThread(context: Context, func: () -> Unit) {
    Handler(context.mainLooper).post(func)
}

// From background thread:
callback.callMethodOnUIThread(mContext) { callback.fetchedList(list) }
callback.callMethodOnUIThread(mContext) { callback.deleteList() }

Предполагая, что вы хотите упростить работу по реализации этого интерфейса тогда я не думаю, что это действительно помогает. Вы перенесли работу по вызову кода в потоке пользовательского интерфейса из реализации интерфейса в пользователя интерфейса. Вы также можете создать глобальную вспомогательную функцию вместо того, чтобы загромождать ваш интерфейс, что является странным местом для этого. Использование становится более простым:

// Global utility function, not in a class
fun Context.onUiThread(func: () -> Unit) {
    Handler(mainLooper).post(func)
}

// Usage:
mContext.onUiThread { callback.fetchedList(list) }
mContext.onUiThread { callback.deleteList() }

Если вы действительно хотите полностью инкапсулировать переключение потоков, вам придется изменить свой интерфейс на абстрактный класс, например:

abstract class GalleryImagesDataCallback {
    protected abstract fun fetchedListImpl(list: List<String>)
    protected abstract fun deleteListImpl()

    fun fetchedList(context: Context, list: List<String>) {
        Handler(context.mainLooper).post { fetchListImpl(list) }
    }

    fun deleteList(context: Context) {
        Handler(context.mainLooper).post { deleteListImpl() }
    }
}

Вместо этого реализации интерфейса, вы должны создать его подклассы и реализовать две абстрактные функции. Ни подкласс, ни пользователь обратного вызова не должны заботиться о том, чтобы код вызывался в потоке пользовательского интерфейса.

...