ContentProvider,Loader和ProgressBar

时间:2012-07-24 20:59:49

标签: android android-contentprovider android-progressbar android-loader

我有一个ContentProvider从sqlite数据库中获取数据并通过Loader加载它。它由Service更新,运行AsyncTask从服务器下载数据并在ContentProvider中更新。我希望它很清楚但是要确定:

  • ListFragmentContentProvider通过Loader获取数据,

  • ContentProvider使用Service进行了更新。

现在,当我第一次启动应用程序时,当我的本地sqlite数据库为空时,它显示它没有任何事件,即使它们当前是通过Service下载的。我宁愿在这一刻显示ProgressBar(无限的旋转轮,而不是条形)。但是如果我在没有来自数据库的结果时显示ProgressBar,那么在外部数据库中没有记录的情况下,即使在从特权情况下从服务器获取数据之后它也会存在(并且在我的情况下经常发生) )。所以:

  • Service I首次下载数据时 想在ContentProvider给出之前显示ProgressBar 非空结果 Service完成了它的工作。

  • ContentProvider未返回任何内容时 AND Service完成 这是工作(并获取空结果)我希望该应用程序显示 “没有找到结果”。

我的问题可能是:如何通知ListFragment Service仍在运行或已完成ts作业。我的意思是 - 我不应该在Fragment内存储对调用Service的任何引用。这违背了ContentProviders的想法,不是吗?怎么样?

注意:我真的不知道哪个代码片段在这里会有所帮助,所以如果您觉得需要查看某些特定的片段,请在评论中告诉我。谢谢!

2 个答案:

答案 0 :(得分:1)

如何在Fragment / ActivityService之间进行通信有各种技巧。

其中一位正在使用ResultReceiver并将其发送到Intent额外的IntentService

您可以创建自定义接收器ServiceResultReceiver,扩展ResultReceiver

public class ServiceResultReceiver extends ResultReceiver {

    private Receiver mReceiver;

    public ServiceResultReceiver(Handler handler) {
        super(handler);
    }

    public void setReceiver(Receiver receiver) {
        mReceiver = receiver;
    }

    public interface Receiver {
        public void onReceiveResult(int resultCode, Bundle resultData);
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {
        if (mReceiver != null) {
            mReceiver.onReceiveResult(resultCode, resultData);
        }
    }
}

制作Fragment工具ServiceResultReceiver.Receiver界面。创建接收器 并将其初始化为Fragment。您可以将接收器传递给服务器并在服务中使接收器从意图中获取并呼叫receiver.send()以将任何内容发送回接收器。

public class MyFragment extends ListFragment implements ServiceResultReceiver.Receiver {
    private ServiceResultReceiver mReceiver;
    ....

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        mReceiver = new ServiceResultReceiver(new Handler());
        mReceiver.setReceiver(this);
    }

    public void startMyService() {
        final Intent intent = new Intent(getActivity(), MyService.class);
        intent.putExtra("receiver", mReceiver);
        getActivity().startService(intent);
    }

    @Override
    public void onReceiveResult(int resultCode, Bundle resultData) {
        // service finished
    }
}

public class MyService extends IntentService {
    ...
    @Override
    protected void onHandleIntent(Intent intent) {
        // download data and update database
        ....
        final ResultReceiver receiver = intent.getParcelableExtra("receiver");
        if (receiver != null) {
            receiver.send(0, null);
        }
    }
}

答案 1 :(得分:1)

由于您对将实际进度发布回UI并不是那么感兴趣,实现它的最简单方法是使用一对自定义广播,也可以使用静态布尔来显示运行状态。

基本上,您的服务可以在开始下载和完成下载时通知您的应用程序中感兴趣的任何组件。因此,您可以定义两个自定义操作字符串:

public static final String ACTION_DOWNLOADSTART = "com.mypackage.intent.ACTION_DOWNLOADSTART";
public static final String ACTION_DOWNLOADCOMPLETE = "com.mypackage.intent.ACTION_DOWNLOADCOMPLETE";

然后让您的服务在代码中的适当位置广播它们:

Intent start = new Intent(ACTION_DOWNLOADSTART);
sendBroadcast(start);

//...Service does its work

Intent finish = new Intent(ACTION_DOWNLOADCOMPLETE);
sendBroadcast(finish);

您可以使用BroadcastReceiver在应用程序的任何位置注册这些回调,并采取相应措施(例如,检查ContentProvider的状态并在必要时显示/隐藏进度。)

另一种常见做法是,如果您希望能够检查Service是否在任何给定点上运行,只需添加一个private static boolean成员即可在Service时切换}是活动的(可能在onCreate() / onDestroy()之间,但可能在其他地方)和一个像isRunning()这样的访问方法。然后,您的应用程序也可以通过调用该方法随时检查Service是否正在运行。