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

时间:2013-06-13 06:06:53

标签: android android-asynctask android-view android-cursorloader

这可能很奇怪,但我在Android中使用多个CursorLoader来执行多个查询,而在onLoadFinished()中,我根据游标结果动态地将TextViews和ListViews等视图添加到我的布局中,就好像游标是不是空的。我确实得到了准确的结果,但由于我使用的是AsyncTaskLoader(CursorLoader),因此光标结果不会同时进入,并且结果不会按正确的顺序添加。我之前使用静态布局并在索引处添加了视图,并根据结果执行了view.setVisiblity(View.GONE),但它太多太混乱,因为我有32个视图。此外,它似乎很奇怪,因为我不认为用户希望看到所有这些视图消失并根据AsyncTaskLoader结果上下移动。 如何在没有一堆布尔变量的情况下以正确的顺序获取视图?我查看了LayoutInflater,但这也需要索引,但我不确定这对我有帮助。索引的问题在于游标加载器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没有执行,那么就会缺少空间,如果我使用静态XML视图并且不动态添加它们,我必须执行大量的view.setVisibility(View.GONE) 。

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

     @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 usage without ContentProvider

给出的内容提供者

1 个答案:

答案 0 :(得分:0)

  

如何在没有我想要的情况下以正确的顺序获取视图   有一堆布尔变量吗?

您需要某种状态控制才能使视图按顺序显示。我会将视图构造/添加委托给一个控件类,无论编译器如何完成他们的工作,它都将拥有正确查看所需的所有信息,并且顺序正确。

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()方法,并在onLoadComplete()调用LoaderCallbacks的{​​{1}}回调中调用。

  

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

您可能已经阅读了ViewDispatcher.onLoadComplete(),可以通过其收到的IntentService的顺序跟踪队列。但是,我不知道这会如何帮助你,因为它会增加问题。对于使用Intents作为您需要传回的数据持有者的人,您需要创建Cursors无法创建的视图(需要创建IntentService创建的视图通过各种沟通方式,从我的角度来看,这是不必要的工作。)