Access parent activity's method from dialog - android

My project have a activity named MainActivity and a BrowserActivity extend dialog service.
MainActivity will intent BrowserActivity on application started.
I would like to BrowserActivity can access MainActivity's public method.
something like that:
Method on MainActivity:
public void chooseShare(Intent intent)
{
try
{
startActivityForResult( intent , PICK_SHARE);
} catch (android.content.ActivityNotFoundException ex)
{
Log.e("Share" , ex.getMessage());
}
}
And i want to do on BrowserActivity :
(Pseudocode)
((MainActivity)BrowserActivity.this.getOwnerActivity()).chooseShare(intent);
I try to do that:
MainActivity ma = new MainActivity();
ma.chooseShare(i);
However, it not work, it throw NULLPointerException.
Because i need startActivityForResult() instead of startActivity() for callback result.
And i digg on SOF, i found startActivityForResult() should be start on Activity, but not Dialog.
thanks you.

You should be able to use getParent() if it's within the same project.
Activity parent = getParent();
if (parent instanceof MainActivity)
((MainActivity)parent).chooseShare(i);
Another option would be to bind it with an ibinder and use a service or implement interfaces.
Services | Android Developers

you can access all classes method like this:
Context context;
public ProceedDialog(#NonNull Context context) {
super(context);
this.context = context;
//do something
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//do something
}
#Override
public void onClick(View view) {
ParentActivity activity = (ParentActivity)context;
activity.method();
}

I had the same question. And I found a partial solution.
The key is that Activity is a subclass of Context.
You pass the Context paraneter to the constructor of your dialog, right?
And most people pass it by using this of MainActivity.
So, I used the following codes to get MainActivity reference.
private MainActivity getMainActivity()
{
Context c= getContext();
if( c instanceof MainActivity)
{
return (MainActivity)c;
}
return null;
}
Then you can call the desired method by
this.getMainActivity().chooseShare(intent);
In the dialog.
I tested this and it works!
Hope it helped you or forecomers.
(I saw the last modification date just now)

Related

Calling getOwnerActivity() method always return null

I have created a simple custom dialog class. In further code I want to run new Intent:
Intent intent = new Intent(android.content.Intent.ACTION_VIEW,
Uri.parse("http://maps.google.com/maps?saddr=20.344,34.34&daddr=20.5666,45.345"));
startActivity(intent);
But the problem is whenever I call to change into that Intent I always get null in getOwnerActivity() - how to properly call that method?
public class AddToQueueDialog extends Dialog implements View.OnClickListener {
Activity mActivity;
private final String android_id = Settings.Secure.getString(getContext().getContentResolver(),
Settings.Secure.ANDROID_ID);
public Activity getmActivity() {
return mActivity;
}
public void setmActivity(Activity mActivity) {
this.mActivity = mActivity;
}
public AddToQueueDialog(Context context, WashLocation washLocation) {
super(context);
setWashLocation(washLocation);
setmActivity(getOwnerActivity());
}
If you will check the source code and the activity it returns is set only in setOwnerActivity(Activity activity) which is not called anywhere. So if you want getOwnerActivity() to return value different than null, you have to change your constructor like following
public AddToQueueDialog(Context context, WashLocation washLocation) {
super(context);
if (context instanceof Activity) {
setOwnerActivity((Activity) context);
}
setWashLocation(washLocation);
setmActivity(getOwnerActivity());
}
You cant call the getOwnerActivity() in Oncreate
If you try to get owner from the constructor, Android hasn't hooked it yet, so you have no owner yet.
try this instead
public void onAttachedToWindow() {
super.onAttachedToWindow();
// getOwnerActivity() should be defined here if called via showDialog(), so do the related init here
Activity owner = getOwnerActivity();
if (owner != null) {
// owner activity defined here
}
}
context is the owning Activity. Your constructor is called with context. This is the owning Activity.

How to know that activity parameter belongs to which Activity

Suppose I have a class A and contains a method which needs and activity and an int as parameters:
class A {
public void performActions(Activity activity, int a){
.....}
}
Now the following activities are accessing method performActions() in class A:
class B extends Activity{
public void aMethod(){
new class A().performActions(B.this, 1);
}
}
class C extends Activity{
public void aMethod(){
new class A().performActions(C.this, 2);
}
}
The question is:
Is there a way that performActions() method in class A know that the activity parameter came from which activity and get back to that activity when it done its actions?
you can keep a check like this
public void performActions(Activity activity, int a){
if(activity instanceOf B){
//came from B
}
if(activity instanceOf C){
//came from C
}
}
I'm not exactly sure what you are meaning.
However,
I would think that you may want to provide a method that B,C overrides from Activity class, that returns which class it is (B or C).
Otherwise consider adding names to activities through some method in Activity.
You don't provide much information about the use case of this code, so it is difficult to answer.
You can use instanceOf to know that context belong to which activity.
Here is the below code for the same
if (context instanceof ActivityA) {
} else {
if (context instanceof ActivityB) {
}
}

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);
}
}
As you can see above, I am instantiating the profileView programatically and passing in the activityContext with it. 2 questions:
Am i passing the correct context into the Profileview?
How do I get the containing activity from the context?
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;
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;
}
No
You can't
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?
When you use
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).
Regards.
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
}
And in Kotlin:
tailrec fun Context.activity(): Activity? = when {
this is Activity -> this
else -> (this as? ContextWrapper)?.baseContext?.activity()
}
If you like to call an activity method from within a custom layout class(non-Activity Class).You should create a delegate using interface.
It is untested and i coded it right . but i am conveying a way to achieve what you want.
First of all create and Interface
interface TaskCompleteListener<T> {
public void onProfileClicked(T result);
}
public class ProfileView extends LinearLayout
{
private TaskCompleteListener<String> callback;
TextView profileTitleTextView;
ImageView profileScreenImageButton;
boolean isEmpty;
ProfileData data;
String name;
public ProfileView(Context context, AttributeSet attrs, String name, final ProfileData profileData)
{
super(context, attrs);
......
......
}
public setCallBack( TaskCompleteListener<String> cb)
{
this.callback = cb;
}
//Heres where things get complicated
public void onClick(View v)
{
callback.onProfileClicked("Pass your result or any type");
}
}
And implement this to any Activity.
and call it like
ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
pv.setCallBack(new TaskCompleteListener
{
public void onProfileClicked(String resultStringFromProfileView){}
});
Context may be an Application, a Service, an Activity, and more.
Normally the context of Views in an Activity is the Activity itself so you may think you can just cast this Context to Activity but actually you can't always do it, because the context can also be a ContextThemeWrapper in this case.
ContextThemeWrapper is used heavily in the recent versions of AppCompat and Android (thanks to the android:theme attribute in layouts) so I would personally never perform this cast.
So short answer is: you can't reliably retrieve an Activity from a Context in a View. Pass the Activity to the view by calling a method on it which takes the Activity as parameter.
Never ever use getApplicationContext() with views.
It should always be activity's context, as the view is attached to activity. Also, you may have a custom theme set, and when using application's context, all theming will be lost. Read more about different versions of contexts here.
I used convert Activity
Activity activity = (Activity) context;
For kotlin user -
val activity = context as Activity
an Activity is a specialization of Context so, if you have a Context you already know which activity you intend to use and can simply cast a into c; where a is an Activity and c is a Context.
Activity a = (Activity) c;
This method should be helpful..!
public Activity getActivityByContext(Context context){
if(context == null){
return null;
}
else if((context instanceof ContextWrapper) && (context instanceof Activity)){
return (Activity) context;
}
else if(context instanceof ContextWrapper){
return getActivity(((ContextWrapper) context).getBaseContext());
}
return null;
}
I hope this helps.. Merry coding!
how about some live data callback,
class ProfileView{
private val _profileViewClicked = MutableLiveData<ProfileView>()
val profileViewClicked: LiveData<ProfileView> = _profileViewClicked
}
class ProfileActivity{
override fun onCreateView(...){
profileViewClicked.observe(viewLifecycleOwner, Observer {
activityMethod()
})
}
}
Create an extension function. And call this extension function with your context like context.getActivity().
fun Context.getActivity(): AppCompatActivity? {
var currentContext = this
while (currentContext is ContextWrapper) {
if (currentContext is AppCompatActivity) {
return currentContext
}
currentContext = currentContext.baseContext
}
return null
}
Kotlin android shorthand extension version of Theo's solution
private fun Context?.getParentActivity() : AppCompatActivity? = when {
this is ContextWrapper -> if (this is AppCompatActivity) this else this.baseContext.getParentActivity()
else -> null
}
Usage of above explained here

Cannot get context to launch intent

I've made a separate class to launch and intent as the class I would like to launch the intent from is a thread and does not inherit from activity and would not launch startActivity. Every time I launch the app I get a null pointer exception for the context.
public class ToLaunch extends Activity {
public void launchScoreloop() {
con.getApplicationContext();
startActivity(new Intent(this, LeaderboardsScreenActivity.class));
}
}
You Are writing an Activity , and you didn't override the method onCreate().
public class ToLaunch extends Activity {
#override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Call your method here after a button click cor example or something else
}
public void launchScoreloop() {
con.getApplicationContext();
startActivity(new Intent(this, LeaderboardsScreenActivity.class));
}
}
refer this two tutorials about using intents to start another Activity :
tuto 1
tuto 2
And if you want to launch the Activity from another Class , you should pass the context to the second Class like this :
SecondClass instance = new SecondClass(this);
and the contructor of your SecondClass will be something like this :
public void SecondClass(Context _context){
this.context = _context;
}
and then you can start the Avtivity by using the context that you passed to your SecondClass like this :
this.context.startActivity(....);
If thread is a inner class inside your activity you can use
startActivity(new Intent(YourActivity.this, LeaderboardsScreenActivity.class));
If it is a separate class you can make a constructor that take context has constructor as argument and you can pass your activity context into that constructor
Context con;
public YourThread(Context context){
con = context;
}
and from inside your activity, while making thread object
YourThread thread = new YourThread(this);

how to come back to my application after ACTION_CALL in android

I've got one question regarding the intent action ACTION_CALL.
What is the correct way of getting back to the own application/activity after the user ends the call?
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" +m1));
startActivity(intent);
I have made the call using the above code. Please provide me with a solution to call my own activity after the call action.
unfortunately some phones have settings to force going into for example the Call Log after a call...
However, you can run a loop after your startActivity to check TelephonyManager.getCallState, and when it's again TelephonyManager.CALL_STATE_IDLE, you can restart your own Activity
be sure to add some sleep to the loop
AFter the endofcall.......it just had to come back to the activity..!! you can handle that one onRestart();
I run with the same problem, and ended up solving it like this:
Make a Callback interface with single (or multiple if you want)
methods
Implement that interface in your activity
Make a reference to that interface inside PhoneStateListener class
Call a method within that interface when the call ended
public class CallTracker extends PhoneStateListener implements Runnable {
private Context mActivity;
private Callback mCallback;
public interface Callback {
void onCallEnded();
}
public CallTracker(Activity activity) {
super();
mActivity = activity;
if (mActivity instanceof Callback) {
mCallback = (Callback) mActivity;
}
}
#Override public void onCallStateChanged(int state, String incomingNumber) {
if (state == TelephonyManager.CALL_STATE_IDLE) {
mCallback.onCallEnded();
}
}
public class CallerActivity extends AppCompatActivity implements
CallTracker.Callback {
#Override public void onCallEnded() {
Toast.makeText(this, "Call ended!", Toast.LENGTH_SHORT).show();
}
}

Categories

Resources