I’m trying to call a method in my main Activity from another file, but it crashes. I can easily do this the other way. Can you not invoke methods of the main Activity from another Activity?
public class MainActivity extends Activity {
….
……..
……
public void my_function(String a){
//do some stuff
}
}
package main;
public class stuff extends Activity {
….
….
…
MainActivity run = new MainActivity();
run.my_function(String a);
}
}
If you want a method to get called from different classes, create a seperate class
and encapsulate the logic. See an activity more as a view controller, the logic
should be somewhere else.
Sorry for my english, hope this helps.
Steve
The problem is this line
MainActivity run = new MainActivity();
you never instantiate Activities directly, you need to instantiate them through Intent objects.
Intent intent = new Intent(this, MainActivity.class);
If you want to instantiate a new activity use an Intent. If you want to call my_function in an activity that is already instantiated, you need first to get a pointer to that Activity, which in Android is a little bit tricky.
Additionally, the fact that you want to call a method from another activity is a sign of bad design, or that you don't fully understand the Android way of doing things.
Think if there's any other approach you can use for your purpose.
Related
This question is mostly to solicit opinions on the best way to handle my app. I have three fragments being handled by one activity. Fragment A has one clickable element the photo and Fragment B has 4 clickable elements the buttons. The other fragment just displays details when the photo is clicked. I am using ActionBarSherlock.
The forward and back buttons need to change the photo to the next or previous poses, respectively. I could keep the photo and the buttons in the same fragment, but wanted to keep them separate in case I wanted to rearrange them in a tablet.
I need some advice - should I combine Fragments A and B? If not, I will need to figure out how to implement an interface for 3 clickable items.
I considered using Roboguice, but I am already extending using SherlockFragmentActivity so that's a no go. I saw mention of Otto, but I didn't see good tutorials on how to include in a project. What do you think best design practice should be?
I also need help figuring out how to communicate between a fragment and an activity. I'd like to keep some data "global" in the application, like the pose id. Is there some example code I can see besides the stock android developer's information? That is not all that helpful.
BTW, I'm already storing all the information about each pose in a SQLite database. That's the easy part.
The easiest way to communicate between your activity and fragments is using interfaces. The idea is basically to define an interface inside a given fragment A and let the activity implement that interface.
Once it has implemented that interface, you could do anything you want in the method it overrides.
The other important part of the interface is that you have to call the abstract method from your fragment and remember to cast it to your activity. It should catch a ClassCastException if not done correctly.
There is a good tutorial on Simple Developer Blog on how to do exactly this kind of thing.
I hope this was helpful to you!
The suggested method for communicating between fragments is to use callbacks\listeners that are managed by your main Activity.
I think the code on this page is pretty clear:
http://developer.android.com/training/basics/fragments/communicating.html
You can also reference the IO 2012 Schedule app, which is designed to be a de-facto reference app. It can be found here:
http://code.google.com/p/iosched/
Also, here is a SO question with good info:
How to pass data between fragments
It is implemented by a Callback interface:
First of all, we have to make an interface:
public interface UpdateFrag {
void updatefrag();
}
In the Activity do the following code:
UpdateFrag updatfrag ;
public void updateApi(UpdateFrag listener) {
updatfrag = listener;
}
from the event from where the callback has to fire in the Activity:
updatfrag.updatefrag();
In the Fragment implement the interface in CreateView do the
following code:
((Home)getActivity()).updateApi(new UpdateFrag() {
#Override
public void updatefrag() {
.....your stuff......
}
});
To communicate between an Activity and Fragments, there are several options, but after lots of reading and many experiences, I found out that it could be resumed this way:
Activity wants to communicate with child Fragment => Simply write public methods in your Fragment class, and let the Activity call them
Fragment wants to communicate with the parent Activity => This requires a bit more of work, as the official Android link https://developer.android.com/training/basics/fragments/communicating suggests, it would be a great idea to define an interface that will be implemented by the Activity, and which will establish a contract for any Activity that wants to communicate with that Fragment. For example, if you have FragmentA, which wants to communicate with any activity that includes it, then define the FragmentAInterface which will define what method can the FragmentA call for the activities that decide to use it.
A Fragment wants to communicate with other Fragment => This is the case where you get the most 'complicated' situation. Since you could potentially need to pass data from FragmentA to FragmentB and viceversa, that could lead us to defining 2 interfaces, FragmentAInterface which will be implemented by FragmentB and FragmentAInterface which will be implemented by FragmentA. That will start making things messy. And imagine if you have a few more Fragments on place, and even the parent activity wants to communicate with them. Well, this case is a perfect moment to establish a shared ViewModel for the activity and it's fragments. More info here https://developer.android.com/topic/libraries/architecture/viewmodel . Basically, you need to define a SharedViewModel class, that has all the data you want to share between the activity and the fragments that will be in need of communicating data among them.
The ViewModel case, makes things pretty simpler at the end, since you don't have to add extra logic that makes things dirty in the code and messy. Plus it will allow you to separate the gathering (through calls to an SQLite Database or an API) of data from the Controller (activities and fragments).
I made a annotation library that can do the cast for you. check this out.
https://github.com/zeroarst/callbackfragment/
#CallbackFragment
public class MyFragment extends Fragment {
#Callback
interface FragmentCallback {
void onClickButton(MyFragment fragment);
}
private FragmentCallback mCallback;
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt1
mCallback.onClickButton(this);
break;
case R.id.bt2
// Because we give mandatory = false so this might be null if not implemented by the host.
if (mCallbackNotForce != null)
mCallbackNotForce.onClickButton(this);
break;
}
}
}
It then generates a subclass of your fragment. And just add it to FragmentManager.
public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager().beginTransaction()
.add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), "MY_FRAGM")
.commit();
}
Toast mToast;
#Override
public void onClickButton(MyFragment fragment) {
if (mToast != null)
mToast.cancel();
mToast = Toast.makeText(this, "Callback from " + fragment.getTag(), Toast.LENGTH_SHORT);
mToast.show();
}
}
Google Recommended Method
If you take a look at this page you can see that Google suggests you use the ViewModel to share data between Fragment and Activity.
Add this dependency:
implementation "androidx.activity:activity-ktx:$activity_version"
First, define the ViewModel you are going to use to pass data.
class ItemViewModel : ViewModel() {
private val mutableSelectedItem = MutableLiveData<Item>()
val selectedItem: LiveData<Item> get() = mutableSelectedItem
fun selectItem(item: Item) {
mutableSelectedItem.value = item
}
}
Second, instantiate the ViewModel inside the Activity.
class MainActivity : AppCompatActivity() {
// Using the viewModels() Kotlin property delegate from the activity-ktx
// artifact to retrieve the ViewModel in the activity scope
private val viewModel: ItemViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.selectedItem.observe(this, Observer { item ->
// Perform an action with the latest item data
})
}
}
Third, instantiate the ViewModel inside the Fragment.
class ListFragment : Fragment() {
// Using the activityViewModels() Kotlin property delegate from the
// fragment-ktx artifact to retrieve the ViewModel in the activity scope
private val viewModel: ItemViewModel by activityViewModels()
// Called when the item is clicked
fun onItemClicked(item: Item) {
// Set a new item
viewModel.selectItem(item)
}
}
You can now edit this code creating new observers or settings methods.
There are severals ways to communicate between activities, fragments, services etc. The obvious one is to communicate using interfaces. However, it is not a productive way to communicate. You have to implement the listeners etc.
My suggestion is to use an event bus. Event bus is a publish/subscribe pattern implementation.
You can subscribe to events in your activity and then you can post that events in your fragments etc.
Here on my blog post you can find more detail about this pattern and also an example project to show the usage.
I'm not sure I really understood what you want to do, but the suggested way to communicate between fragments is to use callbacks with the Activity, never directly between fragments. See here http://developer.android.com/training/basics/fragments/communicating.html
You can create declare a public interface with a function declaration in the fragment and implement the interface in the activity. Then you can call the function from the fragment.
I am using Intents to communicate actions back to the main activity. The main activity is listening to these by overriding onNewIntent(Intent intent). The main activity translates these actions to the corresponding fragments for example.
So you can do something like this:
public class MainActivity extends Activity {
public static final String INTENT_ACTION_SHOW_FOO = "show_foo";
public static final String INTENT_ACTION_SHOW_BAR = "show_bar";
#Override
protected void onNewIntent(Intent intent) {
routeIntent(intent);
}
private void routeIntent(Intent intent) {
String action = intent.getAction();
if (action != null) {
switch (action) {
case INTENT_ACTION_SHOW_FOO:
// for example show the corresponding fragment
loadFragment(FooFragment);
break;
case INTENT_ACTION_SHOW_BAR:
loadFragment(BarFragment);
break;
}
}
}
Then inside any fragment to show the foo fragment:
Intent intent = new Intent(context, MainActivity.class);
intent.setAction(INTENT_ACTION_SHOW_FOO);
// Prevent activity to be re-instantiated if it is already running.
// Instead, the onNewEvent() is triggered
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
getContext().startActivity(intent);
There is the latest techniques to communicate fragment to activity without any interface follow the steps
Step 1- Add the dependency in gradle
implementation 'androidx.fragment:fragment:1.3.0-rc01'
I have created a class that is extending from CountDownTimer, It has a a method onFinish() which calls when timer expires.
There are 6 Activities, user can be in any activity when timer expires, So in CounterTimerwhen Finish() method calls , i need to show an Alert Message to the user,along with i need to redirect user to Login page.
Things getting confusing, as i cannot call Intent class in the Normal Class, I can also not pass the context, as user can be in any activity.
I have written following code, but its not helping out.
I am using context here, but its giving error message on passing context to Intent
public class CounterClass extends CountDownTimer implements ITMServiceEvent {
#Override
public void onFinish() {
if(sql_code.equalsIgnoreCase("0")) {
String resultCode = command1.getString("result");
context.startActivity(context.getApplicationContext(), MainActivity.class);
}
Calling Timer at the Start of Wizard, in a Fragment
CounterClass counterClass= new CounterClass(180000,1000);
counterClass.setTextView(tvTimer);
counterClass.start();
There are two parts of your question, first is how you can clean up the Activity stack and start a new Activity on Top of them, I suppose this would be the LoginActivity in your case.
To do this, you need to set the Flag of your LoginActivity Intent when you want to start it,
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
And the second part is, you want to be able to finish the current activity after showing a dialog to the user. I assume your Timer is a Service Class, which runs in the background. The way to tell your current activity that the Time is Up ! is to send a Broadcast Message. Preferably, LocalBroadcastManager can help you out. You can have a BaseActivity class where all of your 6 Activities can be extended from it and you can register/unregister LocalBroadcastManager to/from those activities in the BaseActivity class (register in onResume and unregister in onPause). After you register them you just need to implement and handle the onReceive method where you can show a dialog and start the LoginActivity after finishing the current one.
I'm just rtying to display an offerwall when someone is leaving the application, so I have placed the finish() method:
#Override
public void finish() {
super.finish();
MobileCore.init(this.getContext(), "xxx", MobileCore.LOG_TYPE.DEBUG, MobileCore.AD_UNITS.OFFERWALL);
MobileCore.setStickeezReadyListener(new OnReadyListener() {
#Override
public void onReady(MobileCore.AD_UNITS adUnit) {
if (adUnit == MobileCore.AD_UNITS.OFERWALL) {
MobileCore.showOferWall(getActivity());
}
}
});
}
But I have problems. First of all with this code this.getContext() and also with this getActivity()
I know that I can not access the activity this way, but I'm extremely confused at the moment. I know that I'm missing a very small part here. Can you give me a push?
Activity class extends Context so actually Activity is instance of Context, in onFinish the system is trying to destroy the Activity so there must be no jobs still working related to this Activity, if you still need a Context you can use this.getApplicationContext.
To call the outer class in a nested class (in your case an anonymous class) use the class name of the outer one:
YourOuterClass.this
Your activity's context will remain valid until you call super.finish(). So don't call it until you're done.
If you can't do that, use the application context.
I'm using Parse with my Android app, and my code looks like this:
public class SignupActivity extends Activity {
//Collect signup data
User.signupInBackground(data);
}
public class User{
//User methods, constructors, etc
public static void signup(data){
ParseUser pUser = new ParseUser();
//Build data into pUser
pUser.signUpInBackground(new SignUpCallback() {
public void done(ParseException e){
if (e!=null){
Log.v("Signup",e.toString());
}
}
});
So the question is, how do I notify my activity when the signUpInBackground process is complete? I can't have SignupActivity implement SignUpCallback because it's an abstract class and I have to extend Activity.
Ultimately, what I'm trying to do is display a dialog box or waiting animation, and then get rid of it when the background thread is done. Alternatively, the background thread could launch an activity. The problem with this is that the User class and the anonymous inner class don't have their own Context, so they can't start activities.
I'm fairly new at this, so thanks for your help.
Several approaches might work given your current code structure.
Create a Handler in SignupActivity and pass that to the User so it has a way of interacting with the activity.
Make SignUpCallback an interface instead of an abstract class.
Create an instance of a concreate subclass of SignUpCallback in your SignupActivity class; it will have access to the methods of SignupActivity.
I'm assuming that signUpInBackground is executing on a worker thread and that the callback is invoked from that thread. If that's correct, then in all cases you will need to interact with SignupActivity through a Handler. Thus, I'd suggest method #1 unless the other approaches allow for cleaner code.
I have 2 activities.
I start one, and at a point I start another one:
Intent enabler = new Intent(this, cprompt.class);
startActivity(enabler);
I want to call a method from the old one, but I want to pass some data too.
This is how I tried:
Activity1.sendcommand(DATA);
And I got this:
Cannot make a static reference to the non-static method sendcommand(String) from the type Activity1
And I don't want change the method to static.
The only way if I make a Listener? If I have to, you can describe for me to how?
The java is new for me... :/ But if this problem is solved I think I am done with my program :)
Only one Activity is active at a time. Are you trying to trigger the method just because you want to pass some data?.You can do it via an Intent
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("YOUR_DATA_KEY", "Data Value");
startActivity(intent);
and in the SecondActivity , you can retrieve the data and process it
String data = getIntent().getStringExtra("YOUR_DATA_KEY");
It's not just Strings that you can send this way.You can even transmit Serializable and Parcelable Extras. For more information refer - Intents on Android Developer Website
You can declare an interface and make Activity1 implements that interface..
Then when you need to call Activity1's method call the inetrface's method...
Your interface:
public interface OnSendCommand{
public void onSendCommand(values);
}
Activity1:
public Activity1 implements OnSendCommand {
public void onSendCommand(values){}
}
Are you returning to the first activity from the second when executing this method? If so you could use startActivityForResult() following this tutorial. If not, then something is wrong with the structure of your application if this method can not be static, and this method should be in a separate class not inheriting from Activity.