Android CursorLoader以特定/特定的顺序动态添加视图



这可能很奇怪,但我在Android中使用多个CursorLoaders来做多个查询,并在onLoadFinished()中,我正在根据光标结果动态地添加视图,如TextViews和ListViews到我的布局,如果光标不为空。我确实得到了准确的结果,但由于我使用的是AsyncTaskLoader (CursorLoader),因此光标结果不会同时进入,并且结果不会以正确的顺序添加。我以前使用过静态布局,并在索引中添加了视图,并根据结果添加了view. setvisibility (View.GONE),但它太多了,太令人困惑了,因为我有32个视图。另外,这看起来很奇怪,因为我不认为用户希望看到所有这些视图消失,并根据AsyncTaskLoader的结果上下移动。如何在不使用一堆布尔变量的情况下让视图按我想要的顺序排列?我研究了LayoutInflater,但它也需要索引,但我不确定这是否会对我有帮助。索引对我来说的问题是,在cursorloader ID 1:

    view.addView(v, 1);
    view.addView(v, 2);

可能不会被执行,直到ID为2的游标加载器完成:

    view.addView(v, 3);
    view.addView(v, 4);

如果cursorLoader ID 1没有得到执行,ID 2做,然后有缺失的空间,我必须做一个吨的view.setVisibility(View.GONE),如果我使用静态XML视图,不动态添加它们。

在代码中,我正在做这样的事情:

     @Override
     public void onLoadFinished(android.support.v4.content.Loader<Cursor> cursorLoader, Cursor cursor) { 
     switch (cursorLoader.getId())
     {
           case 0:
                   if (cursor != null && cursor.moveToFirst()) {
                      ..
                      title = new TextView(this);
                      ...
                      mainLinearLayout.addView(title, 1);
                   }
                   break;
           case 1:
                    if (cursor != null && cursor.moveToFirst()) {
                      ..
                   title2 = new TextView(this);
                   mainLinearLayout.addView(title2, 2);
                   break;
           default:
                   ...
    }

}

我也在网上某处读到,如果你想在后台线程上做查询,并让它们以一定的顺序完成,最好使用服务而不是cursorloader,但我没有听到其他地方的建议,也没有看到任何在服务中做查询的例子。它们都使用CursorLoader。这个建议一定正确吗?听起来有点粗略。

顺便说一下,我使用的是没有内容提供程序的CursorLoader实现在CursorLoader使用中没有ContentProvider

我如何使视图在正确的顺序,我想在没有有一堆布尔变量?

你确实需要一些状态控制来使视图按顺序显示。我将把视图的构造/添加委托给一个控制类,该控制类将拥有创建正确视图所需的所有信息,并且无论加载器如何完成它们的工作。

public class ViewDispatcher {
    public SparseArray<Status> mLoadStatuses = new SparseArray<Status>();
    public SparseArray<Cursor> mDataCursors = new SparseArray<Cursor>();
    // you'll call this method for each of the loaders, in the order they should be. The ids should be incremental
    public void registerLoader(int loaderId) {
        mLoadStatuses.put(loaderId, Status.INITIAL);
    }
    // called when one of the loaders finishes its job
    public void onLoadComplete(int loaderId, Cursor data) {
         mDataCursors.put(loaderId, data);
         boolean current = true;
         mLoadStatuses.put(loaderId, Status.LOADED);
         if (loaderId == firstLoaderId) {
            // the first loader it's done and we should start the view creation right away
            buildView(loaderId, mainLayout, true);
            mLoadStatuses.put(loaderId, data, Status.FULLY_BUILT);          
         } else {
           // implement a priority system, a view construction will be triggered ONLY 
           // if the previous loader has finished loading data and its view is in place
           // I'm assuming that the Loaders have consecutive ids
           if (mLoadStatuses.get(loaderId - 1) != null && mLoadStatuses.get(loaderId - 1) == Status.FULLY_BUILT) {
               buildView(loaderId, data, mainLayout, true); 
               mLoadStatuses.put(loaderId, Status.FULLY_BUILT);    
            } else {
               current = false;
            } 
         }  
         // we'll also need to implement a buddy system. When a loader is done loading and its view
         // is created we must check to see if we don't have other loaders after this current one that have finished loading 
         // but couldn't construct their view because this current loader didn't finished at that moment
         // get the next loader
         int next = loaderId + 1;
         while(current && next < totalNumberOfLoaders && mLoadStatuses.get(next) == Status.LOADED) {
            // continue to build views
            buildView(next, mDataCursors.get(loaderId), mainLayout, true);              
            mLoadStatuses.put(next, Status.FULLY_BUILT);
            next++; 
         } 
    }  
    // this will build the appropriate view, and optionally attach it
    public void buildView(int loaderId, Cursor data, view mainLayout, boolean attach) {
        // build the view for this specific Loader
    }
}
public enum Status {
    INITIAL, LOADED, FULLY_BUILT 
}

我希望我没有错过一些明显的东西,因为我没有写任何测试。要使用它,您将首先按照您需要的顺序为所有加载器调用registerLoader()方法,并在LoaderCallbacksonLoadComplete()回调中调用ViewDispatcher.onLoadComplete()

我还在网上读到,最好使用服务而不是cursorloader如果你想在后台进行查询把它们按一定的顺序织好,但我没有听说过这个建议在其他地方或看到任何例子做查询服务。

你可能已经读过IntentService,它可以通过Intents接收的顺序来跟随队列。但是,我看不出这对你有什么帮助,因为它只会增加问题。首先,您使用Cursors作为您需要传递的数据持有人,并且您需要创建IntentService无法执行的视图(它需要使Activity通过各种通信方式创建它们,从我的角度来看,这是不必要的工作)。

最新更新