I have an Activity in whose onCreate() method i call a Utility function.
This utility functions requires a callback class instance as a parameter, in which it returns the info that i need. this is:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Utility.functionA(new functionACallBack() {
/**
*
*/
private static final long serialVersionUID = -7896922737679366614L;
#Override
public void onResponse(String error) {
((MyActivity) AppClass.getAppContext()).finish();
}
});
}
Once I have obtained that info, I want to close the activity. so i called finish() from inside the anonymous class that i created for the callback.
But the activity is not getting finished. I thought maybe i need to call finish() from UI thread so i did runOnUiThread(), in inside it also i tried calling finish(). But it just doesn't work.
Could someone please help me with this issue?
UPDATE:
I am storing APP context and then trying to use that but to no avail.
public class AppClass extends Application {
private static Context mContext;
#Override
public void onCreate() {
super.onCreate();
AppClass.mContext = getApplicationContext();
}
public static Context getAppContext(){
return AppClass.mContext;
}
}
Simply call something like this:
#Override
public void onResponse(String error) {
((Activity) context).finish();
}
As this is a static function, you'll have to be able to access your Context in a static way. You can save that as a Class variable, but you'll have to be aware about its handling as it might lead to memory leaks.
To avoid them, you can declare a class that extends Application and save here your context, so this way you won't ever have a memory leak.
Try using this code:
((Activity) ActivityClass.this).finish();
Remember, use the Activity class, not the Application one.
Related
I have a question about memory leak.I have two classes.
The first one is:
public class Utility {
private static Utility instance = null;
private UpdateListener listener;
//Make it a Singleton class
private Utility(){}
public static Utility getInstance() {
if (instance == null)
instance = new Utility();
return instance;
}
public void setListener(UpdateListener listener) {
this.listener = listener;
}
//Long running background thread
public void startNewTread() {
new Thread (new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000 * 10);
if (listener != null)
listener.onUpdate();
} catch (InterruptedException e) {
Log.d("Utility", e.getMessage());
}
}
}).start();
}
//Listener interface
public interface UpdateListener {
public void onUpdate();
}
}
Thesecond class is:
public class ListenerLeak extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Setting the listener
Utility.getInstance().setListener(new Utility.UpdateListener() {
#Override
public void onUpdate() {
Log.d("ListenerLeak", "Something is updated!");
}
});
//Starting a background thread
Utility.getInstance().startNewTread();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
in this activity.May new Utility.UpdateListener create a memory leak?
when the activity destoroyed , only Updatelistener can be alive.does activity can be alive?
Create an inner class inside a Utility class like below. Then move the thread to that class.
public void startNewTread() {
new MyThread().start();
}
private static class MyThread extends Thread {
#Override
public void run() {
try {
Thread.sleep(1000 * 10);
if (listener != null)
listener.onUpdate();
} catch (InterruptedException e) {
Log.d("Utility", e.getMessage());
}
}
}
Reason: After each configuration change, the Android system creates a new Activity and leaves the old one behind to be garbage collected. However, the thread holds an implicit reference to the old Activity and prevents it from ever being reclaimed. As a result, each new Activity is leaked and all resources associated with them are never able to be reclaimed. https://www.androiddesignpatterns.com/2013/04/activitys-threads-memory-leaks.html will help to understand it.
This is probably a bit late, and others have had their input as well, but I'd like to have my shot as well :). Memory leak simply means that GC is not able to release a memory used by an instance of an object because it can't be sure that whether it is being used or not.
And in your case, simply put: The Utility class is defined as Singletone, It has a static instance of itself in the class. So It will be there as long as the application is alive. When you set a listener from the activity using setListener() function you are passing an instance created in the activity to it that has a limited lifecycle and is bound to activity's lifecycle. So one can say that the static Utility class can outlive the listener instance passed to utility and leak the activity. So no matter if you're using thread or not, This leaks the activity instance because it can outlive the listener instance which has an implicit reference to parent activity class.
How to prevent leaks here?
I think using a WeakReference for the listener is a good starting point, Also making sure to release or remove the listener as soon as the onDestroy() method of activity is called. but as documentations state, there's no guaranty that onDestroy() is always called. So in my opinion going with something like onPause() or onStop() is a better idea.
Sometimes, I have some headless fragments, which I need to run some initialization even before onCreate
For instance,
public class NetworkMonitorFragment extends Fragment {
public static NetworkMonitorFragment newInstance() {
return new NetworkMonitorFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
public void init() {
// This function shall be call even before onCreate.
}
}
NetworkMonitorFragment networkMonitorFragment = NetworkMonitorFragment.newInstance();
networkMonitorFragment.init();
I was wondering, is it a good practice, to have certain initialization inside Fragment constructor? Is there any drawback for doing so? The reason I'm asking, because I don't see many code example for doing so.
public class NetworkMonitorFragment extends Fragment {
public static NetworkMonitorFragment newInstance() {
return new NetworkMonitorFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
public NetworkMonitorFragment() {
init();
}
private void init() {
// This function shall be call even before onCreate.
}
}
NetworkMonitorFragment networkMonitorFragment = NetworkMonitorFragment.newInstance();
You certainly can, even other methods like Fragment.instantiate(Context context, String fname, Bundle args) calls newInstance() which calls default constructor. Although you must be aware of some things:
You should not do any stuff that is not independent of fragment's
state, lifecycle or Android's context
You should not do any stuff that takes up most of the 16ms UI
drawing window
You should not spawn new threads there
So while variable instantiation or some quick calculations based on external context, let's say, Date, for example, is perfectly fine, but decoding even a small bitmap either synchronously or asynchronously is a quick way to break things.
If execution and results of this function are not tied to fragment lifecycle and not dependent on parent activity then, I guess, it's just a matter of preference.
You can get more specific answers by describing what this function does.
If you want to do something before fragment created, do it in onAttach
(onAttach always calls before onCreate, look fragment lifecycle)
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
init();
...
}
If you want to sure view is created, do it in onViewCreated with same way.
I stuck at this issue many times and I passed the problem in different ways and I'm not sure that I made it in the right way.
I simplified the problem in a the following example. I know that I can pass only the data to the class but I do want to pass the editText cause I have this problem with more difficult UI controls.
mainactivity.java
public class mainactivity extends Activity {
public EditText clickEditText;
int count =0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
newTxt();
}
public void newTxt() {
txt = new MyText(context);
txt.updateTextEdit("Main Activity");
}
}
myText.java
public class MyText
{
private Context _context;
// constructor
public MyText(Context context)
{
_context = context;
}
public void updateTextEdit(String str)
{
private EditText strEditText;
strEditText= (EditText)findViewById(_context.R.id.editTextClick); // ????
strEditText.setText(str + " and myTxt");
}
}
if you could explain me how to fix the updateTextEdit function. i passed the context of the main activity. How can I change the editText? Thank you very much!!!
If you really want to do this this way, you need to save a reference to Activity, not Context. Like this:
public class MyText
{
private Activity _activity;
// constructor
public MyText(Activity activity)
{
_activity= activity;
}
public void updateTextEdit(String str)
{
private EditText strEditText;
strEditText= (EditText)activity.findViewById(R.id.editTextClick);
strEditText.setText(str + " and myTxt");
}
}
and in newTxt() you will need to change:
txt = new MyText(context);
to:
txt = new MyText(this);
But wouldn't it be easier to just put this method inside your activity? Why do you want it in another class? If it really needs to be in another class, you could make that class an inner class of your activity and you would still have access to the activity's methods and member variables.
There's a similar question here
How to access Activity UI from my class?
You didn't say how you obtained the context, you should use this and get the mainactivity in the other class. not context.
then you can call runOnUIThread to perform UI updates.
I am currently working on an android project and I have an activity, lets call it MyActivity and this activity calls a standard Java class called MyClass.
I need MyClass to finish the MyActivity activity but I can't find out how to do this. I thought I might be able to pass the context to the standard java class and call context.finish() but this doesn't appear to be available.
How can I do this, thanks for any help you can offer.
You can pass the Context, but you will need to cast it to an Activity (or simply pass the Activity itself), although this in general seems like a bad practice.
The most secure solution uses listener and a Handler. It is complex, but ensures a non direct call to finish activity.
Your listener:
interface OnWantToCloseListener{
public void onWantToClose();
}
Class that should close activity.
class MyClass {
private OnWantToCloseListener listener;
public void setWantToCloseListener(OnWantToCloseListener listener){
this.listener = listener;
}
private void fireOnWantToClose(){
if(this.listener != null)
listener.onWantToClose();
}
}
When you want to close your activity you must call fireOnWantToClose() method.
public MyActivity extends Activity{
public void onCreate(){
final int CLOSE = 1; //number to identify what happens
MyClass my_class = new MyClass();
final Handler handler = new Handler(){
public void handleMessage(Message msg){
if(msg.what == CLOSE)
MyActivity.this.finish();
}
});
my_class.setOnWantToCloseListener(new OnWantToCloseListener(){
public void onWantToClose(){
handler.sendEmptyMessage(CLOSE);
}
});
}
}
This is secure because Activity is not finished directly by MyClass object, it is finished through a listener that orders a handler to finish activity. Even if you run MyClass object on a second thread this code will works nice.
EDIT: CLOSE var added I forget to declare and initialize this.
Pass the MyActivity to MyClass as an Activity. From there you can call myActivity.finish();
For example:
private Activity myActivity;
public MyClass(Activity myActivity){
this.myActivity = myActivity;
}
public void stopMyActivity(){
myActivity.finish();
}
And in MyActivity:
MyClass myClass = new MyClass(this);
This is risky, because you're holding a reference to an Activity, which can cause memory leaks.
If your java class is a nested inner class, you can use:
public class MyActivity extends Activity {
public static class JavaClass {
public void finishActivity() {
MyActivity.finish();
}
}
}
Otherwise you'll have to pass the java class a Context (i.e. pass it a reference to this, since Activity extends Context) and store it as a private instance variable.
Actually i have created an singleton class. Now my singleton class extends Activity, and i have write onCreate() and onStart() method on this class. But it is never called.The code i have used is shown below. If anyone knows help me to solve these out.
Code
public class cycleManager
{
private static CycleManager m_cycleManagerObj;
private CycleManager()
{
// Initialise Variable
onInitialization();
readData(this); // show error when call from here
}
public static synchronized CycleManager getSingletonObject()
{
if (m_cycleManagerObj == null)
{
m_cycleManagerObj = new CycleManager();
}
return m_cycleManagerObj;
}
public Object clone() throws CloneNotSupportedException
{
throw new CloneNotSupportedException();
}
public void writeData(Context c)
{
SharedPreferences preferencesWrite = c.getSharedPreferences("myPreferences", 0);
SharedPreferences.Editor editor = preferencesWrite.edit();
// work to be done
}
public void readData(Context c)
{
SharedPreferences preferencesRead = c.getSharedPreferences("myPreferences", 0);
// work to be done
}
}
The thing is Android manages activities in its own manner: from calling a constructor to calling all lifecycle methods. So if you declare your Activity's constructor as private then Android will not be able to manage this activity.
Why do you need singleton Activity-class? Consider different launch modes
check your activity in the AndroidManifest.xml.
<activity
android:configChanges="orientation|keyboardHidden"
android:name=".ActivityName">
They are not public method.They are protected method.You should override existing method.try like the following.
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
The key here is that Android is supposed to be managing your activity lifecycle, not you.
onCreate and onStart (along with onPause, onDestroy and all the other android activity lifecycle functions) are called by the looper on Android's main thread.
How did you start this activity? Was it declared in your manifest as your main activity and launcher? Did you call startActivity and pass the class name?
The fact that you are creating a singleton instance of your activity, and that its constructor is private, suggests to me that Android would be unable to start this activity when you want it to, though some function for passing an existing activity to be managed may exist, and I've just never seen it.
If onCreate and onStart are never being called, it means Android doesn't know it is supposed to be running your activity.
You get an error because your class is not a subclass of Context. Add Context attribute to getSingletonObject(Context context) method and pass it to CycleManager(Context context) constructor.