使用碎片时处理方向更改的正确方法是什么?
我有一个包含2个片段的横向布局(在FrameLayout
的代码中实例化)。当我切换到纵向模式(其布局仅包含仅保留左窗格的一个FrameLayout
)时,不再需要右侧片段。
我收到错误:
E/AndroidRuntime(4519): Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f060085 for fragment myFragment{418a2200 #2 id=0x7f060085}
假设是我的活动试图将片段重新附加到方向更改之前的位置,但由于包含片段的视图在纵向模式下不存在,因此会抛出错误。
我尝试了以下隐藏/删除/分离方法但仍然出错。告诉片段不再需要它的正确方法是什么,不要尝试显示?
@Override
public void onCreate(Bundle b) {
super.onCreate(b);
Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragholder2);
//rightPane is a framelayout that holds my fragment.
if (rightPane == null && f != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.hide(f); // This doesnt work
ft.remove(f); // neither does this
ft.detach(f); // or this
ft.commit;
}
}
答案 0 :(得分:13)
我遇到了同样的问题,我想我想出了另一个解决方案。此解决方案可能更好,因为您不必将片段添加到后台堆栈。
在调用Activity.onSaveInstanceState()
之前,在super.onSaveInstanceState()
中删除活动中的右侧片段。这对我有用:
public MyActivity extends Activity
{
@Override
public onCreate(Bundle state)
{
super.onCreate(state);
// Set content view
setContentView(R.layout.my_activity);
// Store whether this is a dual pane layout
mDualPane = findViewById(R.id.rightFragHolder) != null;
// Other stuff, populate the left fragment, etc.
.
.
.
if (mDualPane)
{
mRightFragment = new RightFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.rightFragHolder, mRightFragment);
ft.commit()
}
}
@Override
public void onSaveInstanceState(Bundle state)
{
if (mDualPane)
{
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.remove(mRightFragment);
ft.commit()
}
super.onSaveInstanceState(state);
}
private boolean mDualPane;
private Fragment mRightFragment;
}
答案 1 :(得分:1)
如果要保留片段,请尝试不保留片段。
setRetainInstance(false)
而不是
setRetainInstance(true)
答案 2 :(得分:0)
通常,您将拥有两个片段(左/右),一个主要活动和一个右侧片段的容器活动(仅在电话设备上显示时)。此博客条目中描述了这一点:The Android 3.0 Fragments API
public class MyActivity extends FragmentActivity
implements MyListFragment.MyContextItemSelectedListener {
@Override
public void onCreate(final Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity);
}
// Callback from ListFragment
@Override
public void myContextItemSelected(final int action, final long id) {
if (action == R.id.men_show) {
processShow(id);
}
}
private void processShow(final long id) {
if (Tools.isXlargeLand(getApplicationContext())) {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.right);
if (fragment == null ||
fragment instanceof MyEditFragment ||
(fragment instanceof MyShowFragment && ((MyShowFragment) fragment).getCurrentId() != id)) {
fragment = new MyShowFragment(id);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.right, fragment);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.commit();
}
} else {
Intent intent = new Intent();
intent.setClass(this, MyShowActivity.class);
intent.putExtra("ID", id);
startActivityForResult(intent, MyConstants.DLG_TABLE1SHOW);
}
}
private static boolean isXlargeLand(final Context context) {
Configuration configuration = context.getResources().getConfiguration();
return (((configuration.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) &&
configuration.orientation == Configuration.ORIENTATION_LANDSCAPE);
}
}
答案 3 :(得分:0)
如果您有一个带有左窗格和右窗格的双窗格活动,并且其中一个窗格(通常是右窗格)假设在设备切换到纵向模式时不显示,请让Android执行其操作并重新创建右窗格。但是在右窗格的onCreateView中,您应该做的第一件事是检查窗格使用的布局元素之一是否可用。如果不是,请使用FragmentManager删除片段并立即返回:
[Authorize]
[HttpPatch]
[Route("current/customer/{id}")]
public async Task ChangeSessionCustomer(int id)
{
var context = HttpContext.Current;
IAuthenticationManager AuthenticationManager = context.GetOwinContext().Authentication;
var identity = (ClaimsIdentity)User.Identity;
var claimCustomerId = identity.FindFirst("CustomerId");
identity.RemoveClaim(claimCustomerId);
identity.AddClaim(new Claim("CustomerId", id.ToString()));
}
答案 4 :(得分:-1)
我想我已经解决了。
我将片段添加到后台堆栈,然后在活动关闭之前再将其弹出,这有效地消除了它。似乎到目前为止工作。
答案 5 :(得分:-1)
Android会在屏幕旋转期间重新创建两个片段。但是如果你将下面的检查添加到onCreateView()中,它将阻止你解决问题:
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
if (container == null) {
// Currently in a layout without a container, so no
// reason to create our view.
return null;
}
// inflate view and do other stuff
}
我是从Android Developers blog获取的。
答案 6 :(得分:-4)
您不再需要此活动,因为片段将以内嵌方式显示。所以你可以完成活动
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
// we are in landscape so you do not need this activity anymore
finish();
return;
}
if (savedInstanceState == null) {
// plugin right pane fragment
YourFragment frgm = new YourFragment();
getSupportFragmentManager().beginTransaction()
.add(..., frgm).commit();
}
}