I have a XML file containing some data, so I created a class representing it :
public class MyData
{
ArrayList<SpecialData> list;
int currentPage, totalPages;
}
As you can guess I have a list of SpecialData items, each one containing many fields, and currentPage/totalPages are two unique values in the XML file. I need to get and parse the XML file asynchronously, so I created this class :
class GetXMLTask extends AsyncTask<String, Void, MyData>
{
#Override
protected MyData doInBackground(String... params)
{
MyData md = null;
// Getting/parsing data
return md;
}
}
I gave it a try and the problem doesn't come from here because I correctly parse my XML file and my MyData object is perfect. But then I use this task like this in my main Activity class :
MyData md = null;
GetXMLTask task = new GetXMLTask(this);
task.execute(new String[]{url});
// How can this change my md object?
This may be very silly but I simply don't know how to link my MyData instance from my main class to the one that I get with AsyncTask. What should I do? Thanks.
Override AsyncTask's onPostExecute method:
protected void onPostExecute(MyData result) {
md = result;
}
Note that this assumes your AsyncTask is an inner class to your activity. If that isn't the case, you can pass in a reference to your Activity in the constructor to your AsyncTask. In those cases, you should be careful to use a WeakReference to your Activity to prevent resource leaks:
GetXMLTask(MyActivity activity)
{
this.mActivity = new WeakReference<MyActivity>(activity);
}
protected void onPostExecute(MyData result)
{
MyActivity activity = this.mActivity.get();
if (activity == null) // Activity was destroyed due to orientation change, etc.
return;
activity.updateUiFromXml(result);
}
You probably want to implement a callback of some sort. This way you avoid exposing your data by making it publicly accessible, and you can implement other callbacks (such as an error callback if there is a problem loading the data).
For example, you could define an interface like this:
interface MyAsyncFinishedLister {
void onFinished(MyData resultData);
}
Your AsyncTask will have an instance of MyAsyncFinishedListener, and you can call in onPostExecute as so:
protected void onPostExecute(MyData result) {
myAsyncFinishedListener.onFinished(result);
}
Your main activity will implement this interface and look something like:
class MyActivity extends Activity implements MyAsyncFinishedListener {
MyData md;
public void onCreate() {
super.onCreate();
GetXMLTask task = new GetXMLTask(this);
task.execute(new String[]{url});
task.setOnFinishedListener(this);
}
onFinished(MyData result) {
md = result;
}
}
If you want an AsyncTask to return a data object, you need to store it in a variable in class scope, not function scope. To make this easy, the task is usually a private inner class.
Declare MyData as a variable visible to the whole class and try to access it in onPostExecute() by assigning the result to the MyData variable.
Related
I have a method name checkForUpdate() in UpdateActivity.java. It looks like this:
#NonNull
#SuppressWarnings("deprecation")
protected String checkForUpdate(int curVersionCode) {
HttpClient httpclient = new DefaultHttpClient();
...
}
I am trying to call it from anotherActivity. So I'm trying to use code like this:
private void callFromAnotherActivity() {
UpdateActivity updateApp = new UpdateActivity();
String result = updateApp.checkForUpdate(...);
}
so when I type updateApp. then a list of the methods of UpdateActivity.java appears but there is no checkForUpdate() method. Why?
so when I type updateApp. then a list of the methods of UpdateActivity.java appears but there is no checkForUpdate() method. Why?
This is because your method is not public and probably you haven't import the UpdateActivity.
Please be noted that you can't create an Activity by calling the following:
UpdateActivity updateApp = new UpdateActivity();
You need to use something like this:
// context is your activity context.
Intent updateApp = new Intent(context, UpdateActivity.class);
context.startActivity(updateApp);
My suggestion:
You need to move the checkForUpdate method from UpdateActivity and make it as an util. So, other activity using the method won't be dependent and coupled with UpdateActivity. Localize the method to an utility class something like this:
public class UpdateUtil {
...
#NonNull
#SuppressWarnings("deprecation")
public static String checkForUpdate(int curVersionCode) {
HttpClient httpclient = new DefaultHttpClient();
...
}
}
and then use the method with:
UpdateUtil.checkForUpdate(1);
If you can't move the code (e.g, you don't have ownership of the code), you can do these things:
Make the checkForUpdate as static method
Use EventBus to tell the UpdateActivity to do the update.
You should not create an instance of the activity class. It is wrong. Activity has ui and lifecycle and activity is started by startActivity(intent)
Check here : call a method in another Activity
lately i have been researching about memory leaks in java/android and pretty much everywhere it says that instead of anonymous classes i should use static inner classes with weak references.
so, in my android app i started doing that but very quickly got tired of it because it's a lot of boilerplate code... i think have an alternative solution which i would prefer to use, but i'm juts not sure that it is a valid alternative to static inner classes in terms of preventing memory leaks. as i said before, i haven't seen this solution suggested anywhere else (all say to use static inner classes) so thats why im not sure my alternative will work.
ill use a simple example from my app:
i have a class called WebClient which handles asynchronous web requests and it accepts an interface called iCallback which returns the response from the server to the caller, and in my activity once i get this callback i need to dismiss a dialog, and maybe perform some activity related things (like trigger onBackPressed() and setResult()).
so here is my static inner class i have created:
private static class CallBack implements WebClient.ICallback
{
private WeakReference<ProgressDialog> mProgDiag;
private WeakReference<BaseActivity> mActivity;
public CallBack(BaseActivity activity, ProgressDialog progDiag)
{
this.mProgDiag = new WeakReference<>(progDiag);
this.mActivity = new WeakReference<>(activity);
}
#Override
public void onCallback(String data)
{
String responseAsString = Utils.extractStringFromResponse(...);
final BaseActivity parentActivity = mActivity.get();
ProgressDialog dialog = mProgDiag.get();
if(dialog != null)
{
dialog.dismiss();
}
if (responseAsString == null)
{
if(parentActivity != null)
{
Utils.makeServerErrorDialog(parentActivity,
new iDialogButtonClickedListener()
{
#Override
public void onDialogButtonClicked()
{
parentActivity.onBackPressed();
}
});
}
return;
}
//everything is ok
if (responseAsString.equals("1"))
{
if(parentActivity != null)
{
Intent result = new Intent();
result.putExtra(...);
parentActivity.setResult(Activity.RESULT_OK, result);
}
}
else
{
Utils.reportErrorToServer(...);
if(parentActivity != null)
{
parentActivity.setResult(Activity.RESULT_CANCELED);
}
}
if(parentActivity != null)
{
parentActivity.onBackPressed();
}
}
}
so for every variable i need in this static inner class i have to create a new weak reference, then retrieve the object itself, and then every time i want to access it i need to check whether it's null... that seems like a lot of code to me.
and here is my suggested alternative:
public abstract class BaseActivity extends AppCompatActivity
implements WebClient.ICallback
{
private static final String TAG = "BaseActivity";
WebClient.ICallback mCallBack;
ProgressDialog mProgDiag;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(...);
mCallBack = this;
//some code to invoke a server request on button click
//and passing mCallBack to the request
}
#Override
public void onCallback(String data)
{
String responseAsString = Utils.extractStringFromResponse(...);
mProgDiag.dismiss();
if (responseAsString == null)
{
Utils.makeServerErrorDialog(this,
new iDialogButtonClickedListener()
{
#Override
public void onDialogButtonClicked()
{
onBackPressed();
}
});
return;
}
//everything is ok
if (responseAsString.equals("1"))
{
Intent result = new Intent();
result.putExtra(...);
setResult(Activity.RESULT_OK, result);
}
else
{
Utils.reportErrorToServer(...);
setResult(Activity.RESULT_CANCELED);
}
onBackPressed();
}
#Override
protected void onPause()
{
mCallBack = null;
super.onPause();
}
#Override
protected void onResume()
{
super.onResume();
mCallBack = this;
}
}
to me this seems much cleaner: no creating and retrieving instances of weak references for every variable i need access to, i can directly invoke activity methods (e.g. onBackPressed()), and no checking for null everywhere.
the only place i would now have to check for null is inside WebClient class before invoking the callBack method.
so my question is, does this approach achieve the same result in terms of preventing memory leaks? is it a "worthy" alternative to static inner classes?
Unfortunately, your approach does not work. By implementing the WebClient.ICallback in your activity, rather than an inner class, you don't get rid of the leak. The leak happens not because the references to activity and dialog are implicit in an anonymous class, or in lambda, or in a non-static inner class instance; the happens when the WebClient keeps this reference while the activity is gone (it is not destroyed, because there is a strong reference to it).
The special mCallBack that you set to null when the activity is paused, gains nothing. Just as well, you can simply pass your activity instance to the WebClient. Now there is a strong reference to your activity, which is managed by someone (async handlers of the WebClient), who is not under your control. If you are unlucky, the async handler will get stuck somewhere and will never release this reference.
Please read this detailed explanation.
Note that WebView itself can cause a memory leak, if special measures are not undertaken!
I am trying to initialize a class that calls another class that uses AsyncTask. I am using GetDataFromDB gDataFromDB = new GetDataFromDB() but that does not initialize the class, it just gives me access to any static methods in the class. So what do I do to get the onCreate method to run? I have tried using intent but keep getting an error because this is a static class
public class FacadeDataFromDB extends Activity {
static ArrayList<HashMap<String, String>> visitorsList;
private static FacadeDataFromDB dataFromDB;
static boolean accessDB = false;
private FacadeDataFromDB() {
}
public static void initInstance() {
}
public static FacadeDataFromDB getInstance() {
if (dataFromDB == null) {
// Create the instance
dataFromDB = new FacadeDataFromDB();
}
return dataFromDB;
}
public static void setData() {
if (!accessDB) {
GetDataFromDB gDataFromDB = new GetDataFromDB();
accessDB = true;
}
// visitorsList = gDataFromDB.returnInfoFromDB();
}
public static ArrayList<HashMap<String, String>> getVisitorForDay() {
// TODO Auto-generated method stub
setData();
return visitorsList;
}
}
GetDataFromDB is the other class that I am calling. The current class is a static class and uses a singleton because I only want one initialization of the class the gets data from the db. If you have more questions or want me to post code let me know. Thanks
It seems to me that your two classes FacadeDataFromDB GetDataFromDB should not inherit Activity
Activities are made for GUI and user-interaction (I don't see any in your example) and their life-cycle is managed by the framework : you never create them manually with new.
See the android tutorial : https://developer.android.com/guide/components/activities.html and Activity javadoc : https://developer.android.com/reference/android/app/Activity.html.
I'm not sure that you completely understand the Android runtime. You should start Activities using Intent objects, not by creating them with the new keyword as you are. To ensure that your onCreate() method is called within your Activity, you could launch an explicit Intent from some other Activity/Context: Intent intent = new Intent(currentContext, FacadeDataFromDB.class);.
Also, when it comes to Activities, you shouldn't use private constructors. See this post for reasons why.
I just ran into this problem while coding android. If I have a non-static method (It has to be non-static for the code inside to work) in my main class, how am i supposed to call it from within another class, because obviously I can't create another instance of my main class without starting a new instance of the program?
public class MainActivity extends FragmentActivity {
public static String starttime = "";
public static String startdate = "";
public static String endtime = "";
public static String enddate = "";
public static boolean start = false;
}
public void setDateText() {
EditText TextStart = (EditText)findViewById(R.id.txt_start);
TextStart.setText(startdate + " at " + starttime, TextView.BufferType.NORMAL);
EditText TextEnd = (EditText)findViewById(R.id.txt_end);
TextEnd.setText(enddate + " at " + endtime, TextView.BufferType.NORMAL);
}
Any help on how to call the setDateText() method from another class?
Thanks in advance
Normally you can't call a non static method from a static type, so you would do:
MainActivity m = new MainActivity(); // No constructor needed in class def.
m.setDateText();
But, when the program starts, you're not giving your JVM anything to call at the start, so you need to add:
#Override
//the function called when activity is created
public void onCreate(Bundle savedInstanceState) {
//call the create fct. Of the base class
super.onCreate(savedInstanceState);
//load the layout specified in the layout.xml
setContentView(R.layout.main);
MainActivity m = new MainActivity();
m.setDateText();
}
This will be called when the activity is created.
Go to Android - A beginner's guide for more information.
Also watch your syntax, your method def is outside of your class def.
Without knowing which other class is trying to access the MainActivity instance, you will need to pass a reference of this instance to your other objects, probably by passing this into a constructor or method.
For example
public class MainActivity extends FragmentActivity {
public void someMethod() {
SomeClass someClass = new SomeClass(this); // pass this for callbacks
// ~ more
}
}
where SomeClass is a class where you need to call the MainActivity's setDateText method.
I am trying to understand the need for you to call the function from another activity. Your main activity is anyway not on the foreground, so if you call this function from there, date will not be shown. Once you finish the 2nd activity and you will be back to MainActivity, then only you need this function to be called.
If that is so, then you can use startActivityForResult() to start 2nd activity, and then pass the date information back to MainActivity through onActivityResult(). You can call this function in MainActivity itself.
If you have to invoke setDate() at the activity's launch, you can pass the date in the Intent when you launch the activity and pull the date in MainActivity's onCreate method.
If you have to invoke setDate() at a different time other than launch, you can send a broadcast from other activity/component and make MainActivity listen to the Broadcast and pull the date from the intent's data.
I'm new to android and I need little help please. I want to pass data from an activity to a framelayout class, so I've implement a callback. On my activity I use an interface and setting the listener like this:
private OnCallStateListener onCallStateListener;
public interface OnCallStateListener{
int Data = 1;
void OnCallState(int wichAction)
}
public void setOnCallStateListener(OnCallStateListener listener){
onCallStateListener = listener;
}
private void dispatchTriggerEvent(int whichHandle){
if(onCallStateListener != null){
onCallStateListener.OnCallState(whichHandle);
}
}
And I use it like:
private onCallDisconnect(){
dispatchTriggerEvent(OnCallStateListener.DATA);
The dispatchTriggerEvent is executed but the problem is that the listener onCallStateListener is always null. what am I missing here?
Thanks!
It is null because you did not create an instance of the class. From what you have here you only have an interface. You would first need to create a class that implements that interface, and then say something like:
OnCallStateListener myVar = new OnCallStateListenerImpl();