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