While migrating my java Android app to Kotlin I've come across with the next issue:
I have a generic class used to run background tasks as follows:
class TaskRunner {
private val executor: Executor =
Executors.newSingleThreadExecutor()
private val handler = Handler(Looper.getMainLooper())
interface Callback<R> {
fun onComplete(result: R)
}
fun <R> executeAsync(callable: Callable<R>, callback: Callback<R>) {
executor.execute {
val result: R
try {
result = callable.call()
handler.post { callback.onComplete(result) }
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
And then I'm doing a TaskRunner call as follows (have to say it was working fine in java):
override fun onShareThisApp(arrayBitmap: ArrayList<Bitmap?>?) {
val appSettings = instance!!
val outputPath = appSettings.outputPathCache
//
val taskRunner = TaskRunner()
taskRunner.executeAsync(
ScreenshotSaver(
arrayBitmap,
outputPath!!,
""
)
) { ipr: ImageProcessingResult -> this::onImageProcessingFinished(ipr) }
}
This is the interface:
interface IImageListeners {
fun onImageProcessingFinished(ipr: ImageProcessingResult)
}
And the method:
@Override
private fun onImageProcessingFinished(ipr: ImageProcessingResult) {
val uris = ArrayList<Uri?>()
for (file in ipr.screenShotFiles) {
val uri = FileProvider.getUriForFile(this, "$packageName.GenericFileProvider", file)
if (uri!=null) uris.add(uri)
}
AWDrawerMenu.listener = this
AWDrawerMenu.activity = WeakReference(this)
AWDrawerMenu.shareFile(uris, "image/jpg")
}
Previously, in my first attempt, I was having a "Type Mismatch" compilation error, and now, after some modifications (like ::) the error is: Overload resolution ambiguity. All these functions match.
public abstract fun onImageProcessingFinished(ipr: com.xxx.xxx.activities.main.ImageProcessingResult): Unit defined in com.xxx.xxx.activities.shared.BaseActivity
private final fun onImageProcessingFinished(ipr: com.xxx.xxx.activities.thought.result.ImageProcessingResult): Unit defined in com.xxx.xxx.activities.shared.BaseActivity
I'm stuck, and I don't know hot to pass a function as argument to a method in Kotlin.
Edit 1:
The only abstract classic my solution:
abstract class BaseActivity : AppCompatActivity(), ICommonActivityMethods, IActionListeners,
IImageListeners, IWaitingDialog {
var appSettings: AppSettings? = null
var dialog: AlertDialog? = null
var sharedPreferences: SharedPreferences? = null
var screen: AWScreen? = null
private var noInternetDialog: AWDialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE)
setContext(this)
setLocale()
setDrawer()
if (className() == "DisplayThoughtActivity") {
checkInternetConnection()
} else {
startActivity()
}
}
private fun className(): String {
return this.javaClass.simpleName
}
private fun setDrawer() {
setDrawer(this)
setupDrawer(this)
}
private fun checkInternetConnection() {
if (!AWHttp.isOnline()) {
showNoInternetDialog()
} else {
startActivity()
}
}
private fun showNoInternetDialog() {
val title = AWLocale.getStringResourceByName("requestpermission_title")
val message = AWLocale.getStringResourceByName("activity_displaythought_notonline")
val positiveButtonText = AWLocale.getStringResourceByName("customalert_accept")
val negativeButtonText = AWLocale.getStringResourceByName("customalert_cancel")
if (noInternetDialog == null) {
noInternetDialog = AWDialog(this)
val rAccept = Runnable { checkInternetConnection() }
val rCancel = Runnable {
noInternetDialog!!.dismiss()
startActivity()
}
noInternetDialog!!.title = title
noInternetDialog!!.message = message
noInternetDialog!!.closeOnAccept = true
noInternetDialog!!.textColor = Color.parseColor("#ffffff")
noInternetDialog!!.positiveButtonText = positiveButtonText
noInternetDialog!!.positiveRunnable = rAccept
noInternetDialog!!.negativeButtonText = negativeButtonText
noInternetDialog!!.negativeRunnable = rCancel
noInternetDialog!!.dismiss = false
noInternetDialog!!.createYesNoDialog()
}
}
override fun onBackPressed() {
super.onBackPressed()
AWAppearance.doTransitionOut(this)
}
override fun onResume() {
super.onResume()
setContext(this)
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(updateBaseContextLocale(base))
}
override fun setLocale() {
val currLang = AWLocale.locale
AWLocale.locale = currLang
}
override fun startActivity() {
if (dialog != null) dialog!!.dismiss()
if (noInternetDialog != null) noInternetDialog!!.dismiss()
AWDrawerMenu.listener = this
setActivityLayout()
}
override fun setActivityLayout() {
setContentView()
setClassVariables()
setActivityBackground()
createActionBar()
resizeActionBarBackButton(this)
}
override fun setClassVariables() {
setContext(this)
appSettings = instance
dialog = AWDialog.createSpotsWaitDialog(this, R.style.CustomSpotsDialogLight)
appSettings!!.dialog = dialog
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
screen = AWScreen(this)
}
private fun updateBaseContextLocale(context: Context): Context {
val language = AWLocale.locale
val locale = Locale(language)
Locale.setDefault(locale)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
updateResourcesLocale(context, locale)
} else updateResourcesLocaleLegacy(context, locale)
}
fun hideKeyboard(editText: EditText) {
val imm = this.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
Objects.requireNonNull(imm).hideSoftInputFromWindow(
editText.windowToken,
InputMethodManager.RESULT_UNCHANGED_SHOWN
)
}
@TargetApi(Build.VERSION_CODES.N)
private fun updateResourcesLocale(context: Context, locale: Locale): Context {
val configuration = context.resources.configuration
configuration.setLocale(locale)
return context.createConfigurationContext(configuration)
}
private fun updateResourcesLocaleLegacy(context: Context, locale: Locale): Context {
val resources = context.resources
val configuration = resources.configuration
configuration.locale = locale
resources.updateConfiguration(configuration, resources.displayMetrics)
return context
}
override fun onShareThisApp(arrayBitmap: ArrayList<Bitmap?>?) {
val appSettings = instance!!
val outputPath = appSettings.outputPathCache
//
val taskRunner = TaskRunner()
taskRunner.executeAsync(
ScreenshotSaver(
arrayBitmap,
outputPath!!,
""
)
) { ipr: ImageProcessingResult -> this::onImageProcessingFinished(ipr) }
}
@Override
private fun onImageProcessingFinished(ipr: ImageProcessingResult) {
val uris = ArrayList<Uri?>()
for (file in ipr.screenShotFiles) {
val uri = FileProvider.getUriForFile(this, "$packageName.GenericFileProvider", file)
if (uri!=null) uris.add(uri)
}
AWDrawerMenu.listener = this
AWDrawerMenu.activity = WeakReference(this)
AWDrawerMenu.shareFile(uris, "image/jpg")
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
}
override fun showWorkingDialog(message: String?) {
WaitingDialog.context = WeakReference(this)
WaitingDialog.setInstance(message)
}
override fun clearWorkingDialog() {
if (WaitingDialog.instance != null) {
WaitingDialog.instance!!.dismiss()
}
}
companion object {
@JvmStatic
fun resizeActionBarBackButton(activity: Activity) {
val tvTitle = activity.findViewById<AutoResizeTextView>(R.id.tvActionBarTitle)
val treeObserver = tvTitle.viewTreeObserver
treeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
override fun onGlobalLayout() {
tvTitle.viewTreeObserver
.removeOnGlobalLayoutListener(this)
val newImgBackHeight = tvTitle.height
val imgBack = activity.findViewById<ImageView>(R.id.imgBack)
val treeObserverImgBack = imgBack.viewTreeObserver
treeObserverImgBack.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
override fun onGlobalLayout() {
imgBack.viewTreeObserver
.removeOnGlobalLayoutListener(this)
val reduction = AWScreen.dp2px(10)
imgBack.layoutParams.height = newImgBackHeight - reduction
imgBack.requestLayout()
}
})
}
})
}
}
}
Edit 2:
I changed the problematic fun to:
override fun onShareThisApp(arrayBitmap: ArrayList<Bitmap?>?) {
val appSettings = instance!!
val outputPath = appSettings.outputPathCache
//
val taskRunner = TaskRunner()
taskRunner.executeAsync(
ScreenshotSaver(
arrayBitmap,
outputPath!!,
""
)
) { ipr: String -> (this::onImageProcessingFinished)(ipr) }
}
