背景和问题:
我有一个自定义的Fragment
类。我将此片段类重用于多个状态显示。在父级Activity
中,我加载该片段并在该片段上调用方法以设置一些文本等。执行此操作时,我命中了NullPointerException
。原因是尚未调用onCreateView(),即视图不存在,因此访问TextView
来调用.setText(String)
当然会遇到NullPointerException
。
片段类
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;
}
}
在我的主要活动中的某处,作为来自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();
}
其中copyStartFragment
和copyFinishFragment
是上述片段的实例。
注意:
根据Service
状态更新间隔,对replace()
片段的调用几乎是瞬时的-我认为这是实际问题。
我的解决方法:
具有所有视图及其属性的initial setter。例如initialTitleText
,initialMessageText
,initialActionButtonText
,initialActionButtonVisibility
等。我觉得这有点怪异,与片段使用的预期设计理念不符。
我的问题
这是我遇到此类错误的设计问题,还是有一种变通方法可以更快地调用onCreateView()
?
您正在使用.commit()
作为替换片段的一部分。这是异步完成的。没有办法解决,这只是该功能的工作原理。
您可以使用.commitNow()
,它将完成同步。这样,您应该可以在函数返回后立即访问视图。
https://developer.android.com/reference/androidx/fragment/app/FragmentTransaction#commitNow()
使用推荐的方式将初始字符串传递给片段,以初始化片段:
public static CopyStaticFragment newInstance(String initialString....) {
CopyStaticFragment fragment = new CopyStaticFragment();
Bundle args = new Bundle();
args.putString(INITIAL_STRING, initialString);
fragment.setArguments(args);
return fragment;
}
然后输入onCreate
:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mInitialString = getArguments().getString(INITIAL_STRING);
}
}
然后,当您在TextView
中设置OnViewCreated
文本时,字符串和任何其他参数都可用。
使用以下方法初始化活动中的片段:
CopyStaticFragment.newInstance("initial string",....);
旁注:onCreateView
仅应用于膨胀布局资源,在膨胀布局之后,请使用OnViewCreated
初始化视图。