2

我有一个ContentProvider从sqlite数据库提取数据并通过Loader加载它。它由一个Service更新,它运行AsyncTask从服务器下载数据并在ContentProvider中更新它。我希望这是清楚,但可以肯定的:ContentProvider,Loader和ProgressBar

  • ListFragment通过Loader需要从ContentProvider数据,

  • ContentProvider得到了Service更新。现在

,当我的本地SQLite数据库是空的,我第一次启动该应用程序,这表明它没有事件,即使它们通过Service当前正在下载。我宁愿在此刻显示ProgressBar(无限旋转轮,不是酒吧)。但是,如果在没有数据库结果的情况下显示ProgressBar,那么即使在外部数据库中没有记录(在我的情况下经常出现)的情况下,在此特定情况下从服务器获取数据后,它也会在那里。所以:

  • 当数据由Service我 下载首次想显示进度直到ContentProvider给 非空的结​​果Service完成它的工作。

  • ContentProvider返回任何Service结束 它的工作(并取出空的结果)我想该应用显示 “没有发现任何结果”。

我的问题可能是:如何以通知Service仍在运行ListFragment或者说,它完成TS工作。我的意思是 - 我不应该在Service之内存储对调用Fragment的任何引用。它违背了ContentProviders的想法,不是吗?又怎样?

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

回答

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是否正在运行,只需调用该方法即可。

+0

非常感谢你们,我会在今天晚些时候看看你们的解决方案,但他们都看起来很有前途 – 2012-07-25 08:10:06

+0

我还没有写,但似乎你的第二个不足以满足我的情况。但是'BrodcastReceiver'看起来正是我正在寻找的东西。非常感谢你! – 2012-07-25 17:40:59

+0

LocalBroadcastManager对于这个特定的工作甚至更好:http://stackoverflow.com/questions/8802157/how-to-use-localbroadcastmanager。作品像一个魅力:) – 2012-07-25 18:37:21

1

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

其中之一是使用ResultReceiver并将其发送到IntentServiceIntent额外。

您创建自定义接收器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); 
     } 
    } 
} 
+0

'BroadcastReceiver'好像是一个更简单的解决方案+我的'Service'不是'IntentService'(或者它不是一个问题?),但是非常感谢您的回答! – 2012-07-25 17:41:50

+1

'IntentService'是一个已经实现了工作线程的'Service',这个方法是在谷歌I/O 2010应用程序中引入的。 – biegleux 2012-07-26 06:42:54

+1

一个建议的调整是让服务拥有对ServiceResultReceiver的WeakReference。如上所述,该服务将持有对启动它的Fragment的引用,从而防止其操作期间的垃圾收集。虽然这可能是故意的,但我的猜测是为了简单的例子。 – 2012-12-18 15:18:12