【问题标题】:Android Offline Request with Volley使用 Volley 的 Android 离线请求
【发布时间】:2015-07-25 15:24:59
【问题描述】:

我想为我的用户提供更好的离线用户体验,因此,我想构建一个 Service 来存储所有 POSTDELETEPUTGET 没有意义,因为GET 没有网络的调用是缓存调用)请求用户离线并在用户获得互联网连接后立即将它们发送到服务器。我希望它是持久的:即使应用程序被终止,数据也会被发送,以免缓存和服务器数据之间出现不一致。

我对 Google Volley 和 Android Networking API 非常熟悉 --> 我知道如何检测没有网络、如何预取数据、缓存它们等等......

但是有关于这个主题的要点或图书馆吗?我知道最新的 Facebook 版本实现了这样的系统,但我想知道他们是如何做到的(我的意思是,我知道使用了 Service,但他们究竟是如何做到的,不知道!)。有人对此有想法吗,有经验吗?

【问题讨论】:

  • 关于持久化服务,你看过this question了吗
  • 是的,我做到了,但我想知道是否有一些不太通用的东西:)
  • 您可以查看RobospiceRetrofit 库...它使用服务向服务器发送请求,如果应用程序离线,您可以从缓存中获取数据。但我认为当您退出应用程序时服务会被破坏。希望对您有所帮助...
  • 这可以完成这项工作,这是真的,似乎有点矫枉过正,但最后,这可能是最好的方法

标签: android caching android-volley


【解决方案1】:

您需要使用 BroadcastReceiver 来监听网络变化事件。使用以下操作在您的 AndroidManifest.xml 中定义一个 broadcastReciver。

<receiver android:name=".NetworkBroadcastReceiver" >
     <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
     </intent-filter>
</receiver>

还将以下权限添加到您的清单文件中 -

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

NetworkBroadcastReceiver -

public class NetworkBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, final Intent intent) {

        if(isInternetConnected(context)) {
            //Do something i.e. trigger an API call or start a IntentService etc.
        }    
    }


    public boolean isInternetConnected(Context context) {
        ConnectivityManager connectivityManager 
            = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        return activeNetworkInfo != null && activeNetworkInfo.isConnected();
    }    
}

这就是您在上网后立即提出请求所需要做的一切。

要缓存数据,我建议您解析服务器响应并将其保存在数据库中以供离线使用。每次您发出成功的请求时,都将新数据保存在数据库中并丢弃旧数据。当用户启动应用程序时,首先从数据库中加载数据,然后触发 Volley 请求,如果请求成功,则将新数据加载到应用程序中,将其存储在数据库中并删除旧数据。所以如果请求失败,用户仍然可以看到之前成功请求的旧数据。

要处理应用程序和服务器中的数据不一致,您需要使用 SyncAdapter。 SyncAdapter 为后台的定期同步提供了很好的支持。只需将同步代码放在 SyncAdapter 的 onPerformSync() 方法中即可。它可能不适用于以下两种情况 - 1.如果用户没有连接到互联网 2. 如果用户设备已关闭

要处理这些情况,请使用我在上面回答中解释的 BroadCastReceiver 来触发 SyncAdapter。还将以下操作添加到 AndroidManifest.xml 中的接收器,以监听设备的启动完成事件。

<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />

如果您需要通过编码示例进行更深入的解释,请告诉我。希望对你有帮助

【讨论】:

    【解决方案2】:

    看看我遇到的这个库 - Android Priority Job Queue.

    您将后台任务定义为作业并将它们排入您的队列中 JobManager 实例。作业经理将处理优先级, 持久化、负载均衡、延迟、网络控制、分组等。 它还为您的工作提供了一个很好的生命周期,以提供更好的、 一致的用户体验。

    此外,它们还监控网络连接。当设备离线时,需要网络连接的作业在网络连接恢复之前不会运行。

    【讨论】:

    • 我明白了,我会看看,因为我几乎写了这个库来满足这个需求...#stupid Thx mate
    【解决方案3】:

    你可能会做一个网络验证方法:
    1.检查网络连接
    是的:
    a) 提出截击请求
    b) 从 volley 请求中解析适配器
    c) 并将 json 保存到私有文件中

    否:
    a) 读取私有文件
    b) 从下载的 json 文件中制作适配器。

    **********************例如

        if(isconnect){   
        JsonArrayRequest Req = new JsonArrayRequest(url,
                new Response.Listener<JSONArray>() {
                    public void onResponse(JSONArray response) {
                      //this the request of your http request 
                       Log.d(TAG, response.toString());
                         // Parsing json
                          for (int i = 0; i < response.length(); i++) {
                            try {
                             ......adapter etc etc
                             }
                            adapter.notifyDataSetChanged();
                            //here write the httprequest (json file) in local memory 
                              try {
                              String textjson= response.toString();
                              fos = context.openFileOutput("request.json",MODE_PRIVATE);
                              fos.write(textjson.getBytes("ISO-8859-1")); //encode
                              fos.close();
                              } catch (IOException e) {
                                 // TODO Auto-generated catch block
                                 e.printStackTrace();
                              }
                        swipeRefreshLayout.setRefreshing(false);  
                     }  
                  }, new Response.ErrorListener() {
                   @Override
                   public void onErrorResponse(VolleyError error) {
                   // VolleyLog.d(TAG, "Error: " + error.getMessage());
                 }   });      AppController.getInstance().addToRequestQueue(movieReq);
                                }
                            else{
                                //noconnection();
                                in the noconnection method u can parse the               listview/recyclerview from json file to make the offline mode } 
    }else{
        //parse the listview/recyclerview from local file. }
    

    【讨论】: