Call a class with AsyncTaks from a static class - java

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.

Related

How to call a method contained in an Android activity?

I have an Activity-class with a method called getPacketNames() that returned the names of some installed packages.
private ArrayList<CharSequence> getPackageNames(){
ArrayList<CharSequence> packageNames = new ArrayList<>();
List<PackageInfo> packagesInfos = getPackageManager().getInstalledPackages(0);
for(PackageInfo packageInfo: packagesInfos){
if(!isSystemApp(packageInfo)){
packageNames.add(packageInfo.packageName);
}
}
return packageNames;
}
I want to make it easy for someone else to call this method from another class. However, in order to do so, they would have to create an instance of the activity. This seems cumbersome, and not correct.
Is thee any way I can create this method outside of an Activity? When I create a separate class and copy-paste the method it does not work, because getPackageManager().getInstalledPackages(0) seems to need to be in an activity.
You should't attempt to do that. Instead create a UtilityClass and make your getPackageNames() as static method.
public final class MyUtils {
public static ArrayList<CharSequence> getPackageNames(final Context context){
ArrayList<CharSequence> packageNames = new ArrayList<>();
List<PackageInfo> packagesInfos = context.getPackageManager().getInstalledPackages(0);
for(PackageInfo packageInfo: packagesInfos){
if(!isSystemApp(packageInfo)){
packageNames.add(packageInfo.packageName);
}
}
return packageNames;
}
private static boolean isSystemApp(...){
...
}
}
Then from the Activity, you can access it as follows:
MyUtils.getPackageNames(this);
Sagar's answer is correct and you should follow that. If you are going to create a util class don't forget to add a private constructor, so that your util class will not be instantiated.
For a "hacky" and bad solution, you can always define your method as public static in your activity class and call it from elsewhere with YourActivity.methodname. But this approach will fail especially if you experiment with Don't Keep Activities option.

Install4j: how to check a RemoteCallable running unelevated

My installer is storing some information in a singleton class during the installation process. Now, I have noticed that in elevated action, the singleton class does not have the same instance. So far, I have not found any workaround/solution so that they share the same instance. So, I have decided to make sure that if anyone wants to get an instance of the singleton, they must call from an unelevated environment. Let's say the singleton looks like the following:
public class InvestigatorReport {
private final List<Report> reports = new ArrayList<>();
private final static InvestigatorReport INSTANCE = new InvestigatorReport();
private InvestigatorReport() {
MyLogger.logInfo(getClass(), "initiating...");
}
public static InvestigatorReport getInstance(Context context) {
if (context.hasBeenElevated()) {
throw new IllegalAccessError(
"this method must be called unelevated!");
}
return INSTANCE;
}
private boolean addReport(Report report) {
return reports.add(report);
}
}
But the problem is, There are some cases when I have to call this add report from an action class that is elevated. So I have tried the following in my elevated action class:
if (context.hasBeenElevated()) {
return (Boolean) context.runUnelevated(new RemoteCallable() {
#Override
public Serializable execute() {
return getInstance(context).addReport(report);
}
});
}
But, as you can see if I am passing the same context object from the elevated action class to the RemoteCallable class so, even though I am running the class unelevated, the context.hasBeenElevated() still returns true.
Is there any other way that I can check the elevation level other than the context? If you have any other better idea on preventing anyone from calling the singleton getInstance() method, I am all ears.
I would use a different pattern. Make all methods of your singleton static and wrap the data access with runUnelevated calls:
public static boolean addReport(Report report, Context context) {
context.runUnelevated(new RemoteCallable() {
#Override
public Serializable execute() {
InvestigatorReport.reports.add(report);
return null;
}
});
}
In that way, you can call the methods from both elevated and unelevated code without having to check anything at the call site.

possible alternative to static inner classes to prevent memory leaks in android/java?

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!

getContentResolver in Separate Class

I need a class to get the artists, albums and tracks on the device, which I will then use JNI to call upon.
At the moment, in its barebones, the following causes a crash.
public class AndroidMediaLibray extends Activity {
public void getArtists() {
getContentResolver();
}
}
How do I get this to not crash?
The problem you have, is that you need to call getContentResolver() on a Context. If you call it in an Activity, you automatically call it on the Context of the Activity. But you (probably) never really start AndroidMediaLibrary. Please refer to the documentation of activities. If you want to have the DB call in an extra class, you may have a look at the following code. I have created a class with static methods. I just need to pass the context of my given Activity to that class. In your case that class might look like this:
public class AndroidMediaLibrary {
public static List<String> getArtists(Context context){
ArrayList<String> retVal = new ArrayList<String>();
ContentResolver resolver = context.getContentResolver();
// some more stuff here..
return retVal;
}
}
You may call that function from your MainActivity with:
List<String> myValues = DBUtils.someFunction(MainActivity.this);

Need an explanation : how to use AsyncTask?

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.

Categories