I have developed a new release of an application and I have changed the name of the activity which is launched.
Before the upgrade, in the manifest was:
<activity
android:name=".Splash"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#android:style/Theme.NoTitleBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
and then I only changed the name and the package of the activity and now it is:
<activity
android:name=".view.SplashActivity"
... >
...
</activity>
what happens is that after people download the application from the market, the launcher is not refreshing and it still calls to the old path to the activity.
Do you know how to solve this?
Refer Things That Cannot Change
It says,
A subtle but important aspect of what constitutes a break in compatibility is the android:name attribute of your activity, service, and receiver components. This can be surprising because we think of android:name as pointing to the private code implementing our application, but it is also (in combination with the manifest package name) the official unique public name for that component, as represented by the ComponentName class.
Changing the component name inside of an application can have negative consequences for your users. Some examples are:
If the name of a main activity of your application is changed, any shortcuts the user made to it will no longer work. A shortcut is an Intent that directly specifies the ComponentName it should run.
If the name of a service implementing a Live Wallpaper changes, then a user who has enabled your Live Wallpaper will have their wallpaper revert to the system default when getting the new version of your app. The same is true for Input Methods, Accessibility Services, Honeycomb’s new advanced Widgets, and so on.
If the name of a receiver implementing a Device Admin changes, then as with the live wallpaper example, the device admin will be disabled when the application is updated. This also applies to other kinds of receivers, such as App Widgets.
So if possible, don't change the name of components declared in the manifest, or remove any icon pointing to that component using below code.
ComponentName componentToDisable = new ComponentName("application.package.name", "packagename.ActivityClassName");
getPackageManager().setComponentEnabledSetting(componentToDisable, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Also specify new launcher activity in manifest using <intent-filter>...</intent-filter> so that your new activity will be launched when user clicks launcher icon.
Does the activity is called correctly if you start the activity in debug mode on your phone.
If so check if you did something of the following:
you changed the whole package name
you signed it not at all or not correctly
Also you might check out http://developer.android.com/guide/publishing/publishing_overview.html
Anyway. If the application runs correctly on your debugging phone there is something wrong with your publishing parameters and you should go through the page above step by step.
If not you might check the path values, like package and name of the activity and the filters.
Related
I have an Android application in Android Studio. And I've added a library into the application. The button, view, and activities are defined in the library. When I click on the button, I need to navigate to the activity defined in the application.
Usually, to navigate to another page, we used the intent, like this:
Intent intent = new Intent(MainActivity.this, Activity.class);
startActivity(intent);
But this is not a sufficient method to call the activity of the application from the library.
The problem is that the library and the application are independent; they have different packages. So the activity in the application cannot be recognized by the library.
How do I handle communication between the library and the application?
The normal way for doing this is to do this:
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.my.package","com.my.package.activity.ActivityName");
startActivity(intent);
This is an explicit reference to an activity within your library. You should ensure that when starting this Activity that you catch the ActivityNotFoundException as this can happen when the Activity does not exist in the system.
Ideally when building this Intent you should insure that you can resolve it by using PackageManager APIs.
However you should try to avoid hardcoding packages, but when it comes to a library, sometimes you don't have a choice.
Also one thing to note is that within the library you need to ensure that the Activity is exported so that you can access it outside of your application.
android:exported
Whether or not the activity can be launched by
components of other applications — "true" if it can be, and "false" if
not. If "false", the activity can be launched only by components of
the same application or applications with the same user ID. The
default value depends on whether the activity contains intent filters.
The absence of any filters means that the activity can be invoked only
by specifying its exact class name. This implies that the activity is
intended only for application-internal use (since others would not
know the class name). So in this case, the default value is "false".
On the other hand, the presence of at least one filter implies that
the activity is intended for external use, so the default value is
"true".
This attribute is not the only way to limit an activity's exposure to
other applications. You can also use a permission to limit the
external entities that can invoke the activity (see the permission
attribute).
Ref
http://developer.android.com/guide/topics/manifest/activity-element.html
Include the activity in AndroidManifest.xml.
To access an activity from any other project the easiest way is to
pass the whole class name (including package, e.g;
"com.myproject.MainActivitiy")
Calling from your library :
Intent intent= new Intent("com.myproject.MainActivitiy");
startActivity(intent);
And in your project manifest declare it like this
<activity
android:name="com.myproject.MainActivitiy"
android:label="#string/app_name" >
<intent-filter>
<action android:name="com.myproject.MainActivitiy" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
In this case, Intent can be used by providing the full class name including the package.
Let us suppose your current Activity class is MainActivity.java with package name com.app.myproject.
And you want to navigate to another Activity with class named Activity.java that is in another package com.app.external.
Include com.app.external.Activity.java in the manifest of your current project/library.
<activity
android:name="com.app.external.Activity"
android:label="#string/title_activity_login"
android:screenOrientation="portrait">
</activity>
And your Intent should be like this -
Intent intent = new Intent(MainActivity.this, com.app.external.Activity.class);
startActivity(intent);
In this case use Implicit Intent
Inside library Activity TESTActivity :
Intent intent = new Intent();
intent.setAction("com.myapp.myimplicit_action");
startActivity(intent);
and here is my manifest file declaration for some activity say 'ImplicitActivity' with the same action
<activity android:name=".ImplicitActivity">
<intent-filter>
<action android:name="com.myapp.myimplicit_action" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
“My First App” has an activity that handles a “share” intent. Its activity in AndroidManifest.xml looks like this:
<activity
android:name="com.example.foo.myfirstapp.MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/jpeg"/>
</intent-filter>
</activity>
In KitKat, sharing an image from the album to “My First App” causes MainActivity to be part of the album’s task. This is the desired behavior.
In Lollipop, sharing an image from the album to “My First App” causes a new instance of “My First App” to be launched. If I look at the overview screen, the album task is there...and then there's a separate entry for "My First App". If I share another image, I wind up with two instances of "My First App"...etc.
Question: How do I make Lollipop process the share intent in the same way as KitKat?
Here's what I've done:
I notice that the intents sent from the Album have different flags set depending on the OS. (I got these using getIntent() and looking at mFlags.)
Kitkat: 0x80001 (524289): FLAG_GRANT_READ_URI_PERMISSION, FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
Lollipop: 0x18080001 (403177473): FLAG_GRANT_READ_URI_PERMISSION, FLAG_ACTIVITY_MULTIPLE_TASK, FLAG_ACTIVITY_NEW_DOCUMENT, FLAG_ACTIVITY_NEW_TASK
From reading http://developer.android.com/reference/android/content/Intent.html, it seems that these last three flags are causing the problem. Specifically
When paired with FLAG_ACTIVITY_MULTIPLE_TASK both of these behaviors (FLAG_ACTIVITY_NEW_DOCUMENT or FLAG_ACTIVITY_NEW_TASK) are modified to skip the search for a matching task and unconditionally start a new task.
I’ve been attempting to “override” these flags by specifying android:launchMode and android:documentLaunchMode in the activity in AndroidManifest.xml without success.
From http://developer.android.com/reference/android/R.attr.html#documentLaunchMode, using documentLaunchMode “never” seems promising, since
This activity will not be launched into a new document even if the Intent contains Intent.FLAG_ACTIVITY_NEW_DOCUMENT. This gives the activity writer ultimate control over how their activity is used.
but this didn't work.
I also considered android:taskAffinity, but there doesn’t seem to be a way to say “please prefer whatever task launched you”.
Afraid you can't do anything about this. It isn't under your control. This is a change in the way the "Album" app is launching its "share" Intent. If it doesn't want your Activity in its task, you can't force it in there.
If you have issues with having multiple instances of your "share" activity, you could declare your "share" activity as launchMode="singleTask" or launchMode="singleInstance" (depending on your needs. This may, however, break other things.
I'm in the process of trying to make a release build of my first android app to send to a few testers. However, I ran into a problem with it. When you exit the app and then re-enter it by launching it via its icon, it restarts the whole app instead of returning to it's previous location. This occurs even if you re-enter right after exiting. However, it does not happen if I hold the Home button and launch it through the recent apps list.
I've searched online for others having this problem and there are a few, but no one has ever had a solid answer as to why it's happening to them. It's been suggested in old questions to set the launchmode to singletask or singleinstance in the manifest file, but that hasn't helped me, and besides - from what I understand, the default behavior for android is to return to the previous state of the task in this situation, so I don't know why I would need special manifest options to make it do that.
The most bizarre thing about this problem is that if I use eclipse and the debugger to put the app on my phone, this problem does not occur. I don't even need to be connected to the debugger, it seems like as long as I have a debug version of the app, the problem doesn't occur. But if I use a release version (I create it using the Android Tools - Export Signed Application Package menu option in Eclipse), the problem happens.
If anyone has any insight as to what is causing this, I'd love to hear your thoughts.
I had the same problem with an application and I resolved this behavior adding flag "android:launchMode="singleTop"" instead of "android:launchMode="singleTask"" in the <activity> declaration of your AndroidManifest.xml file. Hope this will help somebody.
So far I've found out that it's an issue based on how you install it in your real device, specifically:
If you simply copy and paste the APK to your device's local storage and install it from the device, regardless of whether it's signed or unsigned or taken from bin folder, it shows this behavior, app restarts from menu icon.
If you install it using one of the following options, This issue does not appear:
Go to sdk/tools/ using a terminal or command prompt then type
adb install <FILE PATH OF .APK FILE>
In Linux, type:
./adb install <FILE PATH OF .APK FILE>
Simply run your project from Eclipse.
I would be pleased to know if there's any possible way to distribute correct APKs for beta testing. I already tried exporting a signed APK because when you copy and paste an APK and install it manually it shows the rogue behavior.
Update:
I found out a solution. Follow these two Steps:
Set android:launchMode="singleTask" = true for all activities of your app in the AndroidMainifest.xml inside the activity tag.
Put this code in your Launcher Activity's onCreate().
if (!isTaskRoot())
{
final Intent intent = getIntent();
final String intentAction = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
finish();
return;
}
}
This behavior is a bug in Android. Not a special case.
// To prevent launching another instance of app on clicking app icon
if (!isTaskRoot()
&& getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)
&& getIntent().getAction() != null
&& getIntent().getAction().equals(Intent.ACTION_MAIN)) {
finish();
return;
}
write the above code in your launcher activity before calling setContentView. This will solve the problem
You could use launchMode as singleTop to the Launcher Activity in AndroidManifest.xml
<activity
android:name="<YOUR_ACTIVITY>"
android:label="#string/app_name"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
It is the default behavior in Android. For the debug builds it works differently for some reason. It can be solved by adding android:launchMode="singleInstance" to the activity, you want to restart after you launch from the icon.
Add this to your first activity:
if (!isTaskRoot()) {
finish();
return;
}
super.onCreate(savedInstanceState);
Try using android:alwaysRetainTaskState as shown in the following example:
<activity
android:name="com.jsnider.timelineplanner.MainActivity"
android:alwaysRetainTaskState="true"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
For me, I found that I had erroneously posted NoHistory = true in my activity attribute
[Activity(NoHistory = true, ScreenOrientation = ScreenOrientation.Landscape)]
This prevented the app resuming into this activity and restarted
You can try to set android:alwaysRetainTaskState="true" for your launcher activity in AndroidManifest.xml.
<activity
android:name=".YourMainActivity"
android:alwaysRetainTaskState="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
For details you can see https://developer.android.com/guide/topics/manifest/activity-element.html#always
I see this issue on Android TV in 2019. Is there a better fix for it? other than
if (!isTaskRoot()) {
finish();
}
It works but looks like a hack more than the actual solution.
All of the solutions above didn't work consistently on all of my devices. It worked on some Samsung but not all.
The cause of the problem for me was installing the APK manually.
For me the fix was adding LaunchMode = LaunchMode.SingleTop to my Activity attribute over the Main Activity:
/// <summary>
/// The main activity of the application.
/// </summary>
[Activity(Label = "SilhuettePhone",
Icon = "#drawable/icon",
Theme = "#style/MainTheme",
MainLauncher = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Portrait,
LaunchMode = LaunchMode.SingleTop,
WindowSoftInputMode = SoftInput.AdjustResize)]
I had a problem with a restarting app, my problem was in themes:
I have differents fragments and I would have one background for all. But this cause a restarting app in some devices(.
I've deleted this line in themes and this helped:
item name ="android:windowBackground">#drawable/background /item
Removing task affinity rather than launch mode has worked somewhat for as it has its own demerits
When you press the back button in Android, the onDestroy method is invoked (as opposed to pressing the home button, where only the onPause() method is invoked).
If you need your app to continue where it left off, save the state of the app in your onDestroy() method and load that state in the onCreate() method.
The documentation says you can specify a custom category.
When, why and how would you do it?
What would be the use of it?
The way I understand it, categories are public directives to the android operating system(and other apps) that represent different categories that your app should be a part of.
Example
When the launcher icon is tapped on the home screen, the home application looks through every installed app's manifest for the HOME category -- and if so it displays it in the app drawer.
However, there's more. You can specify categories in your applications manifest that lets the system know that you application can handle the intent category. For example, by putting a ALTERNATIVE category, other apps in the system know that your app can handle that category without specifically knowing the action name! In the following example, custom intent categories are passed through this intent, which is filtered and the corresponding object gets edited(taken from the Notes example app):
<intent-filter android:label="#string/resolve_title">
<action android:name="com.android.notepad.action.EDIT_TITLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
By registering this intent filter in an <activity /> tag, you can edit a "note". The intent data would contain the note, and the intent would get routed to the activity that this filter is registered in.
In Conclusion:
There isn't really a reason you'd use a custom category. They are for Android, and thus don't really make sense in application use. But, if you choose to use them, they can be used in the methods described above. "They provide some specific semantic rules, and if those rules are useful to you then feel free to use them"(Hackbod).
http://developer.android.com/guide/topics/intents/intents-filters.html
Scroll down a bit and you should see a section under "Intent Objects"
They basically describe certain special properties of an activity. for example, adding
<category android:name="android.intent.category.HOME" />
means that the app can be started on the phone's bootup
I'm kinda a noob to Android still, although I have programming experience otherwise.. It says a custom category in your own namespace. I'm guessing that if you are programming multiple apps and you want one app to run another app, you could use a custom category for your intent to force the phone to find your other app to catch the intent with?
When you do not want to use the default category then use the custom category.
Custom categories should use the package name as a prefix, to ensure that they are unique.
Some information is provided on below link:
http://developer.android.com/guide/topics/manifest/category-element.html
Check the below link it has somewhat same question:
Android custom categories
In my application, I have specified a second activity that can be launched from the launcher, using this manifest entry:
<activity
android:name=".Lists.ListOfListsActivity"
android:icon="#drawable/ic_launcher_lists"
android:launchMode="singleTop"
android:label="#string/lists_activity_name" >
<!-- An Intent filter so that the Lists activity shows in the Launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Let's say I have the app open at the "main" activity then press the home key. My app will still be running, but in background.
Later the user selects the launcher icon I have for "ListsOfListsActivity" from the homescreen.
This will bring the application to the foreground, but NOT at the "ListOfListsActivity", but at whatever it's current activity was when it went to the background (e.g. at the "main"activity).
This is confusing, as the user selected the "ListOfListsActivity" but is shown another one. Then they have to navigate to it.
I had this working better, by specifying launchMode = "singleTask" for the "ListOfListsActivity", but in that mode it cannot be launched from another activity for a result (startActivityForResult() ), and I need to be able to do that to pick a list...
Question:
- how to specify an intent-filter that will force an activity to the foreground and be the selected activity, no matter what the current status of the application and it's current activity??
My final implementation was to define a different taskAfinity string for each activity I wanted to launch independently from the Launcher.
That way, each "shortcut" always launches the activity I want, but the downside that I have not been able to avoid is that the user may have multiple tasks with an activity from my application in it, and maybe the same activity open/active in different tasks....