create an instance of Activity with Activity class object - android

I have got an Activity class by:
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
String activityClassName = launchIntent.getComponent().getClassName();
Class<?> activityClazz = Class.forName(activityClassName);
Is it possible to create an instance of this Activity by using the activityClazz ? If so, how?
(My code is in a independent java class. Not in activity or service. )

Technically, you can create an instance of an Activity like this. However, this instance would be useless because its underlying Context would not have been set up.
The rule is that you should never ever create instances of Android components (Activity, Service, BroadcastReceiver, Provider) yourself (using the new keyword or other means). These classes should only ever be created by the Android framework, because Android sets up the underlying Context for these objects and also manages the lifecycle.
In short, your architecture is flawed if you need to create an instance of an Activity like this.

Class.forName() needs the fully qualified name - that is, the name of the package the class is contained in, plus the simple name of the class itself.
Assuming the package containing the class is called com.your.package, the code would have to be
String className = "com.your.package.Tab3"; // Change here
Object obj= null;
try {
obj= Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

yes. you can get the activity context by using below line of code
Activity activity = (Activity) getContext();

Related

how use getContentResolver in a class without activity?

my class looks like this:
public class sendInformation{
public void test() throws Exception {
Uri uri = SuspiciousActivityTable.CONTENT_URI;
getContentResolver().update(uri, values2, where,new String[]{"Null"});
}
}
}
but it say getContentResolver() doesn't exist, I know I need a Context or Activity to make this work but how do I get the correct Context here?
You will need to pass off a Context, even the ContentResolver class needs a valid context to be instantiated.
Simplest way is as an argument to the method:
public void test(Context context) throws Exception {
Uri uri = SuspiciousActivityTable.CONTENT_URI;
context.getContentResolver().update(uri, values2, where,new String[]{"Null"});
}
And to call: (assuming that the class that contains test is instantiated and your Activity's name is MyActivity <- Replace with the Activity name you're calling test() from)
try{
sendInformationInstanceVariable.test (MyActivity.this);
}
catch (Exception e)
{
e.printStackTrace();
}
MyActivity.this can be shortened to just this if you're not calling test() from inside an anonymous inner class.
Also, if your class really doesn't have a good reason to be instantiated, consider making test() a static method, like this:
public static void test(Context context) throws Exception {
Uri uri = SuspiciousActivityTable.CONTENT_URI;
context.getContentResolver().update(uri, values2, where,new String[]{"Null"});
}
Then from your Activity, you call this method without needing an instance:
try{
sendInformation.test (MyActivity.this);
}
catch (Exception e)
{
e.printStackTrace();
}
Lastly, throwing Exception is bad practice, do don't do it without good reason and if you do have a good reason, be as specific as possible.
Somewhere between where your application starts (and you have access to getApplicationContext()) and the point where you call test(), you'll need to pass in a Context to your sendInformation class. I would look at what lifecycle your sendInformation class has and compare it to the various Android components (Application, Activity, Fragment) and use the appropriate context from there:
Application: getApplicationContext()
Activity: this (as Activity extends Context)
Fragment: getActivity()

How to call a function present in one class from another class?

I'm trying to call a function present in one class from another class by creating its object. Somehow it's not working. The new activity doesn't load.
My java code:
public class MessagesActivity extends TabActivity {
public WorkEntryScreenActivity workEntryObject = new WorkEntryScreenActivity() ;
public void AddWorkEntryClick(View v) {
workEntryObject.newWorkEntry();
}
}
The other class:
public class WorkEntryScreenActivity extends Activity {
public void newWorkEntry() {
try {
Intent i = new Intent(this, WorkEntryActivity.class);
i.putExtra("CurDate", mDateDisplay.getText());
i.putExtra("DD", String.valueOf(mDay));
i.putExtra("MM", String.valueOf(mMonth));
i.putExtra("YYYY", String.valueOf(mYear));
startActivity(i);
finish();
} catch (Exception e) {
System.out.println("Exception" + e.getStackTrace());
Log.d(TAG, "Exception" + e.getStackTrace());
}
}
}
You must create your workEntryObject first (it's not C++). Like this
public WorkEntryScreenActivity workEntryObject=new WorkEntryScreenActivity();
Also, I highly recommed you to read Android Basics
http://developer.android.com/guide/index.html
#biovamp is correct. It looks like you have a null reference that you're trying to call a method on. In order to call a non-static method, you need a instance of that object.
From the naming of your method, it looks like you might be trying to re-use some of your UI in another part of your application. In Android, the way to accomplish that is through Intents and Activities. If you're not familiar with those or how to use them, I would highly suggest researching them.

ClassCastException while dynamically loading a class in Android

I have a thread that loads different classes for the resources it needs depending on the specific implementation of the system. My implementation is on Android and I have a class that returns the specific classes needed by my implementation. I seem to be able to load the class fine, but when I try to assign it to the object in my main thread, it gives me a ClassCastException. Here are the snippets:
In my main thread, I do:
try {
grammarProcessor = config.loadObject(GrammarProcessor.class);
which gives me this stacktrace:
E/AndroidRuntime(6682): FATAL EXCEPTION: JVoiceXmlMain
E/AndroidRuntime(6682): java.lang.ClassCastException: org.jvoicexml.android.JVoiceXmlGrammarProcessor
E/AndroidRuntime(6682): at org.jvoicexml.JVoiceXmlMain.run(JVoiceXmlMain.java:321)
GrammarProcessor is an interface and JVoiceXmlGrammarProcessor is the class that I load and implements that interface. The loading code is as follows:
else if(baseClass == GrammarProcessor.class){
String packageName = "org.jvoicexml.android";
String className = "org.jvoicexml.android.JVoiceXmlGrammarProcessor";
String apkName = null;
Class<?> handler = null;
T b = null;
try {
PackageManager manager = callManagerContext.getPackageManager();
ApplicationInfo info= manager.getApplicationInfo(packageName, 0);
apkName= info.sourceDir;
} catch (NameNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return null;
}
PathClassLoader myClassLoader =
new dalvik.system.PathClassLoader(
apkName,
ClassLoader.getSystemClassLoader());
try {
handler = Class.forName(className, true, myClassLoader);
return (T) handler.newInstance();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
When debugging, I check what's returning from the load method and it is an object with an id number. If I click on it, it'll say org.jvoicexml.android.JVoiceXmlGrammarProcessor#40565820, and the dropdown will show the two private fields that a JVoiceXmlGrammarProcessor should have, so it looks like it's well loaded. Any ideas?
I think I understand what's happening here but I have to make an assumption that org.jvoicexml.android is not your package, i.e., you're loading from a different apk (as the bounty seems to suggest).
With that in mind, this is impossible and for a good reason.
Let's start with your own app - you have the type GrammarProcessor available from your own classes.dex and into your default ClassLoader (the PathClassLoader that you get when the zygote forks your process). Let's call this type GP1. Any class in your own application that implements GrammarProcessor actually has GP1 in their interface list.
Then, you instantiate a new classloader. If you look at the source, you'll see that PathClassLoader is just a thin wrapper around BaseDexClassLoader which in turn delegates to a DexPathList, which in turn delegates to DexFile objects which in turn do the loading in native code. Phew.
There's a subtle part of BaseDexClassLoader that's the cause of your troubles but if you haven't seen it before, you might miss it:
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
and a bit further down:
#Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class c = pathList.findClass(name);
if (c == null) {
...
}
return c;
}
BaseDexClassLoader does not check with its parent first!
.. and that in short is your problem.
More precisely, the DexPathList and DexFile inside it load all the classes from the other dex and never look into the classes already loaded in the VM.
So, you end up with two different loaded versions of GrammarProcessor. Then, the object you're instantiating is referring to the new GP2 class, while you're trying to cast it to GP1. Obviously impossible.
Is there a solution to this?
There's one that's been done before, but you won't like it. Facebook use it in their app to load a bunch of dex files with strong relationships between them. (It's there, before all the messing about with LinearAlloc):
we examined the Android source code and used Java reflection to directly modify some of its internal structures
I'm 90% sure they get the PathClassLoader that you're given (getSystemClassLoader()), get the DexPathList and override the dexElements private field to have an extra Element with the other dex file (apk in your case). Hacky as hell and I would advise against it.
It just occurred to me that if you don't want to use the newly loaded classes in a way that the framework sees them, you could extend from BaseDexClassLoader and implement the proper look-in-parent-before-trying-to-load behaviour. I haven't done it, so I can't promise it will work.
My advice? Just use remote services. This is what Binder is meant for. Alternatively, rethink your apk separation.

Dalvik classloader mystery

I am on Android 2.2 SDK and could not get my static block inside MultiUserChat class to execute. I have tried to force load it as
try
{
String qual = MultiUserChat.class.getName();
ClassLoader.getSystemClassLoader().loadClass(qual);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
and it always hits the catch block. 'qual' gets the valid name of the class... what can it be?
Your app includes both framework classes like ArrayList and Activity, plus application classes like FlashlightActivity. The framework classes are loaded by the system class loader (and also the bootstrap class loadeR); the application classes are loaded by the application class loader.
The system class loader can only see the system classes. It doesn't know the application class path and it can't be used to load application classes. You need to use the application class loader to do that. The easiest way to get a reference to the application class loader is via an application class:
try {
String qual = MultiUserChat.class.getName();
MyActivity.class.getClassLoader().loadClass(qual);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

Android: how to process onClick without an activity?

http://developer.android.com/reference/android/view/View.html#attr_android:onClick
Here it is said that
For instance, if you specify android:onClick="sayHello", you must declare a public void sayHello(View v) method of your context (typically, your Activity).
I'm intrested in "typically, your Activity"... And what if not typically? I'm creating a widget app so I don't have an activity at all...
Almost forgot..
And the question is: where should I write that sayHello method?
Here's the code which is responsible for the invacation:
try {
mHandler = getContext().getClass().getMethod(handlerName, View.class);
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Could not find a method " +
handlerName + "(View) in the activity", e);
}
So basiclly it searches in the class which implements the context for the given method. Usually the context is an activity.

Categories

Resources