[英]Android fragment onCreateView delayed
Background & Problem:背景与问题:
I have a custom Fragment
class.我有一个自定义
Fragment
类。 I reuse this fragment class for multiple status displays.我将这个片段类重用于多个状态显示。 In the parent
Activity
, I load the fragment and call a method on the fragment to set some text, etc. When I do this, I hit a NullPointerException
.在父
Activity
,我加载片段并调用片段上的方法来设置一些文本等。当我这样做时,我遇到了NullPointerException
。 The reason is onCreateView() has not yet been called, ie the view doesn't exist, thus accessing a TextView
to call .setText(String)
will ofcourse run into a NullPointerException
.原因是onCreateView()还没有被调用,即视图不存在,因此访问
TextView
来调用.setText(String)
会遇到NullPointerException
。
Fragment Class片段类
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.example.app.R;
public class CopyStaticFragment extends Fragment {
private String initialActionText, initialSecondaryText, initialTitleText;
private TextView textViewTitle, textViewSecondary;
private Button btnAction;
private View.OnClickListener actionCallback;
public void setActionButtonListener(View.OnClickListener actionCallback) {
this.actionCallback = actionCallback;
}
public CopyStaticFragment() {
}
public CopyStaticFragment(View.OnClickListener actionCallback) {
this.actionCallback = actionCallback;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.fragment_main_status, container, false);
textViewTitle = layout.findViewById(R.id.textViewTitle);
textViewTitle.setText(initialTitleText);
textViewSecondary = layout.findViewById(R.id.textViewSecondary);
textViewSecondary.setText(initialSecondaryText);
btnAction = layout.findViewById(R.id.btnAction);
btnAction.setText(initialActionText);
btnAction.setOnClickListener(v -> {
if(actionCallback != null) {
actionCallback.onClick(v);
}
});
return layout;
}
public void setPrimaryText(String text) {
textViewTitle.setText(text);
}
public void setSecondaryText(String text) {
textViewSecondary.setText(text);
}
public void setActionText(String text) {
btnAction.setText(text);
}
public void setInitialActionText(String text) {
this.initialActionText = text;
}
public void setInitialSecondaryText(String text) {
this.initialSecondaryText = text;
}
public void setInitialTitleText(String text) {
this.initialTitleText = text;
}
}
Somewhere in my main activity, as a callback response from a Service
status, I will do something like:在我的主要活动的某个地方,作为来自
Service
状态的回调响应,我将执行以下操作:
if (instance.getUnbackedUpCount() > 0) {
// Load first fragment - i.e. we can backup content
getSupportFragmentManager().beginTransaction()
.replace(R.id.frameCurrentStatus, copyStartFragment)
.commit();
capacityControlFragment.setInfoIconVisible(true);
} else {
getSupportFragmentManager().beginTransaction()
.replace(R.id.frameCurrentStatus, copyFinishFragment)
.commit();
}
where copyStartFragment
& copyFinishFragment
are instances of the above mentioned fragment.其中
copyStartFragment
和copyFinishFragment
是上述片段的实例。
Note:笔记:
Depending on the Service
status update interval, the call to replace()
fragments can be almost instantaneous - which I figure is the actual problem.根据
Service
状态更新间隔,对replace()
片段的调用几乎是瞬时的——我认为这是实际问题。
My workaround:我的解决方法:
Is to have initial setters for all views and their properties.是为所有视图及其属性设置初始设置器。 eg
initialTitleText
, initialMessageText
, initialActionButtonText
, initialActionButtonVisibility
, etc. I feel this is hack'ish and not inline with the intended design philisophy of Fragment use.例如
initialTitleText
、 initialMessageText
、 initialActionButtonText
、 initialActionButtonVisibility
等。我觉得这是hack'ish,不符合Fragment 使用的预期设计理念。
My Question我的问题
Is this a design problem on my part for encountering such an error or is there a workaround to call the onCreateView()
sooner?这是我遇到此类错误的设计问题还是有解决方法可以更快地调用
onCreateView()
?
You are using .commit()
as part of replacing fragments.您正在使用
.commit()
作为替换片段的一部分。
This is done async.这是异步完成的。 No way around it, it's just how that function works.
没有办法解决它,这就是该功能的工作方式。
You can use .commitNow()
, and it will be done sync.您可以使用
.commitNow()
,它将完成同步。
By doing it like this, you should be able to access the views instantly after the function returns.通过这样做,您应该能够在函数返回后立即访问视图。
https://developer.android.com/reference/androidx/fragment/app/FragmentTransaction#commitNow() https://developer.android.com/reference/androidx/fragment/app/FragmentTransaction#commitNow()
Pass the initial strings to the fragment using the recommended way to initialise a fragment:使用推荐的方法将初始字符串传递给片段以初始化片段:
public static CopyStaticFragment newInstance(String initialString....) {
CopyStaticFragment fragment = new CopyStaticFragment();
Bundle args = new Bundle();
args.putString(INITIAL_STRING, initialString);
fragment.setArguments(args);
return fragment;
}
Then in onCreate
:然后在
onCreate
:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mInitialString = getArguments().getString(INITIAL_STRING);
}
}
Then when you set your TextView
text in OnViewCreated
the string and any other parameters are available.然后,当您在
OnViewCreated
设置TextView
文本时,字符串和任何其他参数都可用。
Initialise your fragment in the activity using:使用以下方法在活动中初始化您的片段:
CopyStaticFragment.newInstance("initial string",....);
Side note: onCreateView
should only be used to inflate your layout resource, use OnViewCreated
to initialise your views after the layout has been inflated.旁注:
onCreateView
应该只用于膨胀你的布局资源,在布局膨胀后使用OnViewCreated
来初始化你的视图。
Stay as far away as you can from commitNow()
and popBackStackImmediate()
unless you love IllegalStateException
尽可能远离
commitNow()
和popBackStackImmediate()
除非你喜欢IllegalStateException
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.