Is it possible to pass class name as a parameter in Java? - java

I have following code:
private void startLesson(String input) {
Intent intent = new Intent(StartovayaAktivnost.this, OsnovnayaAktivnostORM.class);
intent.putExtra("vybor_razdela", input);
startActivity(intent);
}
I want to launch different activities depending on parameter, is there a simple solution to pass a class name like
private void startLesson(String input, String activityname) {
Intent intent = new Intent(StartovayaAktivnost.this, activityname.class);
intent.putExtra("vybor_razdela", input);
startActivity(intent);
} //I know it's not gonna work
or the only way is to use embranchments like
private void startLesson(String input, String activityname) {
if (activityname.equals("OsnovnayaAktivnost"))
{
Intent intent = new Intent(StartovayaAktivnost.this, OsnovnayaAktivnost.class);
intent.putExtra("vybor_razdela", input);
startActivity(intent);
}
else if (activityname.equals("OsnovnayaAktivnostORM")) {
Intent intent = new Intent(StartovayaAktivnost.this, OsnovnayaAktivnostORM.class);
intent.putExtra("vybor_razdela", input);
startActivity(intent);
}
}

You can have a class as a parameter. Consider the following:
private void startLesson(String input, Class activityname) {
Intent intent = new Intent(StartovayaAktivnost.this, activityname);
intent.putExtra("vybor_razdela", input);
startActivity(intent);
}
You can then call your method as
startLesson("input", Main.class);
The same way as they're using classes as their parameters.

you can do something like:
Class<?> myClass = Class.forName(activityname);
Intent intent = new Intent(StartovayaAktivnost.this, myClass);
intent.putExtra("vybor_razdela", input);
startActivity(intent);
However, activityname should be the full class name.

You already have answers that show you solutions. I am more curious about your use-case though. For a similar situation I created a map of strings to classes of a certain base type. When passing activityName to that map, I would find the activity, or not. This gives you more control over what kind of classes are allowed to be loaded in this situation. In your scenario it would be harder to limit what kind of classes can be passed into Intent. But I imagine they have to adhere to certain rules that make up an activity.
Something like:
Map<String, MyBaseActivityType> activities
If you need new instances of the activity class every time, you can modify it a bit, I haven't given that part much thought.
But don't use reflection unless you really really need it. It gets messy quickly.

Found an answer while trying at random:
private void startLesson(String input, String activityname) throws ClassNotFoundException {
Intent intent = new Intent(StartovayaAktivnost.this, Class.forName(activityname));
intent.putExtra("vybor_razdela", input);
startActivity(intent);
}

Related

How can I open an Activity using the name as string via intent?

I want to use String variable containig the name of an activity, and i want to open the activity via in intent.
For example:
next = "foo.class";
Intent baslat = new Intent(this,next);
"next" is my value. I think using variable is impossible because eclipse don't let me use two arguments.
How can I solve this problem?
Edit: I am trying to go to "foo.class"
Edit: I solve the problem, You are all so nice and pretty :D, kisses for all, thank you very much!
OK, use the method Class.forName()
String myClass = "foo.class";
Intent myIntent = new Intent(getApplicationContext(), Class.forName(myClass));
startActivity(myIntent );
There is a method Intent.putExtra(). You can use this method to add extra variables inside your intent object.
String next = "foo.class";
Intent baslat = new Intent();
baslat.putExtra("my_tag", next);
Intent.putExtra() is what you're looking for.
next = "foo.class";
Intent baslat = new Intent(/*intent action goes here*/);
basalt.putExtra(/*data name*/, next);
If foo.class is where you're headed, then use Intent(Context packageContext, Class cls):
Intent baslat = new Intent(this, foo.class);
startActivity(basalt);

Calling an Intent in Android that is a variable

I currently have a list view and I'm trying to direct the list view to different activities. So that if you click an item from let's say 1-4 you'll get the class that corresponds to that. The only way that I can think of doing it is grabbing the text of the item in the list view and starting the activity of that name. The code for it would go something like this:
final String chosen = "";
chosen = (String) ((TextView) view).getText();
Intent nextScreen = new Intent(getApplicationContext(), chosen.class);
That does not work. I get an error on the last line, saying that chosen cannot be resolved into a type.
I know that ((TextView) view).getText() works because
Log.d("Debug", "Test"+((TextView) view).getText());
gives me the correct chosen item in logcat.
Any ideas/suggestions? Thanks in advance
EDIT:
I tried changing my code to this:
String chosen = (String) ((TextView) view).getText();
try {
Intent nextScreen = new Intent(getApplicationContext(), Class.forName(chosen));
startActivity(nextScreen);
Log.d("Debug", "Good"+((TextView) view).getText());
}
catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d("Debug", "Bad"+((TextView) view).getText());
}
Log.d("Debug", "Final"+((TextView) view).getText());
Log cat gave me an output of
BadItem1
FinalItem1
I think I'm going about this the wrong way as someone pointed out. I also think I should be using OnItemClickListener. I will try it and post my results for easier help in the future.
The error is here:
final String chosen = "";
chosen = (String) ((TextView) view).getText();
Since you declare chosen as final, you can assign it a value only once:
final String chosen = (String) ((TextView) view).getText();
Moreover I suppose you want to start the Activity which has the name that is stored in variable chosen. You cannot write chosen.class for this. The correct way to do this is:
Class.forName(chosen);
Hope this helps!
There is no Intent constructor that takes a Context and a String. You can probably do something like Class.forName(chosen) in the call to the Intent constructor.
Calling .class on a variable gets the class for that variable, not the class for the content of the variable.
I think that you should use the OnItemClickListener on the ListView to identity the clicked item. The position parameter, or calling getItemAtPosition(position), should be enough to identify uniquely a item in the listview and call the appropriate activity.
See documentation here: http://developer.android.com/reference/android/widget/AdapterView.OnItemClickListener.html
Make a Factory.
This way you don't have to tie your class names to the text the user is reading. giving you more flexibility / better user experience / easier code to maintain. Helping with your separation of concerns as well.
class NavFactory {
private static final int CLASS_FIRST = 1;
public static Intent getNavIntent(Context context, String name){
switch(getId(name)){
case CLASS_FIRST:
return new Intent(context, FirstClass.class);
default:
return null;
}
}
private static int getId(String name){
if("listItemOneText".equals(name)
return CLASS_FIRST;
return -1;
}
}
Ref: Java Factory Pattern
In your case:
String chosen = (String) ((TextView) view).getText();
Intent nextScreen = NavFactory.getNavIntent(this, chosen);
You are new sending String as the class of supposed Activity. This is what you need:
final String chosen = "";
chosen = ((TextView) view).getText();
Class<?> chosenActivity = Class.forName(chosen);
Intent nextScreen = new Intent(this, chosenActivity);

Get result from an activity after finish(); in an Android unit test

I'm currently writing some Android unit tests, and while I've gotten most things to work the way I want, one thing has left me kind of stumped.
I have the following code in my activity under test:
Intent result = new Intent();
result.putExtra("test", testinput.getText().toString());
setResult(Activity.RESULT_OK, result);
finish();
I'm trying to figure out how to use Instrumentation (or whatever) to be able to read the result of the activity, or get at the intent after the activity is finished.
Can anyone help?
You can use reflection and grab the values directly from the Activity.
protected Intent assertFinishCalledWithResult(int resultCode) {
assertThat(isFinishCalled(), is(true));
try {
Field f = Activity.class.getDeclaredField("mResultCode");
f.setAccessible(true);
int actualResultCode = (Integer)f.get(getActivity());
assertThat(actualResultCode, is(resultCode));
f = Activity.class.getDeclaredField("mResultData");
f.setAccessible(true);
return (Intent)f.get(getActivity());
} catch (NoSuchFieldException e) {
throw new RuntimeException("Looks like the Android Activity class has changed it's private fields for mResultCode or mResultData. Time to update the reflection code.", e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Or you could also use Robolectric and shadow the Activity under test. Then, ShadowActivity provides you with methods to easily know if an Activity is finishing and for retrieving its result code.
As an example, one of my tests looks like this:
#Test
public void testPressingFinishButtonFinishesActivity() {
mActivity.onCreate(null);
ShadowActivity shadowActivity = Robolectric.shadowOf(mActivity);
Button finishButton = (Button) mActivity.findViewById(R.id.finish_button);
finishButton.performClick();
assertEquals(DummyActivity.RESULT_CUSTOM, shadowActivity.getResultCode());
assertTrue(shadowActivity.isFinishing());
}
You can do this by writing a special activity whose only purpose is to start the activity you are testing for result and save the result for you to assert correctness on.
For example, you could create an activity named ResultReceiverActivity. Give it three methods: getResultCode, getResultData, and getReceivedRequestCode, which can be used to verify that the tested activity returned the right values. You would create a test case that extends ActivityInstrumentationTestCase2 and the generic parameter would be ResultReceiverActivity. Calling getActivity will get you the activity instance.
public class ReturnedResultTest
extends ActivityInstrumentationTestCase2<ResultReceiverActivity> {
public void testReturnedResult() {
ResultReceiverActivity a = getActivity();
assertEquals(Activity.RESULT_OK, a.getResultCode());
assertEquals("myResult", a.getResultData().getStringExtra("test"));
assertEquals(0x9999, a.getReceivedRequestCode());
}
}
ResultReceiverActivity needs to override onActivityResult, of course, and should just store the values of that methods parameter in its fields, like so:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
this.receivedRequestCode = requestCode;
this.resultCode = resultCode;
this.resultData = data;
}
Of course, you may want to customize the activity that ResultReceiverActivity starts, and you can easily do that by using getIntent in its onCreate method. In your test case, call setActivityIntent before calling getActivity to set which Intent is used to start the activity.
I'm not sure if it is different for unit tests, but you should be able to use onActivityResult as seen here: StartingActivities. You just start the Activity with startActivityForResult(intent, requestCode) and then use
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
back in the activity that used startActivityForResult.

Passing custom objects between activities?

How do I pass custom objects between activites in android? I'm aware of bundles but I can't seem to see any functionality for this in them. Could anyone show me a nice example of this?
You should implement Parcelable interface.
Link to documentation.
Using Parcelable interface you can pass custom java object into the intent.
1) implement the Parcelable interface to your class like:
class Employee implements Parcelable
{
}
2) Pass the Parcelable object into the intent like:
Employee mEmployee =new Employee();
Intent mIntent = new Intent(mContect,Abc.class);
mIntent.putExtra("employee", mEmployee);
startActivity(mIntent);
3) Get the data into the new [Abc] Activity like:
Intent mIntent = getIntent();
Employee mEmployee = (Employee )mIntent.getParcelableExtra("employee");
a Parcel MIGHT solve your problem.
think of a Parcel as an "array" (metaphorical) of primitive types (long, String, Double, int, etc). if your custom class is composed of primitive types ONLY, then change your class declaration including implements Parcelable.
you can pass a parcelable object thru an intent with no difficulty whatsoever (just like you would send a primitive-typed object). in this case i have a parcelable custom class called FarmData (composed of longs, strings and doubles) which i pass from one activity to another via intent.
FarmData farmData = new FarmData();
// code that populates farmData - etc etc etc
Intent intent00 = new Intent(getApplicationContext(), com.example.yourpackage.yourclass.class);
intent00.putExtra("farmData",farmData);
startActivity(intent00);
but retrieving it may be tricky. the activity that receives the intent will check if a bundle of extras was send along with the intent.
Bundle extras = getIntent().getExtras();
FarmData farmData = new FarmData();
Intent intentIncoming = getIntent();
if(extras != null) {
farmData = (FarmData) intentIncoming.getParcelableExtra("farmData");// OK
}
Given an object PasswordState that implements Serializable throughout the object tree, you can pass this object to anther activity as in:
private void launchManagePassword() {
Intent i= new Intent(this, ManagePassword.class); // no param constructor
PasswordState outState= new PasswordState(lengthKey,timeExpire,isValidKey,timeoutType,"",model.getIsHashPassword());
Bundle b= new Bundle();
b.putSerializable("jalcomputing.confusetext.PasswordState", outState);
i.putExtras(b);
startActivityForResult(i,REQUEST_MANAGE_PASSWORD); // used for callback
}
One simple way to pass an object between activities or make a object common for all applicattion, is create a class extending Application.
Here is a example:
public class DadosComuns extends Application{
private String nomeUsuario="";
public String getNomeUsuario() {
return nomeUsuario;
}
public void setNomeUsuario(String str) {
nomeUsuario = str;
}
}
In all your others activities, you just need instantiate one object "DadosComuns", declarating as a Global Variable.
private DadosComuns dadosComuns;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//dados comuns
dadosComuns = ((DadosComuns)getApplicationContext());
dadosComuns.setNomeUsuario("userNameTest"); }
All others activities that you instantiate dadosComuns = ((DadosComuns)getApplicationContext()); you can acess getNomeUsuario() == "userNameTest"
In your AndroidManifest.xml you need to have
<application
android:name=".DadosComuns"

Launching intent from a class outside an activity

I've got two activities, one of them is called MyActivity. I want both of them to be able to use a function located in a class othat we may call MyClass. In MyClass, I try to use an intent to launch the activity AnotherActivity. Since the constructor takes a context as parameter, I simply tried to store a context from the activity in the constructor, and then use it when I try to create my intent.
class MyClass {
private Context cxt;
MyClass(Context cxt) {
this.cxt = cxt;
}
startIntent() {
Intent intent = new Intent(cxt, AnotherActivity.class);
startActivity(intent); // this line throws a NullPointerException
}
}
The code in MyActivity to use the class is shown below:
myClassObject = new MyClass(MyActivity.this);
myClassObject.startIntent();
However, even thought none of the arguments are null (checked that with a simple if-statement), intent seems to be null and a NullPointerException is thrown. Why does it not work, and what can I do to solve the problem?
I'm quite new to Android and Java development, so please explain it as basic as you can.
cxt.startActivity(new Intent(cxt, AnotherActivity.class));
and to be sure that it's intent is NULL, and not something internal in startActivity method, you can add some checks, i.e.
Intent intent = new Intent(cxt, AnotherActivity.class);
Log.d(toString(), "intent = " + intent.toString());
cxt.startActivity(intent);
I've used almost identical code in my applications and it's worked fine.
I suspect there's something else going on that's in code you haven't shown us; I suspect there's some cut-and-paste issues --- e.g. what are you calling startActivity() on in MyClass?

Categories