使用反射访问DialogFragment中的一些字段
Using reflection to access some fields in DialogFragment
我有一个classBaseDialog extends DialogFragment
一段时间后,我发现默认的 DialogFragment.show() 可能会导致一些问题 - 如果 activity 正在关闭或被销毁等...
在查看 DialogFragment 的反编译(?)源代码后,我无意中发现了这段代码:
public void show(FragmentManager manager, String tag) {
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
}
而且我想自己尝试一个小的 'hack' 来消除 Activity 通过 onSaveInstanceState()
调用后与 showing/dismissing 对话框相关的错误。
我想到了这个:
public void showAllowingStateLoss(FragmentManager manager, String tag) {
try {
Class thiz = super.getClass();
Field dismissed = thiz.getField("mDismissed");
dismissed.setAccessible(true);
dismissed.set(thiz, false);
} catch(NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} //mDismissed = false;
try {
Class thiz = super.getClass();
Field shown = thiz.getField("mShownByMe");
shown.setAccessible(true);
shown.set(thiz, true);
} catch(IllegalAccessException e) {
e.printStackTrace();
} catch(NoSuchFieldException e) {
e.printStackTrace();
} //mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
效果很好。
我现在遇到的问题是,我似乎无法访问 DialogFragment 的某些字段以将它们设置为正确的预期值,就像原始来源所做的那样。
W/System.err( 2510): java.lang.NoSuchFieldException: mDismissed
W/System.err( 2510): at java.lang.Class.getField(Class.java:1048)
W/System.err( 2510): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:70)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.openConfirmationDialog(ActivityLogin.java:250)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.access0(ActivityLogin.java:45)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:306)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:262)
W/System.err( 2510): at com.dpd.navigator.backend.soap.SOAPHelper.onPostExecute(SOAPHelper.java:1290)
W/System.err( 2510): at android.os.AsyncTask.finish(AsyncTask.java:632)
W/System.err( 2510): at android.os.AsyncTask.access0(AsyncTask.java:177)
W/System.err( 2510): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
W/System.err( 2510): at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err( 2510): at android.os.Looper.loop(Looper.java:155)
W/System.err( 2510): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 2510): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 2510): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
W/System.err( 2510): java.lang.NoSuchFieldException: mShownByMe
W/System.err( 2510): at java.lang.Class.getField(Class.java:1048)
W/System.err( 2510): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:81)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.openConfirmationDialog(ActivityLogin.java:250)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.access0(ActivityLogin.java:45)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:306)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:262)
W/System.err( 2510): at com.dpd.navigator.backend.soap.SOAPHelper.onPostExecute(SOAPHelper.java:1290)
W/System.err( 2510): at android.os.AsyncTask.finish(AsyncTask.java:632)
W/System.err( 2510): at android.os.AsyncTask.access0(AsyncTask.java:177)
W/System.err( 2510): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
W/System.err( 2510): at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err( 2510): at android.os.Looper.loop(Looper.java:155)
W/System.err( 2510): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 2510): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 2510): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
W/System.err( 2510): java.lang.NoSuchFieldException: mViewDestroyed
W/System.err( 2510): at java.lang.Class.getField(Class.java:1048)
W/System.err( 2510): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:95)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.openConfirmationDialog(ActivityLogin.java:250)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.access0(ActivityLogin.java:45)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:306)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:262)
W/System.err( 2510): at com.dpd.navigator.backend.soap.SOAPHelper.onPostExecute(SOAPHelper.java:1290)
W/System.err( 2510): at android.os.AsyncTask.finish(AsyncTask.java:632)
W/System.err( 2510): at android.os.AsyncTask.access0(AsyncTask.java:177)
W/System.err( 2510): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
W/System.err( 2510): at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err( 2510): at android.os.Looper.loop(Looper.java:155)
W/System.err( 2510): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 2510): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 2510): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
我想知道为什么我不能访问这些字段....它们不是静态的,所以 getField() 应该可以工作。我也试过 getDeclaredField()
- 没有骰子。
所以我开始怀疑 - 尝试使用反射访问这些字段是否可行?我知道 "just for show" 那里有一些 Android 代码(SDK 代码),因为我们无法触摸它 - 它在 AndroidRuntime
进程中运行,这就是为什么反射不能在那里做任何事情的原因。
这就是我问这个问题的原因:我找不到这些字段是因为它们在 Android 运行时进程中 运行 还是因为我做错了什么?
我可以接受第一种情况。如果是第二种情况,我真的很想将它们设置为预期值。
P.S。我真的对为什么使用 commitAllowingStateLoss
是错误的 and/or 不好的说教不感兴趣。问题的重点不是这个。 问题的重点是为什么我找不到这些字段?
提前感谢您的帮助:)
编辑:
这里的 logcat 表明使用 getDeclaredField
也不起作用。
W/System.err( 330): java.lang.NoSuchFieldException: mDismissed
W/System.err( 330): at java.lang.Class.getDeclaredField(Class.java:886)
W/System.err( 330): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:70)
W/System.err( 330): at com.dpd.navigator.ui.activities.ActivityMenu.openProfile(ActivityMenu.java:275)
W/System.err( 330): at com.dpd.navigator.ui.activities.ActivityMenu.access[=13=]0(ActivityMenu.java:31)
W/System.err( 330): at com.dpd.navigator.ui.activities.ActivityMenu.onClick(ActivityMenu.java:74)
W/System.err( 330): at android.view.View.performClick(View.java:4785)
W/System.err( 330): at android.view.View$PerformClick.run(View.java:19858)
W/System.err( 330): at android.os.Handler.handleCallback(Handler.java:739)
W/System.err( 330): at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err( 330): at android.os.Looper.loop(Looper.java:155)
W/System.err( 330): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 330): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 330): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 330): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 330): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
编辑 2:
感谢@pskink 和@derek-fung 的投入,我将代码更改为:
public void showAllowingStateLoss(FragmentManager manager, String tag) {
try {
// Class<? extends DialogFragment> thiz = DialogFragment.class;
Class<? extends DialogFragment> thiz = ((DialogFragment)this).getClass();
Field dismissed = thiz.getDeclaredField("mDismissed"); <-- line 71
dismissed.setAccessible(true);
dismissed.set(this, false);
} catch(NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} //mDismissed = false;
try {
Class<? extends DialogFragment> thiz = ((DialogFragment)this).getClass();
// Field shown = thiz.getField("mShownByMe");
Field shown = thiz.getDeclaredField("mShownByMe"); <-- line 83
shown.setAccessible(true);
shown.set(this, true);
} catch(IllegalAccessException e) {
e.printStackTrace();
} catch(NoSuchFieldException e) {
e.printStackTrace();
} //mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
使用 DialogFragment.class
导致 java.lang.IllegalArgumentException: Expected receiver of type android.app.DialogFragment, but got java.lang.Class<android.app.DialogFragment>
这就是我尝试将其转换为一个的原因。
结果是:
W/System.err( 3227): java.lang.NoSuchFieldException: mDismissed
W/System.err( 3227): at java.lang.Class.getDeclaredField(Class.java:886)
W/System.err( 3227): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:71)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.openConfirmationDialog(ActivityDPDSplash.java:636)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.startApplication(ActivityDPDSplash.java:866)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.access0(ActivityDPDSplash.java:70)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.run(ActivityDPDSplash.java:765)
W/System.err( 3227): at android.os.Handler.handleCallback(Handler.java:739)
W/System.err( 3227): at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err( 3227): at android.os.Looper.loop(Looper.java:155)
W/System.err( 3227): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 3227): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 3227): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 3227): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 3227): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
W/System.err( 3227): java.lang.NoSuchFieldException: mShownByMe
W/System.err( 3227): at java.lang.Class.getDeclaredField(Class.java:886)
W/System.err( 3227): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:83)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.openConfirmationDialog(ActivityDPDSplash.java:636)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.startApplication(ActivityDPDSplash.java:866)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.access0(ActivityDPDSplash.java:70)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.run(ActivityDPDSplash.java:765)
W/System.err( 3227): at android.os.Handler.handleCallback(Handler.java:739)
W/System.err( 3227): at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err( 3227): at android.os.Looper.loop(Looper.java:155)
W/System.err( 3227): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 3227): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 3227): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 3227): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 3227): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
成功的原因是:
public void showAllowingStateLoss(FragmentManager manager, String tag) {
try {
Class<? extends DialogFragment> thiz = DialogFragment.class;
Field dismissed = thiz.getDeclaredField("mDismissed");
dismissed.setAccessible(true);
dismissed.set(this, false);
} catch(NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} //mDismissed = false;
try {
Class<? extends DialogFragment> thiz = DialogFragment.class;
Field shown = thiz.getDeclaredField("mShownByMe");
shown.setAccessible(true);
shown.set(this, true);
} catch(IllegalAccessException e) {
e.printStackTrace();
} catch(NoSuchFieldException e) {
e.printStackTrace();
} //mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
您应该将 super.getClass()
替换为 DialogFragment.class
连同getDeclaredField()
这是因为 super.getClass()
会 return 您实例的 class,而不是您想要的超级 class。并且 getField()
无法获取 private
字段。
编辑:
dismissed.set(thiz, false);
应替换为 dismissed.set(this, false);
,因为您需要提供对象而不是 class 才能设置字段。
我有一个classBaseDialog extends DialogFragment
一段时间后,我发现默认的 DialogFragment.show() 可能会导致一些问题 - 如果 activity 正在关闭或被销毁等...
在查看 DialogFragment 的反编译(?)源代码后,我无意中发现了这段代码:
public void show(FragmentManager manager, String tag) {
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
}
而且我想自己尝试一个小的 'hack' 来消除 Activity 通过 onSaveInstanceState()
调用后与 showing/dismissing 对话框相关的错误。
我想到了这个:
public void showAllowingStateLoss(FragmentManager manager, String tag) {
try {
Class thiz = super.getClass();
Field dismissed = thiz.getField("mDismissed");
dismissed.setAccessible(true);
dismissed.set(thiz, false);
} catch(NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} //mDismissed = false;
try {
Class thiz = super.getClass();
Field shown = thiz.getField("mShownByMe");
shown.setAccessible(true);
shown.set(thiz, true);
} catch(IllegalAccessException e) {
e.printStackTrace();
} catch(NoSuchFieldException e) {
e.printStackTrace();
} //mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
效果很好。
我现在遇到的问题是,我似乎无法访问 DialogFragment 的某些字段以将它们设置为正确的预期值,就像原始来源所做的那样。
W/System.err( 2510): java.lang.NoSuchFieldException: mDismissed
W/System.err( 2510): at java.lang.Class.getField(Class.java:1048)
W/System.err( 2510): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:70)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.openConfirmationDialog(ActivityLogin.java:250)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.access0(ActivityLogin.java:45)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:306)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:262)
W/System.err( 2510): at com.dpd.navigator.backend.soap.SOAPHelper.onPostExecute(SOAPHelper.java:1290)
W/System.err( 2510): at android.os.AsyncTask.finish(AsyncTask.java:632)
W/System.err( 2510): at android.os.AsyncTask.access0(AsyncTask.java:177)
W/System.err( 2510): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
W/System.err( 2510): at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err( 2510): at android.os.Looper.loop(Looper.java:155)
W/System.err( 2510): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 2510): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 2510): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
W/System.err( 2510): java.lang.NoSuchFieldException: mShownByMe
W/System.err( 2510): at java.lang.Class.getField(Class.java:1048)
W/System.err( 2510): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:81)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.openConfirmationDialog(ActivityLogin.java:250)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.access0(ActivityLogin.java:45)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:306)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:262)
W/System.err( 2510): at com.dpd.navigator.backend.soap.SOAPHelper.onPostExecute(SOAPHelper.java:1290)
W/System.err( 2510): at android.os.AsyncTask.finish(AsyncTask.java:632)
W/System.err( 2510): at android.os.AsyncTask.access0(AsyncTask.java:177)
W/System.err( 2510): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
W/System.err( 2510): at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err( 2510): at android.os.Looper.loop(Looper.java:155)
W/System.err( 2510): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 2510): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 2510): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
W/System.err( 2510): java.lang.NoSuchFieldException: mViewDestroyed
W/System.err( 2510): at java.lang.Class.getField(Class.java:1048)
W/System.err( 2510): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:95)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.openConfirmationDialog(ActivityLogin.java:250)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin.access0(ActivityLogin.java:45)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:306)
W/System.err( 2510): at com.dpd.navigator.ui.activities.ActivityLogin$SOAPListener_getUserLogin.onSOAPSuccess(ActivityLogin.java:262)
W/System.err( 2510): at com.dpd.navigator.backend.soap.SOAPHelper.onPostExecute(SOAPHelper.java:1290)
W/System.err( 2510): at android.os.AsyncTask.finish(AsyncTask.java:632)
W/System.err( 2510): at android.os.AsyncTask.access0(AsyncTask.java:177)
W/System.err( 2510): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
W/System.err( 2510): at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err( 2510): at android.os.Looper.loop(Looper.java:155)
W/System.err( 2510): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 2510): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 2510): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 2510): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
我想知道为什么我不能访问这些字段....它们不是静态的,所以 getField() 应该可以工作。我也试过 getDeclaredField()
- 没有骰子。
所以我开始怀疑 - 尝试使用反射访问这些字段是否可行?我知道 "just for show" 那里有一些 Android 代码(SDK 代码),因为我们无法触摸它 - 它在 AndroidRuntime
进程中运行,这就是为什么反射不能在那里做任何事情的原因。
这就是我问这个问题的原因:我找不到这些字段是因为它们在 Android 运行时进程中 运行 还是因为我做错了什么?
我可以接受第一种情况。如果是第二种情况,我真的很想将它们设置为预期值。
P.S。我真的对为什么使用 commitAllowingStateLoss
是错误的 and/or 不好的说教不感兴趣。问题的重点不是这个。 问题的重点是为什么我找不到这些字段?
提前感谢您的帮助:)
编辑:
这里的 logcat 表明使用 getDeclaredField
也不起作用。
W/System.err( 330): java.lang.NoSuchFieldException: mDismissed
W/System.err( 330): at java.lang.Class.getDeclaredField(Class.java:886)
W/System.err( 330): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:70)
W/System.err( 330): at com.dpd.navigator.ui.activities.ActivityMenu.openProfile(ActivityMenu.java:275)
W/System.err( 330): at com.dpd.navigator.ui.activities.ActivityMenu.access[=13=]0(ActivityMenu.java:31)
W/System.err( 330): at com.dpd.navigator.ui.activities.ActivityMenu.onClick(ActivityMenu.java:74)
W/System.err( 330): at android.view.View.performClick(View.java:4785)
W/System.err( 330): at android.view.View$PerformClick.run(View.java:19858)
W/System.err( 330): at android.os.Handler.handleCallback(Handler.java:739)
W/System.err( 330): at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err( 330): at android.os.Looper.loop(Looper.java:155)
W/System.err( 330): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 330): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 330): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 330): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 330): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
编辑 2:
感谢@pskink 和@derek-fung 的投入,我将代码更改为:
public void showAllowingStateLoss(FragmentManager manager, String tag) {
try {
// Class<? extends DialogFragment> thiz = DialogFragment.class;
Class<? extends DialogFragment> thiz = ((DialogFragment)this).getClass();
Field dismissed = thiz.getDeclaredField("mDismissed"); <-- line 71
dismissed.setAccessible(true);
dismissed.set(this, false);
} catch(NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} //mDismissed = false;
try {
Class<? extends DialogFragment> thiz = ((DialogFragment)this).getClass();
// Field shown = thiz.getField("mShownByMe");
Field shown = thiz.getDeclaredField("mShownByMe"); <-- line 83
shown.setAccessible(true);
shown.set(this, true);
} catch(IllegalAccessException e) {
e.printStackTrace();
} catch(NoSuchFieldException e) {
e.printStackTrace();
} //mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
使用 DialogFragment.class
导致 java.lang.IllegalArgumentException: Expected receiver of type android.app.DialogFragment, but got java.lang.Class<android.app.DialogFragment>
这就是我尝试将其转换为一个的原因。
结果是:
W/System.err( 3227): java.lang.NoSuchFieldException: mDismissed
W/System.err( 3227): at java.lang.Class.getDeclaredField(Class.java:886)
W/System.err( 3227): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:71)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.openConfirmationDialog(ActivityDPDSplash.java:636)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.startApplication(ActivityDPDSplash.java:866)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.access0(ActivityDPDSplash.java:70)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.run(ActivityDPDSplash.java:765)
W/System.err( 3227): at android.os.Handler.handleCallback(Handler.java:739)
W/System.err( 3227): at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err( 3227): at android.os.Looper.loop(Looper.java:155)
W/System.err( 3227): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 3227): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 3227): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 3227): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 3227): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
W/System.err( 3227): java.lang.NoSuchFieldException: mShownByMe
W/System.err( 3227): at java.lang.Class.getDeclaredField(Class.java:886)
W/System.err( 3227): at com.dpd.navigator.ui.dialogs.BaseDialog.showAllowingStateLoss(BaseDialog.java:83)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.openConfirmationDialog(ActivityDPDSplash.java:636)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.startApplication(ActivityDPDSplash.java:866)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.access0(ActivityDPDSplash.java:70)
W/System.err( 3227): at com.dpd.navigator.ActivityDPDSplash.run(ActivityDPDSplash.java:765)
W/System.err( 3227): at android.os.Handler.handleCallback(Handler.java:739)
W/System.err( 3227): at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err( 3227): at android.os.Looper.loop(Looper.java:155)
W/System.err( 3227): at android.app.ActivityThread.main(ActivityThread.java:5696)
W/System.err( 3227): at java.lang.reflect.Method.invoke(Native Method)
W/System.err( 3227): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err( 3227): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
W/System.err( 3227): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
成功的原因是:
public void showAllowingStateLoss(FragmentManager manager, String tag) {
try {
Class<? extends DialogFragment> thiz = DialogFragment.class;
Field dismissed = thiz.getDeclaredField("mDismissed");
dismissed.setAccessible(true);
dismissed.set(this, false);
} catch(NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} //mDismissed = false;
try {
Class<? extends DialogFragment> thiz = DialogFragment.class;
Field shown = thiz.getDeclaredField("mShownByMe");
shown.setAccessible(true);
shown.set(this, true);
} catch(IllegalAccessException e) {
e.printStackTrace();
} catch(NoSuchFieldException e) {
e.printStackTrace();
} //mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
您应该将 super.getClass()
替换为 DialogFragment.class
连同getDeclaredField()
这是因为 super.getClass()
会 return 您实例的 class,而不是您想要的超级 class。并且 getField()
无法获取 private
字段。
编辑:
dismissed.set(thiz, false);
应替换为 dismissed.set(this, false);
,因为您需要提供对象而不是 class 才能设置字段。