Ответ 1
http://code.google.com/p/android/issues/detail?id=63570#c2
это было подтверждено google как ошибка в 4.4.2
Действие A запускает действие B без флагов. Стек теперь A-B с B сверху. B начинает активность A с FLAG_ACTIVITY_REORDER_TO_FRONT (единственным флагом). Я ожидаю, что теперь стек будет B-A. Однако при нажатии кнопки "Назад" в этот момент он возвращается к главному экрану. Здесь я ожидаю, что активность B будет перенесена на фронт. При повторном нажатии на значок запуска приложение открывается с помощью B в качестве текущей активности и ничего в стеке.
Launchmode является стандартным (по умолчанию) в манифесте.
Является ли это ожидаемым поведением, и я просто не понимаю его правильно?
EDIT: Я создал тестовый проект без каких-либо смешающих факторов и все еще вижу такое же поведение. Я просто этого не понимаю, похоже, это не соответствует документации.
РЕДАКТИРОВАТЬ: Мне кажется, что это поведение является ошибкой в структуре, см. мой комментарий к ответу ниже. Мне нужно обходное решение.
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void onClickBtn(View view)
{
Intent flowIntent = new Intent(this, SecondActivity.class);
startActivity(flowIntent);
}
}
открытый класс SecondActivity расширяет активность { @Override protected void onCreate (Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView (R.layout.activity_second); }
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void onClickBtn(View view)
{
Intent flowIntent = new Intent(this, MainActivity.class);
flowIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(flowIntent);
}
} код >
манифеста:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tester"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.tester.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.tester.SecondActivity" />
</application>
</manifest>
http://code.google.com/p/android/issues/detail?id=63570#c2
это было подтверждено google как ошибка в 4.4.2
Прежде всего, давайте начнем с того, что вы правы!
Но если моя логика правильная, то что произойдет, когда вы REORDER
на ваш основной Activity
(Launcher
Activity
), Intent установлен так, что обратное нажатие вернет вас к Launcher
.
В качестве эксперимента попробуйте добавить Activity
C и попробуйте REORDER
B спереди от C.
Это:
A- > B- > C... A- > C- > B
Если порядок очень важен для вас, вам может потребоваться переопределить метод Activity.onNewIntent().
@Override
protected void onNewIntent(Intent intent) {
}
Я нашел простой способ обхода этой ошибки.
Переопределить onNewIntent и завершить функции любого из них могут переупорядочиваться на переднюю активность, так как следующее будет делать трюк, просто не полностью экзамен, если вы обнаружите какую-либо проблему для этого обходного пути, пожалуйста, свяжитесь со мной по [email protected]
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if ((intent.getFlags() | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) > 0) {
mIsRestoredToTop = true;
}
}
@Override
public void finish() {
super.finish();
if (android.os.Build.VERSION.SDK_INT >= 19 && !isTaskRoot() && mIsRestoredToTop) {
// 4.4.2 platform issues for FLAG_ACTIVITY_REORDER_TO_FRONT,
// reordered activity back press will go to home unexpectly,
// Workaround: move reordered activity current task to front when it finished.
ActivityManager tasksManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
tasksManager.moveTaskToFront(getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION);
}
}
Я не мог найти эту проблему вообще. Вот проект, который я создал.
Я только что переопределил метод Finish(), чтобы проверить, какая активность закрыта.
Я столкнулся с этой ошибкой и решил, что мне, возможно, придется обойти это. И, по крайней мере, в моем случае это кажется возможным, предоставляя пользовательскую реализацию back stack для версии 4.4.2. Это ни в коем случае не симпатично и может не работать во всех ситуациях, но это спасло меня и мою навигацию на основе DrawerLayout
.
Во-первых, у меня есть NavigationDrawerActivity
как класс, который распространяется на все остальные действия. Там у меня есть статический Stack
для вызываемых классов, а также массив классов, к которым можно получить доступ из навигационного ящика. Метод addClassToStack
является общедоступным, так что другие средства навигации, кроме ящика, также могут использовать стек. Обратите внимание, что класс, который должен быть добавлен в стек, сначала удаляется (если он существует), так что мы получаем ту же функциональность, что и нормальный флаг переупорядочения. Я окружил взломанный код проверками версий, чтобы хак использовался только при необходимости.
public class NavigationDrawerActivity extends Activity {
...
private static Stack<Class<?>> classes = new Stack<Class<?>>();
private Class<?>[] activity_classes;
...
public static void addClassToStack(Class<?> to_add) {
if (android.os.Build.VERSION.RELEASE.equals("4.4.2")) {
classes.remove(to_add);
classes.push(to_add);
}
}
...
Далее - класс слушателя для навигационного ящика. Кнопки на моем ящике находятся в ListView
, поэтому каждый раз, когда пользователь хочет куда-то пойти, здесь будет вызываться onItemClick
. Единственная "хакерская" вещь - вызов addClassToStack
для добавления нового действия в качестве вершины заднего стека.
private class DrawerItemClickListener implements ListView.OnItemClickListener {
private Intent i;
@Override
public void onItemClick(AdapterView<?> parent, View v, int pos, long id) {
i = new Intent(NavDrawerActivity.this, activity_classes[pos]);
addClassToStack(activity_classes[pos]);
i.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
nav_drawer.closeDrawers();
startActivity(i);
}
}
Последняя часть обходного пути заключается в переопределении метода onKeyDown
, и в случае нажатия кнопки "Назад" на Android 4.4.2 (и мы вышли за рамки первого действия в нашей навигации), активность, которую нужно открыть, выбирается из нашего пользовательского back stack и вызывается напрямую. Обратите внимание, что самый верхний элемент в стеке всегда является текущей деятельностью, и поэтому нам нужно избавиться от этого и использовать второй в качестве цели. Также обратите внимание, как я очищаю официальную историю задач, когда возвращаюсь к первому действию. Это требовалось, потому что в противном случае, после повторного нажатия и возвращения на главный экран, в следующий раз, когда приложение было обращено к нему, оно переместилось прямо в верхнюю часть официального стека.
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean handled = false;
if (keyCode == KeyEvent.KEYCODE_BACK &&
android.os.Build.VERSION.RELEASE.equals("4.4.2") &&
classes.size() > 1) {
classes.pop();
Intent prev = new Intent(this, classes.peek());
if (classes.size() == 1) {
prev.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
} else {
prev.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
}
startActivity(prev);
handled = true;
}
if (!handled) {
return super.onKeyDown(keyCode, event);
} else {
return true;
}
}
}
Единственное, что осталось (и не показано здесь), это добавить начальную активность (ту, которая открывается при запуске приложения) в задний стек отдельно в соответствующем месте. В моем приложении у меня есть отдельный экран запуска, который недоступен через ящик навигации, поэтому я могу вызвать NavigationDrawerActivity.addClassToStack(StartScreenActivity.class)
из этого действия onCreate. Для других структур вы можете сделать что-то другое, чтобы убедиться, что начальная активность добавляется в стек только один раз в качестве самого первого элемента.
Теперь это хак и тот, который я еще не тестировал очень тщательно, но, похоже, работает на Nexus 4 (4.4.2) и на Nexus S (застрял на 4.1). Поэтому, если вы попытаетесь сделать что-то подобное, и это не сработает, не сердитесь, но дайте мне знать.:)
Я вижу, что эта проблема происходит на ОС S7 7.0, где, когда активность задана с помощью Flag Intent.FLAG_ACTIVITY_REORDER_TO_FRONT, и это действие завершается, Пользователь переводится на главный экран устройства.
Исправьте, я вложил для этого - удалил флаг Intent.FLAG_ACTIVITY_REORDER_TO_FRONT и добавил noHistory = true
Таким образом, новый экземпляр активности попадает в стек, а поскольку noHistory истинна, старый экземпляр, который уже является частью стеков, уничтожается.