我想用C#和Java标记这个问题;对于Java程序员,我相信你可以很容易地理解C#代码,它们非常相似。
自从知道如何编程以来,我遇到了许多奇怪的问题,这是最奇怪的问题之一,这肯定是Android引擎和API的问题。
首先,我想简要描述它有多奇怪。你能想到电话setContentView
没有做任何事情的任何情况吗?没有抛出异常,Activity的内容视图根本没有改变为我想要的东西(即使传递null
值也没有发生任何事情)。
事实上,我没有尝试过测试其他一些方案来重现问题。但是我将在这里描述的场景应该很容易重现这个问题。
您需要一个简单的自定义Fragment
,您可以在其中加载一个简单的Button
布局。现在在onCreateView
回调中,您需要对布局进行充气,连接Click
的{{1}}事件,以通过自定义片段触发另一个公开事件。
Button
Fragment
设置为RetainInstance
。现在在true
中,您声明了自定义MainActivity
的 静态 字段。在Fragment
的{{1}}回调中,Fragment
仅创建一次(通过核对null
)。我们将自定义OnCreate
的公开点击事件与处理程序联系起来,该处理程序只使用MainActivity
显示新内容。
代码在没有屏幕旋转的情况下工作正常。但是在屏幕旋转之后,Fragment
根本无效,并且没有例外。这听起来像点击事件没有被触发,但实际上它仍然被解雇了,而 SetContentView
实际上被称为 (我很确定这一点,因为我通过在那里设置断点来调试它。
以下是代码:
主要布局 :(此名称为SetContentView
)
SetContentView
自定义片段 :
Main.axml
MainActivity :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
那就是重现奇怪问题的所有设置。
如上所述,代码运行良好,无需旋转屏幕。但是在旋转屏幕后,public class CustomFragment : Fragment {
//the click event
public event EventHandler ButtonClick;
void onButtonClick(EventArgs e){
var handler = ButtonClick;
if(handler != null) handler(this,e);
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState){
//we can even use a simple layout as a Button.
var button = new Button(parent.Context);
button.Click += (s,e) => {
onButtonClick(EventArgs.Empty);
};
return button;
}
}
什么都不做 ,虽然它肯定会被称为 (我确实知道通过在通话中设置断点)。
我认为另外一件事也很重要的是[Activity(Label = "Hello", MainLauncher = true]
public class MainActivity : AppCompatActivity {
//the static custom Fragment
static CustomFragment frag;
protected override void OnCreate(Bundle bundle){
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
//this ensures that the code inside if block is run just once
//between screen rotations
if(frag == null){
frag = new CustomFragment(this);
frag.RetainInstance = true;
frag.ButtonClick += (s,e) => {
//whatEverView here is any View, layout resource id
//or even null value.
SetContentView(whatEverView);
};
//load the fragment into the container in the Main layout
var ft = FragmentManager.BeginTransaction();
ft.Replace(Resource.Id.container, frag);
ft.Commit();
}
}
}
似乎没有被调用之后的所有调用(因为在SetContentView
运行之后没有达到设置的断点,就像那里一样是SetContentView
打断那里的代码)。没有例外且应用程序没有崩溃,只是在此之后正常运行(再次单击按钮将再次调用SetContentView
)。
这很奇怪,内心发生的事情肯定是我不知道的。阅读源代码不是我的优势,部分原因是因为我还不熟悉Android编程。
您可能需要尝试在自己的计算机上复制问题以了解此问题。
最后,代码在Kitkat和Marshmallow Android OS上运行(由Visual Studio Emulator运行)。
答案 0 :(得分:1)
1)重新创建活动后,您将失去隐含this
中原始活动(this.SetContentView(whatEverView);
)的范围。
2)在您的片段OnCreateView
中,您在内部使用Context
ViewGroup
MainActivity
实例OnAttach
,但每次活动都会更改由于配置更改而重新创建。 OnDetach
和CustomFragment
应该用于分配当前的Context / Activity并清除/清空它。
3)不应使用FragmentManager.FindFragmentByTag
的静态var,而应使用CustomFragment
,并根据需要重新创建片段,因为操作系统可以回收片段,即使它将被保留,你将在野外追逐幻影崩溃......
这是一个快速修复示例,Button
的内部仍然需要重置/清除旧的事件处理程序,当片段与Activity分离并更正{{1}使用旧/新上下文。
public class MainActivity : AppCompatActivity
{
const string customFragmentTag = "custom_fragment";
CustomFragment frag;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
frag = FragmentManager.FindFragmentByTag(customFragmentTag) as CustomFragment;
if (frag == null)
{
frag = new CustomFragment(Resource.Layout.Frag);
FragmentManager.BeginTransaction().Add(Resource.Id.container, frag, customFragmentTag).Commit();
}
frag.ButtonClick += (s, e) => SetContentView(Resource.Layout.Frag);
}
}
如果您的Fragment需要访问当前的Context / Activity,您应该实现以下覆盖(currentActivity
是类级别Activity
var):
public override void OnAttach(Activity activity)
{
base.OnAttach(activity);
currentActivity = activity;
}
public override void OnAttach(Android.Content.Context context)
{
base.OnAttach(context);
currentActivity = context as Activity;
}
public override void OnDetach()
{
base.OnDetach();
currentActivity = null;
}
答案 1 :(得分:-2)
首先在更换时将TAG设置为您的片段。然后再按下您可以使用按标签查找片段并执行您想要的操作。