Kotlin context to activity

Kotlin Android start new Activity

To start an Activity in java we wrote Intent(this, Page2.class) , basically you have to define Context in first parameter and destination class in second parameter. According to Intent method in source code —

 public Intent(Context packageContext, Class cls) 

As you can see we have to pass Class type in second parameter.

By writing Intent(this, Page2) we never specify we are going to pass class, we are trying to pass class type which is not acceptable.

Use ::class.java which is alternative of .class in kotlin. Use below code to start your Activity

Intent(this, Page2::class.java) 
// start your activity by passing the intent startActivity(Intent(this, Page2::class.java).apply < // you can add values(if any) to pass to the next class or avoid using `.apply` putExtra("keyIdentifier", value) >) 

Any idea why they changed it to ::class.java instead of .class ? The Kotlin approach is unusually complicated, compared to Java.

Simply you can start an Activity in KOTLIN by using this simple method,

val intent = Intent(this, SecondActivity::class.java) intent.putExtra("key", value) startActivity(intent) 

@ShadeToD Yeah! No need to use putExtra method. I just added it for passing values when starting new Activity

startActivity(Intent(this@CurrentClassName,RequiredClassName::class.java) 
class MainActivity : AppCompatActivity() < override fun onCreate(savedInstanceState: Bundle?) < super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) >fun buTestUpdateText2 (view: View) < startActivity(Intent(this@MainActivity,ClassName::class.java)) // Also like this val intent = Intent(this@MainActivity,ClassName::class.java) startActivity(intent) >

You forgot to add an ending ‘)’ in startActivity(Intent(this@CurrentClassName,RequiredClassName::class.java)

You have to give the second argument of class type. You can also have it a little bit more tidy like below.

startActivity(Intent(this, Page2::class.java).apply < putExtra("extra_1", value1) putExtra("extra_2", value2) putExtra("extra_3", value3) >) 

You can generally simplify the specification of the parameter BlahActivity::class.java by defining an inline reified generic function.

inline fun Context.createIntent() = Intent(this, T::class.java) 
startActivity(createIntent()) 
inline fun Activity.startActivity() < startActivity(createIntent()) > 

You could set up inline fun Context.createIntent(vararg extras: Pair) = Intent(this, T::class.java).apply < putExtras(bundleOf(*extras)) >instead of what I said and it’ll work (assuming you have bundleOf from android-ktx or anko)

val intent = Intent(this, Page2::class.java) startActivity(intent) 

Well, I found these 2 ways to be the simplest of all outcomes:

accoun_btn.setOnClickListener
 accoun_btn.setOnClickListener < startActivity(this) > private inline fun startActivity(context: Context)

This is my main activity where i take the username and password from edit text and setting to the intent

class MainActivity : AppCompatActivity() < val userName = null val password = null override fun onCreate(savedInstanceState: Bundle?) < super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) button.setOnClickListener < val intent = Intent(this@MainActivity,SecondActivity::class.java); var userName = username.text.toString() var password = password_field.text.toString() intent.putExtra("Username", userName) intent.putExtra("Password", password) startActivity(intent); >> 

This is my second activity where i have to receive values from the main activity

override fun onCreate(savedInstanceState: Bundle?)

This is because your Page2 class doesn’t have a companion object which is similar to static in Java so to use your class. To pass your class as an argument to Intent , you will have to do something like this

val changePage = Intent(this, Page2::class.java) 

From activity to activity

val intent = Intent(this, YourActivity::class.java) startActivity(intent) 

From fragment to activity

val intent = Intent(activity, YourActivity::class.java) startActivity(intent) 

another simple way of navigating to another activity is

Intent(this, CodeActivity::class.java).apply

Pls do consider of explaining your code and how it would help, so that others can get benefited from this.

fun Context.launchActivity( cls: Class<*>, flags: Int = 0, intentTransformer: Intent.() -> Unit = <> ) < val intent = Intent(this, cls).apply < addFlags(flags) intentTransformer() >this.startActivity(intent) > 

Code dumps without any explanation are rarely helpful. Stack Overflow is about learning, not providing snippets to blindly copy and paste. Please edit your question and explain how it works better than what the OP provided. See How to Answer.

For me it worked like a glove, Let me try to explain. When creating functions like this, you are using advanced and beneficial kotlin techniques, the name of this technique is extension Functions. I will give an example below:

How about this to consider encapsulation?

 override fun onCreate(savedInstanceState: Bundle?) < super.onCreate(savedInstanceState) setContentView(R.layout.activity_contents) val title = intent.getStringExtra(EXTRA_TITLE) ?: EXTRA_TITLE_DEFAULT supportFragmentManager.beginTransaction() .add(R.id.frame_layout_fragment, ContentsFragment.newInstance()) .commit() >// Omit. companion object < private const val EXTRA_TITLE = "extra_title" private const val EXTRA_TITLE_DEFAULT = "No title" fun newIntent(context: Context, title: String): Intent < val intent = Intent(context, ContentsActivity::class.java) intent.putExtra(EXTRA_TITLE, title) return intent >> 
val intentAct: Intent = Intent(this@YourCurrentActivity, TagentActivity::class.java) startActivity(intentAct) 

I had a similar issue, I started to write my application in Kotlin, after I rewrote one of my activities I wanted to see if there are any issues, the problem was that I was not sure how to send an intent from java file to kotlin file.

In this case I created a static function in kotlin (companion object), this function is getting a context (from the current activity) and returning the new intent while using the current context («java» context) while using the kotlin class («::class.java»).

 //this code will be in the kotlin activity - SearchActivity companion object < fun newIntent(context: Context): Intent < return Intent(context, SearchActivity::class.java) >> //this is how you call SearchActivity from MainActivity.java Intent searchIntent = SearchActivity.Companion.newIntent(this); startActivity(searchIntent); 

Источник

Getting activity from context in android

This one has me stumped. I need to call an activity method from within a custom layout class. The problem with this is that I don’t know how to access the activity from within the layout.

ProfileView

public class ProfileView extends LinearLayout < TextView profileTitleTextView; ImageView profileScreenImageButton; boolean isEmpty; ProfileData data; String name; public ProfileView(Context context, AttributeSet attrs, String name, final ProfileData profileData) < super(context, attrs); . . >//Heres where things get complicated public void onClick(View v) < //Need to get the parent activity and call its method. ProfileActivity x = (ProfileActivity) context; x.activityMethod(); >> 

ProfileActivity

public class ProfileActivityActivity extends Activity < //In here I am creating multiple ProfileViews and adding them to the activity dynamically. public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.profile_activity_main); >public void addProfilesToThisView() < ProfileData tempPd = new tempPd(. ) Context actvitiyContext = this.getApplicationContext(); //Profile view needs context, null, name and a profileData ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd); profileLayout.addView(pv); >> 
  1. Am i passing the correct context into the Profileview?
  2. How do I get the containing activity from the context?

15 Answers 15

From your Activity , just pass in this as the Context for your layout:

ProfileView pv = new ProfileView(this, null, temp, tempPd); 

Afterwards you will have a Context in the layout, but you will know it is actually your Activity and you can cast it so that you have what you need:

Activity activity = (Activity) context; 

You can’t be guaranteed that the context you are working with is an Activity Context or an Application Context. Try passing an Application Context to a DialogView, watch it crash, and you will see the difference.

Boris, the question asks if there is a way to get an Activity from a Context. This is not possible. Of course you can cast, but that is a last resort. If you want to treat the Context as an Activity, then don’t downcast to an Activity. It makes for simpler code, and is less prone to bugs later when another person is maintaining your code.

@BorisStrandjev I haven’t quite understand your comment. Anyway, I said that after trying your example but instead of ‘this’ I used getApplicationContext() and the application tried to cast the App itself, hence giving a cast error, instead of the activity. After switching to ‘this’, as you answered, it worked.

The highest upvoted answers on your link both suggest challenging the question if it is smelly. This question certainly is smelly. The OP first stated: «I need to call an activity method from within a custom layout class.» which is completely achievable with appropriate use of interfaces. Then he says «The problem with this is that I don’t know how to access the activity from within the layout.» which is a significant hint toward a misunderstanding. People try to to do the wrong thing all the time in programming and we shouldn’t turn a blind eye to it.

This is something that I have used successfully to convert Context to Activity when operating within the UI in fragments or custom views. It will unpack ContextWrapper recursively or return null if it fails.

public Activity getActivity(Context context) < if (context == null) < return null; >else if (context instanceof ContextWrapper) < if (context instanceof Activity) < return (Activity) context; >else < return getActivity(((ContextWrapper) context).getBaseContext()); >> return null; > 

@lygstate: What target API level are you using in your app? What is the error? This only works within the UI (activities, fragments, etc), not in Services.

There are two different contexts in Android. One for your application (Let’s call it the BIG one) and one for each view (let’s call it the activity context).

A linearLayout is a view, so you have to call the activity context. To call it from an activity, simply call «this». So easy isn’t it?

this.getApplicationContext(); 

You call the BIG context, the one that describes your application and cannot manage your view.

A big problem with Android is that a context cannot call your activity. That’s a big deal to avoid this when someone begins with the Android development. You have to find a better way to code your class (or replace «Context context» by «Activity activity» and cast it to «Context» when needed).

Just to update my answer. The easiest way to get your Activity context is to define a static instance in your Activity . For example

public class DummyActivity extends Activity < public static DummyActivity instance = null; @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); // Do some operations here >@Override public void onResume() < super.onResume(); instance = this; >@Override public void onPause() < super.onPause(); instance = null; >> 

And then, in your Task , Dialog , View , you could use that kind of code to get your Activity context :

if (DummyActivity.instance != null) < // Do your operations with DummyActivity.instance >

Источник

Is there a better way to pass context to a helper kotlin class?

Map contains google map methods and DataWriter contains File writer methods as long with a write storage permission check on runtime IsWriteEnabled().

I call IsWriteEnabled() from Map so I can check If I have permissions with the following way:

class Map : Fragment() , OnMapReadyCallback < private lateinit var mdataWriter: DataWriter // a lot of code removed override fun onMapReady(googleMap: GoogleMap)
class DataWriter(val context: Context): AppCompatActivity() < fun isWriteEnable(): Boolean < if (ActivityCompat.checkSelfPermission( context, Manifest.permission.WRITE_EXTERNAL_STORAGE ) != PackageManager.PERMISSION_GRANTED ) < ActivityCompat.requestPermissions( context as Activity, arrayOf( Manifest.permission.WRITE_EXTERNAL_STORAGE ), WRITE_REQUEST_CODE ) >else < Log.e("DB", "PERMISSION GRANTED") >return true > 

My question

Is there a better way to pass context to a class that its not attached to main activity? Is the call to the method as it should be?

Why is DataWriter extending AppCompatActivity ? Just to request permissions? You shouldn't do this. If it's not an Activity, you should not extend any Activity kind of class. Just ask for the permission either in Map or MainActivity .

@RicardoCosteira inside there some more methods to write csv and start stop logging. Shouldnt do that?

Do whatever you want with the class, just don't extend an Android component if it's not supposed to do the job of that component. You're adding a lot of complexity to the class with no need whatsoever.

I am trying to split the methods to different classes so the code lines dont become increase too much. is it a wrong approach?

Splitting methods is good, as long as the methods are in classes that should be responsible for them. By extending AppCompatActivity , you're already inheriting a bunch of methods that have nothing to do with DataWriter . In this case, you're ask for the permission through something called ActivityCompat. In other words, you're only supposed to use ActivityCompat in something that is supposed to be able to used it, like an Activity or Fragment (as components that handle user interaction, asking for permissions is actually a responsibility of the Activity or Fragment ).

1 Answer 1

You are free to pass a Context to a class that its not attached to an Activity in any way you like. Passing it through the class's constructor is a good practice (dependency injection), but only in the case where your class needs a Context to fully function correctly. If you need a Context to use only in a specific method, might as well pass it as an argument to the method.

The most important thing you have to be aware here is that an Activity has a finite life cycle. If you keep a reference to an Activity Context in a class that will outlive that Activity , you will create a memory leak: the garbage collector will not be able to destroy that Activity because there's a reference to it somewhere. This is why people usually prefer to handle an Application Context instead, which will always outlive any class you can create.

Now, a correction to your code: don't extend AppCompatActivity just to inherit ActivityCompat . By extending AppCompatActivity , you're granting the class access to a lot of life cycle management, resource handling and user interaction methods that have nothing to do with your class. AppCompatActivity is supposed to be extended by Activities only. Otherwise, its name would not end with Activity 🙂

As components that handle user interaction, asking for permissions is a responsibility of the Activity or Fragment , so just ask for the permission either in Map or MainActivity . Also, I'm assuming that Map is indeed doing what a Fragment is supposed to do, and you're not just extending Fragment to get access to some Fragment methods 🙂

Источник

Читайте также:  Wait keyboard input python
Оцените статью