Can multiple Activity declarations share the same class name? - android

For example
<manifest>
<activity android:label="MyActivity1" android:name=".MyClass">
</activity>
<activity android:label="MyActivity2" android:name=".MyClass">
</activity>
</manifest>

Yes and no. When you prepend the Activity name with a ., it looks at the Manifest's default package to get the whole class path, such as com.example.android.MyClass. Thus, if instead you have one .MyClass and another com.example.android.other.MyClass, then this should work.
<manifest>
<package="com.example.android">
<activity android:label="MyActivity1" android:name=".MyClass">
</activity>
<activity android:label="MyActivity2" android:name="com.example.android.other.MyClass">
</activity>
</manifest>

I'm not 100% sure if this is possible, but perhaps there is a better way to go about this. If you need the same activity you can call it in both situations like you normally would but pass in data during the call as well. In your MyClass you can read the data and decide how to handle it.
Example:
//Activity 1
Intent i = new Intent(this, MyActivity.class);
i.putExtra("open", "activity1data");
startActivity(i);
//Activity 2
Intent i = new Intent(this, MyActivity.class);
i.putExtra("open", "activity2data");
startActivity(i);
And in MyActivity do something like this in onCreate()
Intent intent = getIntent();
Bundle extras = intent.getExtras();
String action = intent.getAction();
if(extras.containsKey("open")){
if(extras.getString("open").equals("activity1data")){
//DO activity 1 stuff
}
}
This is a pretty rough example, you could use ints and switch on those etc. But the real goal is to let one activity handle a variety of cases. This seems to be what you want since your going to use the same class anyway.

Related

How to access the Class of the Activity defined in parentActivityName

For every activity which has a logical parent we define that parent Activity in the Manifest like so:
<activity
android:name=".ui.activity.MyActivity"
android:label="#string/activity_title"
android:parentActivityName=".ui.activity.ParentActivity"
android:theme="#style/My.Theme" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.activity.ParentActivity" />
</activity>
Is there a way to access the Class referenced in either #parentActivityName or meta-data#value in MyActivity?
(Please note that I don't want to access the parent Activity instance, just the Class)
The reason is that for tracking purposes we want to generate a path-like String for each Activity. In this case this String would be /parent_activity/my_activity – and since the hierachy is already defined in the Manifest, best case would be to access it there then to define it twice.
Thank you for your help!
Maybe it will help you NavUtils.getParentActivityName(childActivityInstance)
You could always go with the easy way: Pass the parent activity name in intent extras as string, in ParentActivity
Intent intent = new Intent(ParentActivity.this, ChildActivity.class);
intent.putExtra("parent_activity_name", "ParentActivity");
...
startActivity(intent);
And then get it in the ChildActivity activity
Intent intent = getIntent();
String parentName = intent.getStringExtra("parent_activity_name");
Not sure if there is any other more elegant solution.

onNewIntent is not called

I have very strange situation.
Having one app, I decided to create another one from the code of first one.
I copied .xml files, copied .java files so that everything is OK.
But there's one HUGE problem: my onNewIntent(Intent intent) method is called in first project, but it's not called in the second project (the code is the same!)
Method, which could trigger then, but can't trigger now
public void onClick(View arg0) {
Intent browserInt = new Intent (Intent.ACTION_VIEW,
Uri.parse("https://oauth.yandex.ru/authorize?response_type=token&client_id=zzzzz"));
browserInt.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(browserInt);
}
Here's onNewIntent() method:
#Override
protected void onNewIntent(Intent intent){
System.out.println(" I WORKED!");
Uri uri = intent.getData();
if (uri!=null) {
String m = uri.toString().split("#")[1];
String[] args = m.split("&");
String arg = args[0];
String token = arg.split("=")[1];
System.out.println(token);
}
}
I don't see "I WORKED" in my logs, unfortunately.
I've read lots of similar questions both on SO and over the Internet, tried setting Intent flags SINGLE_TOP, SINGLE_TASK and so on.
Here's the Android Manifest of WORKING project:
<application
android:name="yyy"
android:icon="#drawable/yaru_icon"
android:allowBackup="false"
android:label="xxx"
android:theme="#style/LightTheme">
<activity
android:name=".Main"
android:label="xxx"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
I'm quite desperate, why the similar code is not working anymore?
EDIT: I've tried everything: SINGLE_TOP, SINGLE_INSTANCE, SINGLE_TASK..
but then I occasionally did this on another activity:
Main m = new Main();
m.onNewIntent(this.getIntent());
And it finally worked!
I don't know, whether it's a dirty workaround or a bug, if anyone can explain it, please, comment.
PREAMBLE:
Allright, I'm a little late to this one, but as I stumbled over the same issue and no answer here or for any of the other four stackoverflow questions, I found for this issue, solved the problem for me, here's what I figured out.
ANSWER:
There are several possible reasons, why onNewIntent isn't called and I'm gonna list them all - well all of which I know.
As mentioned in many answers before and in the doc for the onNewIntent function (link in Yaroslavs answer), you either need the android:launchMode="singleTop" manifest entry for the activity, where you want onNewIntent to be called, or the Intent used for starting the activity must have the flag FLAG_ACTIVITY_SINGLE_TOP. You don't need both (it's a | aka. logical or not a & aka. logical and )! onNewIntent should also be called for android:launchMode="singleTask", but before you use that, you better check out the android:launchMode documentation, because it has much more consequences, than just one function call.
In older versions of Android there was a bug, which basically prevented android:launchMode="singleTop" from working as specified and thus onNewIntent from being called. The bug was never officially solved, but I couldn't reproduce it in version 4.4.2 (Samsung S4 Mini). So it seems to have been fixed at some point between 4.0.x and 4.4.2.
Not every time the preconditions as mentioned before are fulfilled, onNewIntent will be called. As the documentation of the function states:
...when the activity is re-launched while at the top of the activity stack instead of a new instance of the activity being started, onNewIntent() will be called on the existing instance with the Intent that was used to re-launch it."
That means, if the activity is newly created, onNewIntent won't be called, no matter what launchMode or Intent flags you did set!
To my understanding, either onCreate or onNewIntent is called, but never both.
So, if you wanna pass data to the activity through the Intent and it should always work (as in my case), no matter if the activity is relaunched or the activity is freshly created, you can do as described in this very useful blog post.
As a variation of the solution described in the above blog post, you could also take advantage of the fact, that no matter if onNewIntent or onCreate was called, onResume will always be called afterwards, and do something like this:
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
#Override
protected void onResume() {
super.onResume();
Intent intent = getIntent();
// ... do what you wanna do with the intent
}
For this example getIntent will always get you the Intent you used for the startActivity call or the Notification, as the new Intent will also be set for the Activity, if the Activity is freshly created (and thus onCreate was called).
POSTAMBLE:
Sorry for the long post. I hope you found something useful in it.
The Activity you want to receive onNewIntent() in should have
android:launchMode="singleTop"
Or add the flag tn intent
browserInt.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
Intent.FLAG_ACTIVITY_SINGLE_TOP);
As documented in onNewIntent(Intent)
Here's one situation that might bite you, along with a bit more information: onNewIntent is called as expected with this code:
Intent intent = new Intent...
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
finish();
startActivity(intent);
but not with this code
Intent intent = new Intent...
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
finish();
The reason for that is that, in the second code block, the new activity is added on top before calling finish for the current activity, so to get the second code block to work you must add the FLAG_ACTIVITY_CLEAR_TOP flag as suggested by some of the other answers, like this:
Intent intent = new Intent...
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Note that finish is not called at all here, because it is called for you. From the documentation for the FLAG_ACTIVITY_CLEAR_TOP flag:
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
I was using onNewIntent for search implementation in Android. I came across the problem that onNewIntent wasn't being called when I used the Go button on the keyboard in the emulator. I solved the issue by placing my code for handling the intent in the onCreate method also. This needs to be done to make sure that the intent action is handled when a fresh instance of the activity is started.
This posed a problem as onCreate is called whenever the activity is restored from a previous state too. So, the intent handling method gets called even when an orientation change occurs.
Solution : Use if (savedInstanceState==null) to determine if activity is being restored from a previous state, or is it a fresh search.
The best way to handle onNewIntent with singleTop is simply this:
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
Then do all of your logic on getIntent inside onResume.
for me I didn't add search action to the activity in the manifest:
<activity android:name=".SearchResultsActivity" ... >
...
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
...
</activity>
Check your steps here:
https://developer.android.com/training/search/setup
In my case, I just add launchMode="singleInstance" in the activity tag in the AndroidManifest file.
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Note: I was using kotlin.
To enter to the onNewIntent method, you need in your AndroidManifest.xml file, put after set you main activity a launch mode, in this launch mode you have to put singleInstance e.g:
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:launchMode="singleInstance"
android:windowSoftInputMode="adjustPan" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Now you will able to enter to you onNewIntent method.

Determine how Activity was started

I have an app that starts an activity that isn't the MainActivity first, but it is possible within the course of the app to start the activity on its own. I would like code that runs when the activity is closed to be able to determine if it should go the front of the application(first run) or if it should go back to the previous Activity on the stack(all other runs). Is it possible to determine how an Activity was started inside of it?
You said:
I would like to determine within the course of the Child
Activity what Parent Activity started the Child. In my case that will
either be the Launcher or the MainActivity.
Unfortunately, there is no way to find out what Activity launched your Activity. This information is not available. However...
You can tell if the launcher started your Activity by checking the Intent for ACTION = MAIN and CATEGORY = LAUNCHER:
Intent intent = getIntent();
if (Intent.ACTION_MAIN.equals(intent.getAction()) && intent.hasCategory(Intent.CATEGORY_LAUNCHER)) {
// started by launcher
}
You can also check if the Activity was launched from the list of recent tasks by checking for Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY like this:
Intent intent = getIntent();
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
// Launched from recent task list
}
If this isn't enough for you, then you can always add an "extra" yourself when launching the child Activity from the parent, so that it can tell what Activity started it. For example:
Intent intent = new Intent(this, ChildActivity.class);
intent.putExtra("startedFromMainActivity", true);
startActivity(intent);
and then in your child Activity you can check like this:
Intent intent = getIntent();
if (intent.hasExtra("startedFromMainActivity") {
// started from MainActivity
}
You can store a value in the intent launching your activity, and once opened read it to adapt your behaviour:
intent.putExtra(key,value);
And on the activity side (in onCreate for eg):
getIntent().getExtra(key,defaultValue);
Default value is what you get if no value is found.
getExtra depends o the type of the data stored, so there is getIntExtra ,booleanExtra ,stringExtra ...
Learn more here
your manifesto file exchange mainactivity DEFAULT...
<activity
android:name="com.example.iiintent.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="com.example.iiintent.al">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
</activity>

Launch Main Activity with Implicit Intent in Service

I have an implicit intent in a service that sends information to my main activity, as well as to another class. I also now want that intent to launch my main activity. I've looked at the myriad posts related to this, and tried lots of different things--addCategory, setAction(MAIN; the activity's name; you name it, I've tried it...), category.DEFAULT in the manifest, and several other things that either resulted in ActivityNotFoundExceptions (most commonly) or behavior that was otherwise undesirable.
Here's where the intent is set up and the relevant part of the manifest. The receiver for the intent is registered in the main activity.
final String NEW_DOSES = "changed to protect the innocent";
Intent bluetoothBroadcast = new Intent();
several putExtra lines here
bluetoothBroadcast.setAction(NEW_DOSES);
sendBroadcast(bluetoothBroadcast);
<activity
android:name=".AsthmaAppActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Is it possible to get this intent to launch my main activity with relatively minor changes? Thanks in advance.
Yes it is possible but no with sendBroadcast(bluetoothBroadcast); sendBroadcast does not launch an activity. You must use startActivity to achieve this. For example here is what a launcher application will do in order to launch an application:
public static void LaunchApplication(Context cx, String packagename) {
PackageManager pm = cx.getPackageManager();
Intent i = pm.getLaunchIntentForPackage(ai.packageName);
if (i != null) cx.startActivity(i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
You can easily adjust the extras and the data needed in order to launch the activity. For example if your activity is named myActivity then you can go like this:
Intent i = new Intent(cx, myActivity.class);
//Put the extras and the data you want here...
//If you are launching the activity from a receiver component you must use
//i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
cx.startActivity(i);
Hope this helps...

Start Activity Using Custom Action

I am looking to start an activity in my app using a custom action. I have found a few answers but everything I try it throws java.lang.RuntimeException saying No Activity found to handle Intent { act=com.example.foo.bar.YOUR_ACTION }.
This is the activity in my manifest file:
<activity
android:name=".FeedbackActivity" >
<intent-filter>
<action android:name="com.example.foo.bar.YOUR_ACTION" />
</intent-filter>
</activity>
And this is how I'm starting the activity:
Intent intent = new Intent("com.example.foo.bar.YOUR_ACTION");
startActivity(intent);
Any help would be greatly appreciated.
I think what you need is to add a default category to your intent-filter,
eg.
<activity
android:name=".FeedbackActivity" >
<intent-filter>
<action android:name="com.example.foo.bar.YOUR_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
see this answer for more info.
I think you are creating your intent wrong. Try like this:
String CUSTOM_ACTION = "com.example.foo.bar.YOUR_ACTION";
//Intent i = new Intent(this, FeedBackActivity.class); // <--- You might need to do it this way.
Intent i = new Intent();
i.setAction(CUSTOM_ACTION);
startActivity(i);
Just add and intent-filter category as Default.
Implicit intent works perfectly and in many cases its better to use a implicit intent with Intent-action to call a service/Activity than using class-name.
Before startActivty() / startService() with proper context you cane use this method 'queryIntentActivities(Intent intent, int flags)' from package manager class.
It helps the ActivityManager (responsible for launching activities) to check whether the Android system is getting any match with you Intent.
If it doesn't it returns a list size 0 or else >0.
By this you can also check if your app is getting the call,and in this case even if your app is not installed / has got some problem, it will not crash but will throw a warning in Log. Users will face no big trouble apart from app not being launched.
(users will never forgive you if tour app crashes).
Hope this will help !!!
Happy Coding. :)
I faced the same problem when trying to launch the activity residing in the dynamic feature module and starting through action String as the Activity is not resolvable by name at compile time.
So I set the action but the activity crashes every time (No Activity found to handle intent bla bla.. ) until I set the correct package name.
Context c = getApplicationContext();// flag would be require Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag
Intent i = new Intent(action_string);
i.setPackage(context.getPackageName());//this did the trick actually
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
In the Manifest : add catrgory default to the intent filters
from google docs:
<category android:name="android.intent.category.DEFAULT"/>
Note: In order to receive implicit intents, you must include the CATEGORY_DEFAULT category in the intent filter. The methods startActivity() and startActivityForResult() treat all intents as if they declared the CATEGORY_DEFAULT category. If you do not declare it in your intent filter, no implicit intents will resolve to your activity.

Categories

Resources