How to modify instance variable from separate AsyncTask - android

let's say i have an activity with instance variable loadedMovie and a method that executes AsyncTask which is in another file
class MainActivity:AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
var loadedMovie: Movie? = null
....
fun loadMovie() {
val task = LoadMovieTask(this)
task.execute()
}
}
separate AsyncTask
class LoadMovieTask(val ctx: Activity) : AsyncTask<Void, Void, Void>() {
var movie: Movie? = null
override fun onPreExecute() {
....
}
// loading information from network
override fun doInBackground(vararg params: Void?): Void? {
movie = load()
return null
}
// here i modify views with help of kotlin android extensions
override fun onPostExecute(result: Void?) {
....
}
}
problem is: somehow i can't modify loadedMovie neither from doInBackground (which is ok, because it runs on separate thread) and onPostExecute (which is not ok)
i just type ctx.loadedMovie in onPostExecute and it's not there.. maybe i don't understand something? or maybe there is another way to do it that i'm not aware of

Use this
class LoadMovieTask(val ctx: MainActivity)
instead of
class LoadMovieTask(val ctx: Activity)
MainActivity has the method and not the Android's Activity class itself. So even though you need the context, since you are trying to access the method specific to MainActivity, it is required to pass that

Related

Using AsyncTask with Runnable vs Creating AsyncTask Class

I recently came across a code snippet that used Runnable with AsyncTask, which I was not familiar with previously.
AsyncTask.execute{
/* Some code to run in Background
* ...
* ...
*/
runOnUiThread{
//run on main thread, just like onPostExecute
}
}
I would like to know how does this compare with following way where we create an AsyncTask class?
class MyAsyncTask : AsyncTask<Unit, Unit, String>() {
override fun doInBackground(vararg params: Unit): String {...}
override fun onPostExecute(result: String) {...}
}
Are there any performance or other downsides of the first method?
I don't think it has any thing to do with performance. They are just different ways that you could use to implement this action. If I was writing this code, I would create a class and implement it there.

How to get context from MainActivity from anywhere and how to access it's functions?

I've just recently started going on about android developing not long after I've got stuck.
I want to know how can I get MainActivity's context and it's functions globaly (if that's possible)
The only method I've got to work is passing the context as an argument to another classes' constructor. this#MainActivity doesn't work nor does trying to get a function such as MainActivity.getContext() which returns the context.
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView1.settings.javaScriptEnabled = true
webView1.webViewClient = Client(this) //Initialize the class
webView1.loadUrl("https://www.urbs.curitiba.pr.gov.br/mobile/cartao")
}
fun getContext(): Context //Not accessible from Client
{
return getContext()
}
}
//Client class
class Client(context: Context): WebViewClient()
{
val context: Context = context //This works
override fun onPageFinished(view: WebView, url: String)
{
webView1.loadUrl("https://kotlinlang.org/docs/reference/this-expressions.html")
Toast.makeText(context, "Uau", Toast.LENGTH_SHORT).show()
//using this#MainActivity as context is not defined
}
}
It would be great if I could use functions from the mainactivity class but I'm not really familiarized with the language and therefore I can't do so (if it's possible) right now.
This is my first post at stackoverflow and I'm really sorry if it is low quality, I'm not yet familiriazed with the system.
Welcome to StackOverflow!
In your specific case, there's no need to pass an instance of Context through the constructor, you can instead access the WebView's context property: all View subclasses in Android have a reference to a Context instance.
//Client class
class Client : WebViewClient()
{
override fun onPageFinished(view: WebView, url: String)
{
webView1.loadUrl("https://kotlinlang.org/docs/reference/this-expressions.html")
Toast.makeText(view.context, "Uau", Toast.LENGTH_SHORT).show()
}
}
In general, if you ever need a reference to Context, prefer passing it explicitly rather than storing it in global variables - this way you'll be able to prevent memory leaks.
MainActivity.getContext() means there is a public static method called getContext in MainActivity class while there isn't;
about your scenario, you already have passed a MainActivity instance to the Client class so you can just cast it and call getContext() method:
class Client(context: Context): WebViewClient()
{
private val context: MainActivity = context as MainActivity //This works
override fun onPageFinished(view: WebView, url: String)
{
webView1.loadUrl("https://kotlinlang.org/docs/reference/this-expressions.html")
Toast.makeText(context, "Uau", Toast.LENGTH_SHORT).show()
//now its possible
}
}
about accessing a class instances (like your MainActivity) globally, you can always put your instances in a public static variable and access them from everywhere(but implementing this for Android Activity class is a bit tricky )

Reuse methods in Kotlin, Android

I need to open one activity from several different points in the app. Let's say from Settings fragment, Main Activity and Navigation drawer (fragment). I don't want to copy/paste the same method and the method is very specific, it should be exactly the same (because it registeres Firebase events). How to structure the code in effective way? Where to put this method? One idea is to have a global ActivityUtils.kt file with just methods and it would be used to store these methods. I'm interested in the alternatives and what are pros and cons of each.
I would create a companion object in the Activity you need to open:
class YourActivity : AppCompatActivity() {
companion object {
fun start(ctx: Context) {
// put your logic here (registering of Firebase events)
val i = Intent(ctx, YourActivity::class.java)
ctx.startActivity(i)
}
}
}
And call it from another activity:
YourActivity.start(this)
or from another fragment:
YourActivity.start(context)
Use an extension method:
fun Activity.doMyStuff() {}
That can be called from any class extending Activity:
doMyStuff()
Extension functions like this shouldn't go inside a class, but rather inside a file. So if you were to make an ActivityUtils.kt file, don't have any sort of class ActivityUtils {} stuff in it. The function(s) should just go directly into the file.
Why not to use MVP?
Like,
interface IView {
val context: Context
}
interface IPresenter {
fun launchActivity(view: IView)
}
class MyActivityModel
{
var key = "key"
/*some other data*/
fun getParcelableObject(): Parcelable
{
return /*some parcelable from model data*/
}
}
class MyActivity : AppCompatActivity(), IView
{
override val context: Context
get() = this
}
class MyActivityPresenter() : IPresenter
{
private var model: MyActivityModel = MyActivityModel()
override fun launchActivity(view: IView)
{
val intent = Intent(view.context, MyActivity::class.java)
intent.putExtra(model.key, model.getParcelableObject())
view.context.startActivity(intent)
}
fun setSomeDataToModel(someData: Any) {
}
}
/*Everyone who wants to use presenter, must be a Context and implement IView*/
fun use()//in some fragment, or activity implementing IView
{
MyActivityPresenter().launchActivity(this)
//or
val presenter = MyActivityPresenter()
presenter.setSomeDataToModel("some data")
presenter.launchActivity(this)
}

Create class extend AsyncTask without leaking context object in Android Kotlin

I defined a base class extends AsyncTask and have some custom method. I want to create some child classes which extend this, and override some methods. But by this way, its field will leaks the Context object.
abstract class ParentTask(context: Context) : AsyncTask<Void, Int, String>()
{
...
override fun doInBackground(vararg params: Void): String? {
...
}
...
}
Please tell me why and show me how to implement it in Android Kotlin? I'm very appreciated if there's an example about this.
p/s : I'm searched for this but can't understand. Why using Singleton, or other design pattern
You can't avoid this warning this way, but you can handle that your context is application context and it won't leak:
abstract class ParentTask(context: Context) : AsyncTask<Void, Int, String>() {
private val context: Context
init {
this.context = context.applicationContext
}
override fun doInBackground(vararg voids: Void): String? {
//...
}
}

Kotlin generics issue

The error occurs when passing this to onResume.
Somehow it doesn't recognize that this implements ActivityLifecycleType, Am I missing something?
open class BaseActivity<ViewModelType: ActivityViewModel<*>>: RxAppCompatActivity(), ActivityLifecycleType {
protected var viewModel: ViewModelType? = null
#CallSuper
override fun onResume() {
super.onResume()
viewModel?.onResume(this) ==> Error Required Nothing, Find BaseActivity<ViewModelType>
}
}
open class ActivityViewModel<in ViewType: ActivityLifecycleType> {
fun onResume(view: ViewType) {
// Do something
}
}
interface ActivityLifecycleType {
fun lifecycle(): Observable<ActivityEvent>
}
Kotlin's generics' more strict that you have you write use the code below:
open class BaseActivity<ViewModelType : ActivityViewModel<ActivityLifecycleType>> : ActivityLifecycleType, RxAppCompatActivity() {
protected var viewModel: ViewModelType? = null
#CallSuper
override fun onResume() {
super.onResume()
viewModel?.onResume(this#BaseActivity) // ==> Error Required Nothing, Find BaseActivity<ViewModelType>
}
}
open class ActivityViewModel<in ViewType : ActivityLifecycleType> {
fun onResume(view: ViewType) {
// Do something
}
}
interface ActivityLifecycleType {
fun lifecycle(): Observable<ActivityEvent>
}
What I've done is to change the declaration in the first line.
Java is too weak to check the generic type but Kotlin do.
Mention there're two things you have to do next:
implement lifecycle in BaseActivity or make it abstract.
it's recommended to use lateinit var viewModel instead of nullable types

Categories

Resources