Hi I am kind of new to android, still learning. And my problem is that, for example I have a method which was created in the MainActivity and I need to call it from another class.
Is it a good practice to get the instance of the MainActivity so that I may be able to call the method in the MainActivity from another class?
This is an example:
public class MainActivity extends AppCompatActivity {
private static MainActivity inst;
public static MainActivity instances()
{
return inst;
}
#Override
public void onStart() {
super.onStart();
inst = this;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void showToast (String text){
Toast.makeText(inst, text, Toast.LENGTH_SHORT).show();
}
Then this is the other class:
public class broadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
MainActivity instance = new MainActivity();
instance.showToast(AnyText);
}
}
I saw this type of coding while looking at tutorials and wondered if it's a good practice or maybe there might be a better way? Since I get the warning of Do not place Android Context Classes in static classes
Thanks in advance for any insight or help! :D
I guess You want to make A singleton of Activity Class
but as Mention in All Pattern Design
using Singleton
If and Only If its only way to Make A Global Variable
Singleton is based on Lazing Initialing and Load On Memory
so I guess If you cant to Interact With Activiy You can Use
BroadCast Or Intents
You can call method from another class like this:
MainActivity instance = new MainActivity();
String data = instance.data();
and create data method in that class:
public String data() {
return mangaId;
}
Is it a good practice to get the instance of the MainActivity so that
I may be able to call the method in the MainActivity from another
class?
You totally can do this but you don't need to make it static and use a constructor. Just create a new instance like follows and you'll access the public methods
MainActivity mainActivity = new MainActivity();
mainActivity.showToast(text);
About the warning
It suggests avoiding having context fields defined as static. The warning itself explains why: It's a memory leak. If you make it static it will be accessible anywhere in your app and some methods can hold the reference to this context for a really long time and it won't be garbage collected. It will lead to a outofmemory exception and the app could crash. But here you're trying to invoke showToast() from broadcastreceiver so you can just get rid of static references. And it you need them in the future you safe ways to inject context
You cannot create instances of an Activity using the new operator.
You have to use an Intent to let an Activity to be created.
So you cannot get a reference to an instance of your activity.
The only methods you can use of your activity class are static ones.
I often find myself needing to access methods that require referencing some activity. For example, to use getWindowManager, I need to access some Activity. But often my code for using these methods is in some other class that has no reference to an activity. Up until now, I've either stored a reference to the main activity or passed the context of some activity to the class. Is there some better way to do this?
If you already have a valid context, just use this:
Activity activity = (Activity) context;
Passing context is better way for refrence Activity.
You can pass Context to another class.
IN Activity ::
AnotherClass Obj = new AnotherClass(this);
IN Another Class
class AnotherClass{
public AnotherClass(Context Context){
}
}
You can implement the necessary methods in your activity and implement a Handler. Then, simply pass a handler instance to your classes, where you can obtain a message for handler and send it to target.
You can make you application instance a singleton, and use it when you need a Context
An example is in this question:
Android Application as Singleton
This way, when you need a Context, you can get it with
Context context = MyApplication.getInstance()
This might not be the cleanest solution, but it has worked well for me so far
I found a way to get the Activity to a non-activity class that I have not seen discussed in forums. This was after numerous failed attempts at using getApplicationContext() and of passing the context in as a parameter to constructors, none of which gave Activity. I saw that my adapters were casting the incoming context to Activity so I made the same cast to my non-activity class constructors:
public class HandleDropdown extends Application{
...
public Activity activity;
...
public HandleDropdown() {
super();
}
public HandleDropdown(Activity context) {
this.activity = context;
this.context = context;
}
public void DropList(View v,Activity context) {
this.activity = context;
this.context = context;
...
}
After doing this cast conversion of Context to Activity I could use this.activity wherever I needed an Activity context.
I'm new to android so my suggestion may look guffy but what if you'll just create a reference to your activity as private property and assign that in OnCreate method? You can even create your CustomActivity with OnCreate like that and derive all your activities from your CustomActivity, not the generic Activity provided by android.
class blah extends Activity{
private Activity activityReference;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityReference = this;
}
}
after that you could use that the way you want, i.e. in
Intent i = new Intent(activityReference, SomeOtherActivity.class)
etc
There are many ways for Activities communication.
you can use:
the startActivityForResult method
a system of broadcast message and receiver (you can broadcast an event from the actual activity, and register a receiver in the target activity. Remember that the target activity must be previously initialized and non finished)
as you say, store a reference of the target activity wherever you need.
We built a framework for this. We have a BaseActivity class that inherits from Activity and it overrides all the lifecycle methods and has some static (class) variables that keep track of the activity stack. If anything wants to know what the current activity is, it just calls a static method in BaseActivity that returns the activity on top of our privately-managed stack.
It is kinda hacky, but it works. I'm not sure I would recommend it though.
Handle the Intent in the class you want to do these methods, and send your information to it in a Bundle like so:
Intent i = new Intent("android.intent.action.MAIN");
i.setComponent(new ComponentName("com.my.pkg","com.my.pkg.myActivity"));
Bundle data = new Bundle();
i.putExtras(data);
startActivityForResult(i);
Then use an OnActivityResultListener to grab the new data.
I solved this by making a singleton class has an instance of the class below as a member.
public class InterActivityReferrer <T> {
HashMap<Integer, T> map;
ArrayList<Integer> reserve;
public InterActivityReferrer() {
map = new HashMap<>();
reserve = new ArrayList<>();
}
public synchronized int attach(T obj) {
int id;
if (reserve.isEmpty()) {
id = reserve.size();
}
else {
id = reserve.remove(reserve.size() - 1);
}
map.put(id, obj);
return id;
}
public synchronized T get(int id) {
return map.get(id);
}
public synchronized T detach(int id) {
T obj = map.remove(id);
if (obj != null) reserve.add(id);
return obj;
}
}
This class can get a T object and return a unique integer assigned to the object by attach(). Assigned integers will not collide with each other unless HashMap fails. Each assigned integer will be freed when its corresponding object is detached by detach(). Freed integers will be reused when a new object is attached.
And from a singleton class:
public class SomeSingleton {
...
private InterActivityReferrer<Activity> referrer = new InterActivityReferrer<>();
...
public InterActivityReferrer<Activity> getReferrer() {return referrer;}
}
And from an activity that needs to be referred:
...
int activityID = SomeSingleton.getInstance().getReferrer().attach(this);
...
Now with this, a unique integer corresponding to this activity instance is returned. And an integer can be delivered into another starting activity by using Intent and putExtra().
...
Intent i = new Intent(this, AnotherActivity.class);
i.putExtra("thisActivityID", activityID);
startActivityForResult(i, SOME_INTEGER);
...
And from the another activity:
...
id refereeID = getIntent().getIntExtra("thisActivityID", -1);
Activity referredActivity = SomeSingleton.getInstance().getReferrer().get(refereeID);
...
And finally the activity can be referred. And InterActivityReferrer can be used for any other class.
I hope this helps.
public static Activity getLaunchActivity()
{
final Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
final Method methodApp = activityThreadClass.getMethod("currentApplication");
App = (Application) methodApp.invoke(null, (Object[]) null);
Intent launcherIntent = App.getPackageManager().getLaunchIntentForPackage(App.getPackageName());
launchActivityInfo = launcherIntent.resolveActivityInfo(App.getPackageManager(), 0);
Class<?> clazz;
try
{
clazz = Class.forName(launchActivityInfo.name);
if(clazz != null)
return Activity.class.cast(clazz.newInstance());
}
catch (Exception e)
{}
return null;
}
Just a guess since I haven't done this but it might work.
1) Get your applicationContext by making your Android Application class a Singleton.
2) Get your ActivityManager class from the context.
3) Get a list of RunningTaskInfos using getRunningTasks() on the ActivityManager.
4) Get the first RunningTaskInfo element from the list which should be the most recent task launched.
5) Call topActivity on that RunningTaskInfo which should return you the top activity on the activity stack for that task.
Now, this seems like a LOT more work than any of the other methods mentioned here, but you can probably encapsulate this in a static class and just call it whenever. It seems like it might be the only way to get the top activity on the stack without adding references to the activities.
I know that stuff of calling the new activity and pass the object value from one activity to another by using putExtra and getExtra function. but i want to pass the value without calling and start the new activity. Is it possible ?
If yes then let me know how i can do it ?
You can also use the Application class for declaring global variables
class Globalclass extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}
class TempActivity extends Activity {
#Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}
UPDATED :
Checkout this nice Tutorial about how to do that.
Application Class Using as Global
for this you can use static variable or SharedPreferences or if you heavy data then you can use SQlite.
You can take the help of database like SQLite or you may go for Constant class concept where you can make a public static variable and store your data in one activity and access in other activity.Hope this will help you.
There're a lot of ways to pass a value to an activity:
You can use an Intent with FLAG_ACTIVITY_REORDER_TO_FRONT. In this case onNewIntent() method will be called for already started activity.
You can use static fields or static methods to pass new data to your activity. But it's not a good method really because sometimes application is terminated even if it's foreground and all static data is lost.
You can send new data to an activity using broadcast messages. In this case the activity must register a BroadcastReceiver.
I think it's not very difficult to make up a few more ways to pass arguments.
You may want to use handler's handleMessage() and pass the object in a message .
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
}
};
You can then call handler.handleMessage(msg), you can assign any object to msg.onj
According to what i have learnt from passing data using Intents is that when you pass Object O from Activity A to Activity B via intents, activity B receives a COPY of object O. The way things work is that The object O gets serialized (converted to a sequence of bytes) and that sequence of bytes is then passed to Activity B. Then activity B recreates a copy of object O at the moment it was serialized.
I would like to know if it would be efficient if one extends the Intent class to create a custom Intent and have references to the objects that are required by the other activities and pass the data to the other activities. For example:
public class CustomIntent extends Intent {
private Object o;
public CustomIntent() {
super();
// TODO Auto-generated constructor stub
}
public Object getObject () {
return o;
}
public void setObject(Object object) {
this.o = object;
}
}
In the receiving activity i get the intent and cast the intent to the CustomIntent type and retrieve the object required by the activity. Would this improve the efficiency by reducing the need for Serialization? Kindly throw some light on this. Thanks in advance.
No. Intents are dispatched by the Android system and are always serialized as they can be sent to any activity, service, etc in the system.
For your problem you could probably workaround this issue by creating an Application class and storing your data in it:
class CustomApplication extends Application {
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
You activate it by updating AndroindManifest.xml setting the android:name property on the application tag you your class name.
To use in your activities:
CustomApplication app = (CustomApplication) getApplicationContext();
app.setData(yourDataObject);
I think it would be better if you let the android handle everything for you. Do not customize it, if it is not very essential.
If you want to have the reference of the object in another activity then there are other ways too.
You can make your object static and directly access it from other activity.
You can make a new object of same type and replace it after coming again back to the first activity(in onActivitResult() method.).
or there may be many more ways to do it.
Thanks.
I have Main class and it contains function isSyncAllowed. I start another service. How to call function isSyncAllowed from this service?
It says:
Cannot make a static reference to the
non-static method
isSyncAllowed(Boolean) from the type
Main
If I change type of that function to static and pass context, I come to the problem that startManagingCursor can not be static.
How can I fix it?
Upd. Here is the code of SyncService:
public class SyncService extends BroadcastReceiver {
...
public void onReceive(Context context, Intent intent) {
...
Boolean isDownloadAllowed = Kinobaza.isSyncAllowed(true);
}
and here is the code of Main:
public class Kinobaza extends ListActivity {
...
public static Boolean isSyncAllowed(Boolean showToasts) {
...
Cursor notesCursor = mDbHelper.fetchAllNotes();
startManagingCursor(notesCursor); // here is the error
}
}
You are probably doing Main.isSyncAllowed(...) instead of main.isSyncAllowed(...), where main is an object of class Main.
If you are inside an instance method of Main, then you can simply do isSyncAllowed(...).
Edit - now that I see your code, you should probably pass isSyncAllowed via the Intent you give to the service. When you start the service:
Intent intent = /* however you were constructing your intent */
boolean syncAllowed = /* calculate syncAllowed by calling your existing method */
intent.putExtra("syncAllowed", syncAllowed);
...
and then in your service you can retrieve it:
boolean syncAllowed = getIntent().getBooleanExtra("syncAllowed", true);
Your service shouldn't need to call instance methods on your activities.