我的启动器活动是一个TabLayout,其中包含以下几个片段。愿景是,在每次单击Tab时,Fragment的onCreate将使用Retrofit2库从服务器获取数据并通过onCreateView的RecyclerView显示数据。
当前,该应用程序在启动时崩溃,因为onCreateView首先完成,并且想要在异步GET请求甚至完成之前显示数据。具体来说,内部类ModelHolder的getItemCount方法产生一个空对象引用。
我有两个想法可以将Fragment的视图创建延迟到GET请求完成之后,以便视图实际上具有要显示的数据。
1)在Fragment上强制同步,以便onCreate必须在onCreateView开始之前完成。该应用程序将冻结一会儿,但不会像以前那样崩溃。
2)添加一个启动屏幕并使其成为启动程序活动,以便用户在加载数据时查看启动屏幕。我认为这很骗人,因为它可以避免问题。
延迟onCreateView的最佳方法是什么?如果该方法不是好的做法,那么有哪些替代解决方案?
public class ModelsFragment extends Fragment {
private final String API_KEY = "INSERT API KEY HERE";
private static final String ARG_CATEGORY = "model_category";
private String mCategory;
private RecyclerView mModelRecyclerView;
private ModelAdapter mModelAdapter;
private List<Model> mModels;
public static Fragment newInstance(String category) {
Bundle args = new Bundle();
args.putString(ARG_CATEGORY, category);
ModelsFragment modelsFragment = new ModelsFragment();
modelsFragment.setArguments(args);
return modelsFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCategory = getArguments().getString(ARG_CATEGORY);
EdmundsService service = EdmundsServiceGenerator.createService(EdmundsService.class);
Map<String, String> options = new HashMap<>();
options.put("state", "new");
options.put("year", "2016");
options.put("view", "basic");
options.put("api_key", API_KEY);
if (mCategory != null) {
options.put("category", mCategory);
}
Call<Models> call = service.getModels(options);
call.enqueue(new Callback<Models>() {
@Override
public void onResponse(Call<Models> call, Response<Models> response) {
if (response.isSuccessful()) {
mModels = response.body().getModels();
Log.i("GET Status", "Successfully retrieved data");
Log.i("GET Status", response.body().getModelsCount().toString());
}
else {
Log.i("GET Status", "Failed to retrieve data");
}
}
@Override
public void onFailure(Call<Models> call, Throwable t) {
Log.e("Error retrieving data", t.getMessage());
}
});
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mModelRecyclerView = (RecyclerView) inflater.inflate(R.layout.fragment_models, container, false);
updateUI();
mModelRecyclerView.setHasFixedSize(true);
mModelRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
return mModelRecyclerView;
}
private void updateUI() {
mModelAdapter = new ModelAdapter(mModels);
mModelRecyclerView.setAdapter(mModelAdapter);
}
public class ModelHolder extends RecyclerView.ViewHolder {
public ModelHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(R.layout.fragment_models_card_view_item, parent, false));
}
}
public class ModelAdapter extends RecyclerView.Adapter<ModelHolder> {
// Set number of Cards in the recycler view.
private List<Model> models;
public ModelAdapter(List<Model> models) {
this.models = models;
}
@Override
public ModelHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ModelHolder(LayoutInflater.from(parent.getContext()), parent);
}
@Override
public void onBindViewHolder(ModelHolder holder, int position) {
}
@Override
public int getItemCount() {
return models.size();
}
}
}
您可以通过getItemCount()
检查null来解决崩溃问题。
@Override
public int getItemCount() {
return models == null ? 0 : models.size();
}
然后,在改造中onResponse()
,只需调用updateUI
即可填充ModelAdapter。
编辑:要解决您的两个想法,强制ui线程等待,直到您收到服务器响应,可能会导致ANR,并且用户关闭了您的应用程序。想象一下,如果他们的连接不良并且需要10秒钟来获取数据,将会发生什么情况。对于第二个想法,在加载数据时显示一个ProgressBar,然后在数据准备好后切换其可见性是很常见的。的目的onCreateView()
仅仅是返回视图;数据绑定可以稍后进行。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句