How to change activity from onPostExecute() method using kotlin - android

I have an activity called LoginActivity in my app (using kotlin). This will send a post request to an API as an Async task. I want to change the activity from onPostExecute method to MainWindowActivity after getting response from the API.
I cannot change the activity:
val intent = Intent(this, MainWindowActivity::class.java)
startActivity(intent)
since this will only return LoginActivity.PostJsonAsync
(PostJsonAsync is a class which extends AsyncTask)

To refer an outer class instance (LoginActivity) from inner class (PostJsonAsync) in Kotlin, you must make your class as inner (they can access outer class instance) by adding inner keyword before class.
inner class PostJsonAsync : AsyncTask<Void, Void, Void>() {
override fun onPostExecute(result: Void?) {
super.onPostExecute(result)
val intent = Intent(this#LoginActivity, LoginActivity::class.java)
startActivity(intent)
}
}

Simple:
val intent = Intent(name_of_your_activity:class.this, MainWindowActivity::class.java)
startActivity(intent)

Related

How to bind external library class with callback in Hilt?

I'm a beginner in Hilt. I have a library which takes in an interface. The library does some operation and invokes the interface callback. I have an activity which invokes this library by passing the interface implementation. I'd like to know how to inject this using Hilt.
Interface in library
interface InterfaceInLibrary() {
fun callback1()
fun callback2(/*params */)
}
Activity
class MyActivity: InterfaceInLibrary() {
override fun onCreate(savedInstanceState: Bundle?) {
//library initialization
val myLibraryClass = MyLibraryClass.getInstance(this) //passing the InterfaceInLibrary implementation
}
override fun callback1() {
Toast.makeText(this, "callback1", Toast.LENGTH_LONG).show()
}
override fun callback2() {
Toast.makeText(this, "callback2", Toast.LENGTH_LONG).show()
}
}
I would like to know how to inject MyLibraryClass in MyActivity using Hilt.
The only possible way I know (or at least how I am handling this use-case in my projects) is to field inject the concrete class that invokes the interface and then let the activity implement the concrete class and inherit from the callback. Since your interface and your concrete class look kinda weird, I will provide a full implementation here. Let's assume we have the following interface:
Interface
interface IMyCallbackInterface {
fun callbackWithoutParameters()
fun callbackWithParameters(value: String)
}
Then, you need some class to invoke this callback. In my case, this was always a recylerview.adapter, but we will use somethin easier:
Invoking class
class MyInvokingClass #Inject constructor() {
// this interface will be initialized by our activity
private lateinit var callbackListener: IMyCallbackInterface
// This function invokes the first callback
fun someFunctionThatInvokesCallbackWithoutParameters() {
// do some stuff
callbackListener.callbackWithoutParameters()
}
// This function invokes the second callback
fun someFunctionThatInvokesCallbackWithParameters() {
// do some stuff
callbackListener.callbackWithParameters(value = "Hello")
}
// This will be called from our activity to initialize the callback
fun initializeCallback(callbackOwner: IMyCallbackInterface) {
this.callbackListener = callbackOwner
}
}
Then, you need to field inject the class and inherit from the callback inside your activity
Activity or Fragment
class MyActivity : IMyCallbackInterface {
#Inject lateinit var invokingClass: MyInvokingClass
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate()
setContentView(...)
// Since MyActivity implements the interface
// it is an instance of it. So you can simply
// say, that the "owner" of the callback is the activity
invokingClass.initializeCallback(this#MyActivity)
}
override fun callbackWithoutParameters() {
// do some stuff
}
override fun callbackWithParameters(value: String) {
// do some stuff with string
}
}
Because our Activity inherits from the callback and we said in onCreate() that the interfaceOwner of MyInvokingClass is the activity, every time the callback gets invoked, the interface functions inside the activity will be invoked as well.

How "this" keyword actually works inside Intent constructor arguement?

Intent construcotr's arguements require object of Context class but down here inside this code I am passing "this" which means object of MainActivity class object. How it works? because it requires Context Class instance but i am passing MainActivity's instance.
const val EXTRA_MESSAGE = "com.example.myfirstApp.MESSAGE"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun sendMessage(view: View){
val editText = findViewById<EditText>(R.id.editText)
val message = editText.text.toString()
val intent =Intent(this,DisplayMessageActivity::class.java).apply{
// if I use MainActivity() instead of this , gives me error
putExtra(EXTRA_MESSAGE, message)
}
startActivity(intent)
}
}
Here, this means MainActivity's instance, but if I use MainActivity() instead of this it gives me error. Whereas this and MainActivity() are same thing here.
In Android Activity, Service, BroadcastReceiver, Application all extends Context. So you can pass them in place of Context.
You can see all the class that an Activity class extends here.

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)
}

How to get previous activity in android Kotlin

Lets say my default activity is MainActivity and I start another activity DepositActivity without using finish() in MainActivity
Now how can I access the instance of MainActivity inside DepositActivity
Now as how can I access the instance of MainActivity inside DepositActivity
AFAIK That is not possible to access instance of one activity in other Activity
if you have this type of requirement than Try to manage using Fragments
If you want to retrieve some result from DepositActivity use startActivityForResult(..., DepositActivity::class.java) method. In MainActivity override onActivityResult method:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// retrieve data using 'data' variable
}
In DepositActivity you need to set data using method setResult() before finishing DepositActivity.
If you want to pass some data to DepositActivity use intent for that, for example:
val intent = Intent(this, DepositActivity::class.java)
intent.putExtra("Extra_Name", /*Some Data*/)
startActivity(intent)
Not Recommended: Use static reference to MainActivity (don't forget to delete it in onDestroy() method):
class MainActivity : AppCompatActivity() {
companion object {
#SuppressLint("StaticFieldLeak")
#JvmStatic
var instance: MainActivity? = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
instance = this
}
override fun onDestroy() {
instance = null
super.onDestroy()
}
}
In DepositActivity you can access it like this:
MainActivity.instance?./* call some method or property */
But you should not rely on onDestroy() being called, cause there are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it... So you can have memory leak
You need to declare as companion object variable and method in MainActivity. Static type of variables and methods are declared as companion object in Kotlin.
Look at below example,
Declare variables and methods in MainActivity,
val value : String = "hello from Main"
companion object {
lateinit var instance : MainActivity
fun getInstancem() : MainActivity {
return instance
}
}
Use this instance and print value in DepositActivity like,
Log.d("log_in_second_activity", "message " + MainActivity.getInstancem().value)
You can see log message.
Hope this will give you hint.

How to modify instance variable from separate AsyncTask

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

Categories

Resources