我有一个活动通过WebService
抓取数据,从那里创建显示数据的元素。一些数据被分组,因此我的解决方案是在主布局下方的fragments
中显示分组数据,允许用户在组中滑动,可能在顶部有一个选项卡以显示组名。
我遇到的问题是活动中的片段是在Web调用发生之前创建的,使它们变空或使用旧数据。然后,我创建了一个sharedpreferences
侦听器,并在其中放置了fragments
布局创建方法。主要方法抓取数据,写入共享偏好,片段检测到更改并创建它的布局,或者我认为。
某些组在各项之间是相同的,因此从一个组移动到另一个组不会触发onchange事件,从而不会触发布局创建方法。然后,我决定执行以下操作,以便在编写共享首选项后始终触发onchange事件
final Boolean updated = settings.getBoolean("UPDATED_1", false);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("UPDATED_" + pageNum, !updated);
我认为这不是最好的解决方案,它也存在问题,并且每次都没有触发(我还没有排除故障)
对于所有这些,更好的解决方案是什么?我也有一个记忆泄漏我还没有被诊断出来让事情变得更加令人头疼。
我只是想在ViewPager
初始化之前将我的数据抓取方法移到我的位置,但我还不确定这是否能解决我的问题。
答案 0 :(得分:1)
我不建议您等到显示视图的数据,因为它会影响用户体验并且看起来很迟钝。
相反,您可以在AsyncTaskLoader
中实施fragment
,这样一旦从服务器获取数据,就可以通过BroadcastReceiver
通知片段视图。在此期间,只需显示一个微调器,直到检索到数据,然后隐藏它并使用adapter.notifyDataSetChanged();
更新列表。
以下是AsyncTaskLoader
的示例(在我的情况下,它是数据库查询而不是像您这样的服务器调用):
public class GenericLoader<T extends Comparable<T>> extends AsyncTaskLoader<ArrayList<T>> {
private Class clazz;
public GenericLoader(Context context, Class<T> clazz) {
super(context);
this.clazz = clazz;
}
@Override
public ArrayList<T> loadInBackground() {
ArrayList<T> data = new ArrayList<>();
data.addAll(GenericDAO.getInstance(clazz).queryForAll());
Collections.sort(data);
return data;
}
}
然后在你的片段中:
public class FragmentMobileData extends Fragment implements ListAdapter.OnItemClickListener, LoaderManager.LoaderCallbacks<ArrayList<EntityCategories.EntityCategory>> {
public static String TAG = "FragmentMobileData";
private ImageListAdapter adapter;
private ArrayList<EntityList> mCategories = new ArrayList<>();
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
String result = bundle.getString(DatabaseService.RESULT);
if (DatabaseService.NO_CONNECTION.equals(result)) {
Utils.showToastMessage(getActivity(), "No internet connexion", true);
} else if (DatabaseService.RESULT_TIMEOUT.equals(result)) {
Utils.showToastMessage(getActivity(), "Bad connection. Retry", true);
}
getActivity().getSupportLoaderManager().initLoader(1, null, FragmentMobileData.this).forceLoad();
}
};
@Bind(R.id.progressBarEcard)
ProgressBar spinner;
@Bind(R.id.list)
RecyclerView list;
public FragmentMobileData() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_mobile_plan, container, false);
ButterKnife.bind(this, view);
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle("Mobile");
list.setLayoutManager(new LinearLayoutManager(context));
list.addItemDecoration(new DividerItemDecoration(context, R.drawable.divider));
adapter = new ImageListAdapter(mCategories, this);
list.setAdapter(adapter);
Intent intent = new Intent(context, DatabaseService.class);
intent.setAction(DatabaseService.UPDATE_DATA);
getActivity().startService(intent);
return view;
}
@Override
public void onPause() {
super.onPause();
getActivity().unregisterReceiver(mReceiver);
}
@Override
public void onResume() {
super.onResume();
getActivity().registerReceiver(mReceiver, new IntentFilter(DatabaseService.UPDATE_DATA));
}
@Override
public Loader<ArrayList<EntityCategories.EntityCategory>> onCreateLoader(int id, Bundle args) {
return new GenericLoader(context, EntityCategories.EntityCategory.class);
}
@Override
public void onLoadFinished(Loader<ArrayList<EntityCategories.EntityCategory>> loader, ArrayList<EntityCategories.EntityCategory> data) {
if (mCategories.size() != data.size()) {
mCategories.clear();
mCategories.addAll(data);
adapter.notifyDataSetChanged();
Intent intent = new Intent(context, DownloadFilesService.class);
context.startService(intent);
}
spinner.setVisibility(View.GONE);
}
@Override
public void onLoaderReset(Loader<ArrayList<EntityCategories.EntityCategory>> loader) {
mCategories.clear();
adapter.notifyDataSetChanged();
}
//...
}
答案 1 :(得分:0)
也许我误会了什么。但在你的情况下,我认为有一个很好的替代方法来创建,例如,你的片段将显示一些数据组,然后在它的创建阶段显示ui中的进度条,同时在后台请求数据。然后处理结果数据并显示它,并隐藏进度条。
这可以通过实现MVP模式来实现,以提供代码的灵活性和简单的测试。您还可以使用rxJava和Retrofit以方便的方式处理请求。有关MVP和样本的更多信息,您可以找到here。
如果您因某些原因不想提供此方式。例如,您有不确定数量的组,将来会以某种方式收到这些组,并且您希望根据您收到的数据动态构建片段,然后我建议您可以在活动中组织表示层。在这一层你将接收数据然后将它传递给特殊处理程序,特殊处理程序将它分成组,基于它们将要求活动创建片段。在构造函数中,您将发送已接收的数据(因此需要实现Parcelable接口)。