How to call a method contained in an Android activity? - java

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.

Related

Can't call a method from outside of a java class

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

Static variables, pattern and Android performance

I'm doing some big refactoring operations relative to some performance improvements in an android app which is using a class with lot of static variables and even static activity references which are then use through the app ! So I was looking for some best practices in Android to store data and give to these data a global access in my app.
First I removed all the activity references to avoid any memory leak, but I'm still looking to know what is the best practice regarding static variables which need to be used anywhere in the android app.
I read many times (example1, exemple2) : using static variables is not necessary a good practices and it's better/cleaner to use one singleton class with getter and setter to have access to my global variables whatever the activity where I am. So what I've started to think is a class which could looks like this one :
public class AppSingleton extends Application {
private static AppSingleton appInstance;
// different stored data, which could be relative to some settings ..
private String setting1;
private String setting2;
private AppSingleton() {
super();
appInstance = new AppSingleton();
}
public static AppSingleton getAppInstance() {
if (appInstance == null) {
appInstance = new AppSingleton();
}
return appInstance;
}
// Getter and Setter for global access
public String getSetting1() {return setting1;}
public void setSetting1(String setting1) {this.setting1 = setting1;}
public String getSetting2() {return setting2;}
public void setSetting2(String setting2) {this.setting2 = setting2;}
}
Then I can use for example :
// Get the application instance
AppSingleton appS = (App) getApplication();
// Call a custom application method
appS.customAppMethod();
// Call a custom method in my App singleton
AppSingleton.getInstance().customAppSingletonMethod();
// Read the value of a variable in my App singleton
String var = AppSingleton.getInstance().getCustomVariable;
For me AppSingleton sounds good because this singleton which restrics ths instantiation of this class to one object, also this class is not destroyed until there are any undestroyed Activity in the application so it means I can keep my global data in the current lifecycle of my app for example from a 'Log in'. But also I can maintain the state of my global variables from my getters/setters.
But then I also had a look on the official android documentation about Performance Tips which say it's good to use static variable it's faster and don't forget to avoid internal getter and setter it's too expansive !
I'm a bit confused about all of these and I'm really keen to learn more about that topic. What is the best practices about using one class to provide an access to some variables which are needed in different part of my code ? Is the class above AppSingeleton is something which could be interesting to use in terms of architecture and performance ?
Is it a good idea to use a singleton pattern for managing global variables in android ?
those lines are completely wrong on your code:
private AppSingleton() {
super();
appInstance = new AppSingleton();
}
public static AppSingleton getAppInstance() {
if (appInstance == null) {
appInstance = new AppSingleton();
}
return appInstance;
}
you cannot instantiate new Application, the Android framework instantiates it. Change to this:
private AppSingleton() {
super();
appInstance = this; // keep ref to this application instance
}
public static AppSingleton getAppInstance() {
return appInstance;
}
Regarding the accessing of global variables. I believe it's more organized to have those singletons somewhere else on your application. The application class have different responsibilities you should not overload it with different tasks. That's OO clean coding.
Also, sometimes there's not that much reason in an Android app to have getters/setters for everything, because u don't need as much access control as in bigger projects. But this should be considered case-by-case about the necessity and not be used a general rule.
So you could for example have it like:
public class Globals {
private static final Globals instance = new Globals();
public static Globals get() { return instance; }
public String value1 = "Hello"
public int value2 = 42;
}
then on your code call as needed:
Log.d(TAG, Globals.get().value1);
Globals.get().value1 = "World";
Log.d(TAG, Globals.get().value1);
Log.d(TAG, "Value2 = " + Globals.get().value2);

Call a class with AsyncTaks from a static class

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.

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);

How to call a private method of a class in different package

There is a BookView.class that has a private method defined as below
public class BookView{
private boolean importBook(String epubBookPath){
//The function that adds books to database.
}
}
I am trying to call this function from a different package. My code is
protected void onPostExecute(String file_url) {
// dismiss the dialog after the file was downloaded
dismissDialog(progress_bar_type);
/*Now we add the book information to the sqlite file.*/
TextView textView=(TextView)findViewById(R.id.textView1);
String filename = textView.getText().toString();
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String epubBookPath = baseDir+filename;
Log.i("epubBookPath:",epubBookPath); //No errors till here!
try {
Method m=BookView.class.getDeclaredMethod("importBook");
m.setAccessible(true);//Abracadabra
//I need help from here! How do i pass the epubBookPath to the private importBook method.
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Intent in = new Intent(getApplicationContext(),
CallEPubUIActivity.class);
startActivity(in);
}
EDIT:
I found another public method in the jar file which is doing the above work.
public void jsImportBook(String epubBookPath) {
if (!BookView.this.importBook(epubBookPath))
return;
BookView.this.createBookshelf();
}
If you want to do that you should make it public or make a public wrapper method it.
If thats not possible, you can work your way around it, but thats ugly and bad and you should have really good reasons to do so.
public boolean importBook(String epubBookPath){
//The function that adds books to database.
}
or
public boolean importBookPublic(String epubBookPath){
return importBook(epubBookPath);
}
private boolean importBook(String epubBookPath){
//The function that adds books to database.
}
Also note that if you CAN'T access the method directly in a third-party library than it is most likely INTENDED that way. Take a look at the call hierarchy of the private method and see if you find a public method that does the call to the private one and that also does what you need.
Libraries are often designed in a way that a public method does some checking (all Parameters given, authenticated etc.) and then pass the call to the private method to do the actual work. You almost never want to work around that process.
With reflection, you'll need an instance of BookView to invoke the method with (unless it's a static method).
BookView yourInstance = new BookView();
Method m = BookView.class.getDeclaredMethod("importBook");
m.setAccessible(true);//Abracadabra
Boolean result = (Boolean) m.invoke(yourInstance, "A Path"); // pass your epubBookPath parameter (in this example it is "A Path"
The method you are looking for is Method#invoke(Object, Object...)
Use reflection to get you method and set Accessible as true, then invoke the method using BookView Object instance and required parameters(path string) using statement as below:
Boolean result = (Boolean)method.invoke(bookObject, epubBookPath);
Sample code as below:
Method method = BookView.getDeclaredMethod("importBook");
method.setAccessible(true);
Boolean result = (Boolean)method.invoke(bookObject, epubBookPath);
Private methods cannot be accessed outside the class it is defined.
Make it Public.

Categories