Динамически установить родительскую активность
Таким образом, в настоящее время у меня есть действие, которое может быть достигнуто двумя различными действиями, проблема в том, что я могу установить только одно действие в качестве родительского действия в XML-файле манифеста. Очевидно, что это плохой дизайн UX/UI, потому что действие может отослать пользователя назад к неправильному действию, в котором он был ранее, и поэтому я пытаюсь динамически установить, какое действие является родительским действием.
Проблема в том, что я не совсем уверен, как это сделать, будь то код или XML, поэтому любые указатели приветствуются.:)
7 ответов
Здесь есть две концепции: "Вверх" и "Назад". "Назад" очевиден: отведи меня туда, где я был до того, как пришел сюда. Обычно вам не нужно беспокоиться о "Назад", так как система справится с этим просто отлично. "Вверх" не так очевидно - это аналог Zoom Out - от элемента к коллекции, от детализации к более широкой картине.
Что из этого подходит вашему варианту использования?
Согласно комментарию ниже: кнопка "вверх" извлекает пункт назначения из манифеста Android, но его можно настроить программно.
Для будущих читателей вот пример того, как на самом деле реализовать официальное / правильное решение согласно руководствам разработчика (выделите абзац, начинающийся с "Это подходит, когда родительское действие может отличаться... ").
Обратите внимание, что это решение предполагает использование библиотеки поддержки для реализации ActionBar
и что вы можете по крайней мере установить исходную активность "по умолчанию" в XML-файле манифеста в качестве откатной, если активность, из которой вы отказываетесь, находится в "задаче", которая не принадлежит вашему приложению (см. связанные документы для пояснения).
// Override BOTH getSupportParentActivityIntent() AND getParentActivityIntent() because
// if your device is running on API 11+ it will call the native
// getParentActivityIntent() method instead of the support version.
// The docs do **NOT** make this part clear and it is important!
@Override
public Intent getSupportParentActivityIntent() {
return getParentActivityIntentImpl();
}
@Override
public Intent getParentActivityIntent() {
return getParentActivityIntentImpl();
}
private Intent getParentActivityIntentImpl() {
Intent i = null;
// Here you need to do some logic to determine from which Activity you came.
// example: you could pass a variable through your Intent extras and check that.
if (parentIsActivityA) {
i = new Intent(this, ActivityA.class);
// set any flags or extras that you need.
// If you are reusing the previous Activity (i.e. bringing it to the top
// without re-creating a new instance) set these flags:
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
// if you are re-using the parent Activity you may not need to set any extras
i.putExtra("someExtra", "whateverYouNeed");
} else {
i = new Intent(this, ActivityB.class);
// same comments as above
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
i.putExtra("someExtra", "whateverYouNeed");
}
return i;
}
ПРИМЕЧАНИЕ. Если вы не зададите родительское действие по умолчанию в XML-файле манифеста, вам также потребуется реализовать onCreateSupportNavigateUpTaskStack(), поскольку система не будет знать, как сгенерировать backstack для вашей задачи. Я не привел ни одного примера для этой части.
Мои мысли о finish()
тип решения
В поисках решения этой проблемы я наткнулся на несколько ответов, которые защищают стратегию переопределения onOptionsItemSelected()
и перехват android.R.id.home
кнопка, чтобы они могли просто finish()
электрический ток Activity
вернуться к предыдущему экрану.
Во многих случаях это приведет к желаемому поведению, но я просто хочу отметить, что это определенно не то же самое, что правильная навигация UP. Если вы переходили к дочернему действию через одно из родительских занятий, то да finish()
вернет вас к предыдущему экрану, но что если вы введете дочернюю активность через уведомление? В таком случае finish()
Если вы нажмете кнопку "ВВЕРХ", вы вернетесь обратно на домашний экран или в любое приложение, которое вы просматривали до того, как нажмете уведомление, а вместо этого оно должно было отправить вас в соответствующую родительскую активность в вашем приложении.
Таким образом, вы можете динамически переходить к родительской активности:
getActionBar().setDisplayHomeAsUpEnabled(true);
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
ПРИМЕЧАНИЕ. Он перенаправляет вас на активность или фрагмент, откуда вы пришли, независимо от того, родитель это или нет. Нажатие на кнопку "вверх" / "вверх" на панели действий просто завершит текущее действие.
Метод для переопределения является getParentActivityIntent.
Вот мой код и отлично работает.
@Override
public Intent getParentActivityIntent() {
Intent parentIntent= getIntent();
String className = parentIntent.getStringExtra("ParentClassSource");
Intent newIntent=null;
try {
//you need to define the class with package name
newIntent = new Intent(OnMap.this, Class.forName(className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return newIntent;
}
От родительской деятельности;
Intent i = new Intent(DataDetailsItem.this, OnMap.class);
i.putExtra("ParentClassSource", "com.package.example.YourParentActivity");
startActivity(i);
Как правило, тип "подробный" вид деятельности должен обеспечивать навигацию "вверх", если он имеет вложенное / связанное содержимое. Система навигации "назад" обрабатывается системой, поэтому вам не нужно об этом беспокоиться.
Теперь для дополнительных усилий по поддержке навигации "вверх" есть несколько способов сделать это:
Активность, родительская активность которой определена в AndroidManifest.
Your Android Manifest --------------------- <activity android:name="com.example.app.DetailActivity" android:parentActivityName="com.example.app.MainActivity" > <meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.example.app.MainActivity" /> </activity> Your Detail Activity -------------------- @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: NavUtils.navigateUpFromSameTask(this); return true; } return super.onOptionsItemSelected(item); }
Это хорошо работает, если есть только одно родительское действие, означающее, что (DetailActivity) всегда запускается из (MainActivity). В противном случае это решение не будет работать, если (DetailActivity) запускается из разных мест. Подробнее здесь: http://developer.android.com/training/implementing-navigation/ancestral.html
(Проще и рекомендуется) Действия с фрагментом и бэк-стек фрагмента:
Your Detail Activity -------------------- protected void replaceFragment(Bundle fragmentArguments, boolean addToBackStack) { DetailFragment fragment = new DetailFragment(); fragment.setArguments(fragmentArguments); // get your fragment manager, native/support FragmentTransaction tr = fragmentManager.beginTransaction(); tr.replace(containerResId, fragment); if (addToBackStack) { tr.addToBackStack(null); } tr.commit(); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: finish(); return true; } return super.onOptionsItemSelected(item); }
В этом решении, если пользователь нажимает "назад", фрагмент будет извлечен из обратного стека фрагмента, и пользователь будет возвращен к предыдущему фрагменту, оставаясь при этом в том же действии. Если пользователь нажимает "вверх", действие прекращается, и пользователь возвращается к предыдущему действию (являющемуся родительским действием). Ключевым моментом здесь является использование фрагмента в качестве пользовательского интерфейса, а действия - в качестве хоста фрагмента.
Надеюсь это поможет.
Чтобы узнать, как правильно использовать Навигацию вверх, см. Это Android Dev Guide.
Обратите внимание, что в приведенном выше Руководстве по разработке Android есть большой недостаток, поскольку функции NavUtils работают по-разному для ICS(и ниже) и JellyBean(и выше). Этот недостаток в NavUtils прекрасно объясняется здесь.
Вы можете переопределить кнопку "Вверх", чтобы действовать как кнопка "Назад" следующим образом:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
Котлин 2020
Мое действие запускается из разных действий, поэтому AndroidManifest работает только с одним родительским действием.
Вы можете вернуться к предыдущему действию следующим образом:
supportActionBar?.setDisplayHomeAsUpEnabled(true)
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when(item!!.itemId){
android.R.id.home -> {
finish()
return true
}
}
return super.onOptionsItemSelected(item)
}
Вам нужно будет отслеживать родительскую активность. Один из способов сделать это - сохранить его как дополнительное в намерении, которое вы создаете для запуска дочернего действия). Например, если действие A запускает действие B, сохраните намерение A в намерении, созданном для B. Затем в B onOptionsItemSelected
где вы обрабатываете навигацию вверх, извлекаете намерение А и запускаете его с нужными флагами намерений.
Следующий пост имеет более сложный сценарий использования с цепочкой дочерних активностей. Он объясняет, как вы можете перейти к тому же или новому экземпляру родителя и завершить промежуточные действия при этом.
Навигация по Android вверх для Действия с несколькими родителями