Функция base reshape
работает отлично:
df <- data.frame(
year = c(rep(2000, 12), rep(2001, 12)),
month = rep(1:12, 2),
values = rnorm(24)
)
df_wide <- reshape(df, idvar="year", timevar="month", v.names="values", direction="wide", sep="_")
df_wide
Здесь idvar
- столбец классов, который разделяет строки, timevar
- столбец классов, который должен быть широко представлен, v.names
- это столбец, содержащий числовые значения, direction
указывает широкий или длинный формат, а необязательный аргумент sep
- это разделитель, используемый между именами классов timevar
и v.names
на выходе data.frame
. Если нет idvar
, создайте его перед использованием функции reshape()
:
df$id <- c(rep("year1", 12), rep("year2", 12))
df_wide <- reshape(df, idvar="id", timevar="month", v.names="values", direction="wide", sep="_")
df_wide
Просто помните, что требуется idvar
! Часть timevar
и v.names
проста. Выход этой функции более предсказуем, чем некоторые другие, поскольку все явно определено.
В моем случае, с тем же исключением, я помещаю «onBackPressed ()» в runnable (вы можете использовать любое ваше представление):
myView.post(new Runnable() {
@Override
public void run() {
onBackPressed()
}
});
Я не понимаю, почему, но он работает!
Прочтите http://chris-alexander.co.uk/on-engineering/dev/android-fragments-within-fragments/
статью. fragment.isResumed () помогает мне в onDestroyView без использования метода onSaveInstanceState.
Это происходит всякий раз, когда вы пытаетесь загрузить фрагмент, но действие изменило его состояние на onPause (). Это происходит, например, когда вы пытаетесь извлечь данные и загрузить их в действие, но к тому времени, когда пользователь нажал некоторые и переместился в следующую операцию.
Вы можете решить это двумя способами.
Вы можете использовать transaction.commitAllowingStateLoss () вместо transaction.commit () для загрузки фрагмента, но вы можете
или
Убедитесь, что активность возобновлена и не будет приостанавливаться при загрузке фрагмента. Создайте логическое значение и проверьте, не работает ли действие onPause ().
@Override
public void onResume() {
super.onResume();
mIsResumed = true;
}
@Override
public void onPause() {
mIsResumed = false;
super.onPause();
}
, а затем при загрузке фрагмента проверяет, присутствует ли активность и загружается, только когда активность является приоритетной.
if(mIsResumed){
//load the fragment
}
Хорошо, пробовав все вышеперечисленные решения без успеха (потому что в основном у меня нет транзакций).
В моем случае я использовал AlertDialogs и ProgressDialog в качестве фрагментов, которые иногда, при ротации, при запросе FragmentManager, ошибка возрастает.
Я нашел обходное решение, смешивающее несколько подобных сообщений:
. Это трехэтапное решение, сделанное на вашем FragmentActivity (в данном случае его называемое GenericActivity ):
private static WeakReference<GenericActivity> activity = null; //To avoid bug for fragments: Step 1 of 3
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//To avoid bug for fragments: Step 2 of 3
activity = new WeakReference<GenericActivity>(this);
}
@Override
public FragmentManager getSupportFragmentManager(){
//To avoid bug for fragments: Step 3 of 3
if (this == activity.get()) {
return super.getSupportFragmentManager();
}
return activity.get().getSupportFragmentManager();
}
Я всегда получал это, когда пытался показать фрагмент в методе onActivityForResult (), поэтому проблема была следующей:
То, что я сделал, следующее:
Краткое и рабочее решение:
Выполнять простые шаги:
Шаг 1: переопределить состояние onSaveInstanceState в соответствующем фрагменте. И удалите из него супер-метод.
@Override
public void onSaveInstanceState(Bundle outState) {
};
Шаг 2: Используйте CommitAllowingStateLoss (); вместо commit (); в то время как операции фрагмента.
fragmentTransaction.commitAllowingStateLoss();
вы можете использовать FragmentActivity.onStart перед popBackStackImmediate
следующим образом:
public void backStackFragment() {
this.start();
getFragmentManager().popBackStackImmediate();
}
public void start(){
FragmentActivity a = getActivity();
if(a instanceof DepositPlanPadActivity){
((DepositPlanPadActivity)a).onStart();
}
if(a instanceof SmallChangePlanPad){
((SmallChangePlanPad)a).onStart();
}
if(a instanceof UserCenterActivity){
((UserCenterActivity)a).onStart();
}
}
http://jorryliu.blogspot.com/2014/09/illegalstateexception- может-не-perform.html
Это также может случиться при вызове dismiss()
в фрагменте диалога после того, как экран был заблокирован \ blanked и состояние экземпляра диалога Activity + сохранено. Чтобы обойти этот вызов:
dismissAllowingStateLoss()
Буквально каждый раз, когда я увольняю диалог, я все равно не забочусь о его состоянии, так что это нормально делать - вы на самом деле не проигрываете любое состояние.
Я обнаружил, что если другое приложение является типом диалога и позволяет прикоснуться к фону, то почти любое фоновое приложение будет сбой с этой ошибкой. Я думаю, нам нужно проверять каждый раз, когда транзакция выполняется, если экземпляр был сохранен или восстановлен.
Это исправлено в Android 4.2, а также в источнике библиотеки поддержки. [*]
Подробнее о причине (и обходах) см. отчет об ошибке Google: http : //code.google.com/p/android/issues/detail? id = 19917
Если вы используете библиотеку поддержки, вам не придется беспокоиться об этой ошибке (надолго)[*]. Однако, если вы используете API напрямую (т. Е. Не используете FragmentManager библиотеки поддержки) и ориентируетесь на API под Android 4.2, вам нужно попробовать один из рабочих обходов.
[*] На время написания Android SDK Manager по-прежнему распространяет старую версию, которая показывает эту ошибку.
Редактировать. Я собираюсь добавить некоторые пояснения здесь, потому что я, очевидно, каким-то образом смутил того, кто проголосовал за этот ответ.
Существует несколько разных (но связанных) обстоятельств, которые могут вызвать выброс этого исключения. Мой ответ выше относится к конкретному экземпляру, обсуждаемому в вопросе i.e, ошибка в Android, которая впоследствии была исправлена. Если вы получаете это исключение по другой причине, это связано с тем, что вы добавляете / удаляете фрагменты, когда вам не следует (после сохранения состояний фрагмента). Если вы находитесь в такой ситуации, то, возможно, « Вложенные фрагменты - IllegalStateException» Невозможно выполнить это действие после того, как onSaveInstanceState «» может вам пригодиться.
commitAllowingStateLoss()
устраняет исключение. Он не защищает ваше приложение от случайной потери состояния. См. Это сообщение в блоге .
– Alex Lockwood
21 August 2013 в 00:20
У меня такая же проблема в моем приложении. Я решил эту проблему, просто вызвав super.onBackPressed();
в предыдущем классе и вызвав commitAllowingStateLoss()
в текущем классе с этим фрагментом.
commitAllowingStateLoss()
вместо commit()
– Chintak Patel
21 August 2017 в 06:51
Я получал это исключение, когда я нажимал кнопку «Назад», чтобы отменить намерение выбора на моей активности фрагмента карты. Я решил это, заменив код onResume () (где я инициализировал фрагмент и совершил транзакцию) на onStart (), и теперь приложение работает нормально. Надеюсь, что это поможет.
onSaveInstance будет вызываться, если пользователь поворачивает экран, чтобы он мог загружать ресурсы, связанные с новой ориентацией.
Возможно, этот пользователь повернул экран, а затем нажал кнопку «Назад» (потому что это также возможно, что этот пользователь вошел в свой телефон при использовании вашего приложения)
Мой вариант использования: я использовал прослушиватель в фрагменте, чтобы уведомить активность о том, что произошло что-то. Я сделал новую фиксацию фрагмента по методу обратного вызова. Это работает отлично в первый раз. Но при изменении ориентации активность воссоздается с сохраненным состоянием экземпляра. В этом случае фрагмент не создается снова, подразумевает, что в фрагменте есть слушатель, который является старым разрушенным действием. В любом случае метод обратного вызова будет активирован при действии. Это связано с разрушенной деятельностью, которая вызывает проблему. Решением является сброс слушателя в фрагменте с текущей активностью. Это решает проблему.
Глядя в исходный код Android на то, что вызывает эту проблему, этот флаг mStateSaved в классе FragmentManagerImpl
(экземпляр доступен в Activity) имеет значение true. Он установлен в true, когда задний стек сохраняется (saveAllState) при вызове из Activity#onSaveInstanceState
. После этого вызовы из ActivityThread не сбрасывают этот флаг, используя доступные методы сброса из FragmentManagerImpl#noteStateNotSaved()
и dispatch()
.
Как я вижу, есть некоторые доступные исправления, в зависимости от того, что делает ваше приложение, и используя:
Прежде всего: я бы рекламировал статью Алекс Локвуда . Затем, из того, что я сделал до сих пор:
commit()
), сделайте вызов FragmentManager.executePendingTransactions()
. super.onSaveInstanceState()
. Но это означает, что вы потеряете все состояние своей активности вместе с состоянием фрагментов. onBackPressed
и там вызывать только finish()
. Это должно быть ОК, если приложение не использует API фрагментов; как в super.onBackPressed
есть вызов FragmentManager#popBackStackImmediate()
. FragmentManagerImpl#noteStateNotSaved()
. Но это хак, или можно сказать, что это обходной путь. Мне это не нравится, но в моем случае это вполне приемлемо, поскольку у меня есть код из унаследованного приложения, в котором используется устаревший код (TabActivity
и неявно LocalActivityManager
). Ниже это код, который использует отражение:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
invokeFragmentManagerNoteStateNotSaved();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void invokeFragmentManagerNoteStateNotSaved() {
/**
* For post-Honeycomb devices
*/
if (Build.VERSION.SDK_INT < 11) {
return;
}
try {
Class cls = getClass();
do {
cls = cls.getSuperclass();
} while (!"Activity".equals(cls.getSimpleName()));
Field fragmentMgrField = cls.getDeclaredField("mFragments");
fragmentMgrField.setAccessible(true);
Object fragmentMgr = fragmentMgrField.get(this);
cls = fragmentMgr.getClass();
Method noteStateNotSavedMethod = cls.getDeclaredMethod("noteStateNotSaved", new Class[] {});
noteStateNotSavedMethod.invoke(fragmentMgr, new Object[] {});
Log.d("DLOutState", "Successful call for noteStateNotSaved!!!");
} catch (Exception ex) {
Log.e("DLOutState", "Exception on worka FM.noteStateNotSaved", ex);
}
}
Приветствия!
Такое исключение произойдет, если вы попытаетесь выполнить переход фрагмента после вызова функции фрагмента onSaveInstanceState()
.
Одна из причин, по которой это может произойти, - это если вы оставите AsyncTask
(или Thread
) запущенным при прекращении действия.
Любые переходы после вызова onSaveInstanceState()
потенциально теряется, если система восстанавливает активность ресурсов и воссоздает ее позже.
super.onSaveInstanceState()
.
– Alex Lockwood
16 August 2013 в 16:27
После небольшого исследования решение этой проблемы состоит в том, чтобы сделать ваш фрагмент зафиксированным в onresume.
Источник: https://wenchaojames.wordpress.com/2013/01/12/ IllegalStateException-из-onactivityresult /
Я думаю, что состояние Lifecycle может помочь предотвратить такой крах, начиная с поддержки Android v26.1.0, у вас может быть следующая проверка:
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)){
// Do fragment's transaction commit
}
или вы можете попробовать:
Fragment.isStateSaved()
дополнительная информация здесь https://developer.android.com/reference/android/support/v4/app/Fragment.html#isStateSaved ()
Спасибо @gunar, но я думаю, что есть лучший способ.
Согласно doc:
blockquote>* If you are committing a single transaction that does not modify the * fragment back stack, strongly consider using * {@link FragmentTransaction#commitNow()} instead. This can help avoid * unwanted side effects when other code in your app has pending committed * transactions that expect different timing. * * @return Returns true if there were any pending transactions to be * executed. */ public abstract boolean executePendingTransactions();
Поэтому используйте
commitNow
для заменить:fragmentTransaction.commit(); FragmentManager.executePendingTransactions()
Я заметил что-то очень интересное. У меня есть в моем приложении возможность открыть галерею телефона, и устройство спрашивает, какое приложение использовать, там я нажимаю на серой области вдали от диалогового окна и вижу эту проблему. Я заметил, как моя деятельность переходит из onPause, onSaveInstanceState обратно в onResume, не происходит посещения onCreateView. Я делаю транзакции в onResume. Итак, что я закончил делать, это установить флаг, который будет отрицаться onPause, но будет true onCreateView. если флаг true onResume, то do onCommit, иначе commitAllowingStateLoss. Я мог продолжать и тратить столько времени, но я хотел проверить жизненный цикл. У меня есть устройство, которое является sdkversion 23, и я не получаю эту проблему, но у меня есть еще один, который равен 21, и там я его вижу.
это сработало для меня ... нашел это самостоятельно ... надеюсь, что это вам поможет!
1) НЕ имеет глобального «статического» FragmentManager / FragmentTransaction.
2) onCreate, ALWAYS снова инициализируйте FragmentManager!
пример ниже: -
public abstract class FragmentController extends AnotherActivity{
protected FragmentManager fragmentManager;
protected FragmentTransaction fragmentTransaction;
protected Bundle mSavedInstanceState;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSavedInstanceState = savedInstanceState;
setDefaultFragments();
}
protected void setDefaultFragments() {
fragmentManager = getSupportFragmentManager();
//check if on orientation change.. do not re-add fragments!
if(mSavedInstanceState == null) {
//instantiate the fragment manager
fragmentTransaction = fragmentManager.beginTransaction();
//the navigation fragments
NavigationFragment navFrag = new NavigationFragment();
ToolbarFragment toolFrag = new ToolbarFragment();
fragmentTransaction.add(R.id.NavLayout, navFrag, "NavFrag");
fragmentTransaction.add(R.id.ToolbarLayout, toolFrag, "ToolFrag");
fragmentTransaction.commitAllowingStateLoss();
//add own fragment to the nav (abstract method)
setOwnFragment();
}
}
Перед вызовом super.onPostResume () просто вызовите super.onPostResume () перед отображением фрагмента или переместите свой код в метод onPostResume (). Это решает проблему!
Вы можете вызвать функцию fragmentManager.popBackStackImmediate (); когда действие приостановлено. Активность не завершена, но приостановлена, а не на переднем плане. Вам нужно проверить, приостановлена ли операция или нет до popBackStackImmediate ().
Когда я использую startactivity в одном фрагменте, я получу это исключение;
Когда я меняю использование startactivityforresult, исключение исчезло :)
Таким образом, простой способ исправить он использует startActivityForResult api:)
У меня была такая же проблема, что и IllegalStateException, но замена всех моих вызовов commit () с помощью commitAllowingStateLoss () не помогла.
Виновником был вызов DialogFragment.show ().
Я окружаю его с помощью
try {
dialog.show(transaction, "blah blah");
}
catch(IllegalStateException e) {
return;
}
, и он сделал это. ОК, я не могу показать диалог, но в этом случае все было в порядке.
Это было единственное место в моем приложении, где я сначала называл FragmentManager.beginTransaction (), но никогда не называл commit () поэтому я не нашел его, когда искал «commit ()».
Самое забавное, что пользователь никогда не покидает приложение. Вместо этого убийца стал рекламным объявлением AdMob.
Тот же вопрос от меня, и после дневного анализа всех статей, блога и stackoverflow я нашел простое решение. Не используйте savedInstanceState вообще, это условие с одной строкой кода. О коде фрагмента:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
.....
Мое решение для этой проблемы было
В методах добавления фрагмента:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
guideMapFragment = (SupportMapFragment)a.getSupportFragmentManager().findFragmentById(R.id.guideMap);
guideMap = guideMapFragment.getMap();
...
}
@Override
public void onDestroyView() {
SherlockFragmentActivity a = getSherlockActivity();
if (a != null && guideMapFragment != null) {
try {
Log.i(LOGTAG, "Removing map fragment");
a.getSupportFragmentManager().beginTransaction().remove(guideMapFragment).commit();
guideMapFragment = null;
} catch(IllegalStateException e) {
Log.i(LOGTAG, "IllegalStateException on exit");
}
}
super.onDestroyView();
}
Может быть плохо, но не удалось найти ничего лучшего.
У меня возникла эта проблема. Но я думаю, что эта проблема не связана с commit и commitAllowStateLoss.
Следующее сообщение трассировки стека и сообщения об исключении относится к commit ().
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
Но это исключение было вызвано onBackPressed ()
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(Unknown Source)
at android.support.v4.app.FragmentActivity.onBackPressed(Unknown Source)
Все они были вызваны checkStateLoss ()
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
if (mNoTransactionsBecause != null) {
throw new IllegalStateException(
"Can not perform this action inside of " + mNoTransactionsBecause);
}
. MStateSaved будет истинным после onSaveInstanceState.
Эта проблема редко бывает. Я никогда не сталкивался с этой проблемой. Я не могу повторить проблему.
Я нашел вопрос 25517
Возможно, это произошло в следующих случаях
Я не уверен, в чем корень проблемы. Поэтому я использовал уродливый способ.
@Override
public void onBackPressed() {
try{
super.onBackPressed();
}catch (IllegalStateException e){
// can output some information here
finish();
}
}
commitAllowingStateLoss()
устраняет исключение. Он не защищает ваше приложение от случайной потери состояния. См. Это сообщение в блоге .
– Alex Lockwood
21 August 2013 в 00:20
Я решил проблему с onconfigurationchanged. Хитрость заключается в том, что в соответствии с жизненным циклом активности андроида, когда вы явно называете намерение (намерение камеры или любое другое); действие приостанавливается, и в этом случае вызывается onsavedInstance. При вращении устройства в другое положение, отличное от того, в котором активна активность; выполнение операций фрагмента, таких как фиксация фрагмента, вызывает исключение из нелегального состояния. Есть много жалоб на это. Это что-то вроде управления жизненным циклом активности Android и правильных вызовов методов. Чтобы решить эту проблему, я сделал следующее: 1-Переопределите метод onsavedInstance вашей активности и определите текущую ориентацию экрана (портретную или альбомную), а затем установите ориентацию экрана перед ее приостановкой активности. таким образом, вы заблокируете поворот экрана для своей активности, если он был повернут другим. 2, затем переопределите метод onresume активности и настройте режим ориентации теперь на датчик, чтобы после вызова метода onsaved он будет вызывать еще один раз при настройке для правильного вращения.
Вы можете копировать / вставьте этот код в свою деятельность, чтобы справиться с этим:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Toast.makeText(this, "Activity OnResume(): Lock Screen Orientation ", Toast.LENGTH_LONG).show();
int orientation =this.getDisplayOrientation();
//Lock the screen orientation to the current display orientation : Landscape or Potrait
this.setRequestedOrientation(orientation);
}
//A method found in stackOverflow, don't remember the author, to determine the right screen orientation independently of the phone or tablet device
public int getDisplayOrientation() {
Display getOrient = getWindowManager().getDefaultDisplay();
int orientation = getOrient.getOrientation();
// Sometimes you may get undefined orientation Value is 0
// simple logic solves the problem compare the screen
// X,Y Co-ordinates and determine the Orientation in such cases
if (orientation == Configuration.ORIENTATION_UNDEFINED) {
Configuration config = getResources().getConfiguration();
orientation = config.orientation;
if (orientation == Configuration.ORIENTATION_UNDEFINED) {
// if height and widht of screen are equal then
// it is square orientation
if (getOrient.getWidth() == getOrient.getHeight()) {
orientation = Configuration.ORIENTATION_SQUARE;
} else { //if widht is less than height than it is portrait
if (getOrient.getWidth() < getOrient.getHeight()) {
orientation = Configuration.ORIENTATION_PORTRAIT;
} else { // if it is not any of the above it will defineitly be landscape
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
}
}
}
return orientation; // return value 1 is portrait and 2 is Landscape Mode
}
@Override
public void onResume() {
super.onResume();
Toast.makeText(this, "Activity OnResume(): Unlock Screen Orientation ", Toast.LENGTH_LONG).show();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
Это самая глупая ошибка, с которой я столкнулся до сих пор. У меня было приложение Fragment
, отлично работающее для API & lt; 11 и Force Closing
в API> 11.
Я действительно не мог понять, что они изменили внутри жизненного цикла Activity
при вызове saveInstance
, но я вот как я решил это :
@Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super(). Bug on API Level > 11.
}
Я просто не звоню в .super()
, и все отлично работает. Я надеюсь, что это сэкономит вам некоторое время.
EDIT: после еще нескольких исследований, это известная ошибка в пакете поддержки.
Если вам нужно сохранить экземпляр и добавить что-то в свой outState
Bundle
, вы можете использовать следующее:
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
super.onSaveInstanceState(outState);
}
EDIT2: это также может произойти, если вы пытаетесь выполнить транзакцию после того, как ваш Activity
исчез в фоновом режиме. Чтобы избежать этого, вы должны использовать commitAllowingStateLoss()
EDIT3: . Вышеупомянутые решения были устранением проблем в ранних библиотеках support.v4 из того, что я помню. Но если у вас все еще есть проблемы с этим, вы MUST также читаете блог @AlexLockwood : Fragment Transactions & amp;
commit()
транзакции после onPause()
на pre-Honeycomb и onStop()
на post-Honeycomb Activity
. Используйте onCreate()
, onResumeFragments()
и onPostResume()
commitAllowingStateLoss()
только в качестве последнего средства commitAllowingStateLoss()
устраняет исключение. Он не защищает ваше приложение от случайной потери состояния. См. Это сообщение в блоге .
– Alex Lockwood
21 August 2013 в 00:20