【问题标题】:How to create a proper Volley Listener for cross class Volley method calling如何为跨类 Volley 方法调用创建适当的 Volley 侦听器
【发布时间】:2016-02-05 17:58:46
【问题描述】:

我的目标是从另一个班级调用 Volley,这是一种非常简洁、模块化的方式,即:

            VolleyListener newListener = new VolleyListener();
            VolleySingleton.getsInstance().somePostRequestReturningString(getApplicationContext(), newListener);
            JSONObject data = newListener.getResponse();

但是让监听器部分工作以便能够从诸如

之类的方法访问结果数据时遇到了很多麻烦
newListener.getResponse();

本网站上的一些问题大致概述了如何从其他班级设置凌空呼叫,例如:Android Volley - How to isolate requests in another class。我已经成功地让方法调用工作了,但是现在将这些数据放入当前类以供使用已经造成了麻烦。

我的VolleySingleton 类中的操作为:

public void somePostRequestReturningString(final Context context,final VolleyListener<String> listener) {

        final String URL = "http://httpbin.org/ip";

        JsonObjectRequest set = new JsonObjectRequest(Request.Method.GET, URL, ((String) null),
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {

                        listener.outPut = response.toString();
                        //Toast.makeText(context, response.toString(), Toast.LENGTH_LONG).show();
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.d("Error.Response", error.toString());
                    }
                }
        );

        mRequestQueue.add(set);
}

在监听器类中:

public class VolleyListener {
    public static String outPut;

    private static Response.Listener<String> createSuccessListener() {
        return new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                outPut = response;
            }
        };
    }
}

如何配置它以使其工作并允许 Volley 调用和从另一个类检索数据,特别是如何正确构建回调?

【问题讨论】:

    标签: java android callback listener android-volley


    【解决方案1】:

    对于您的要求,我建议您参考我的以下解决方案,希望它清楚且有帮助:

    首先是界面

    public interface VolleyResponseListener {
        void onError(String message);
    
        void onResponse(Object response);
    }
    

    然后在你的助手类中(我将它命名为VolleyUtils 类):

    public static void makeJsonObjectRequest(Context context, String url, final VolleyResponseListener listener) {
            JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
                    (url, null, new Response.Listener<JSONObject>() {
    
                    @Override
                    public void onResponse(JSONObject response) {
                        listener.onResponse(response);
                    }
                }, new Response.ErrorListener() {
    
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        listener.onError(error.toString());
                    }
                }) {
    
            @Override
            protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
                try {
                    String jsonString = new String(response.data,
                            HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
                    return Response.success(new JSONObject(jsonString),
                            HttpHeaderParser.parseCacheHeaders(response));
                } catch (UnsupportedEncodingException e) {
                    return Response.error(new ParseError(e));
                } catch (JSONException je) {
                    return Response.error(new ParseError(je));
                }
            }
        };
    
        // Access the RequestQueue through singleton class.
        VolleySingleton.getInstance(context).addToRequestQueue(jsonObjectRequest);
    }
    

    然后,在你的 Activity 类中,你可以像下面这样调用:

    VolleyUtils.makeJsonObjectRequest(mContext, url, new VolleyResponseListener() {
            @Override
            public void onError(String message) {
    
            }
    
            @Override
            public void onResponse(Object response) {
    
            }
        });
    

    您可以参考以下问题了解更多信息(正如我昨天告诉您的):

    Android: How to return async JSONObject from method using Volley?

    POST Request Json file passing String and wait for the response Volley

    Android/Java: how to delay return in a method

    【讨论】:

    • 我不喜欢基本 Volley 语法,几乎与您在示例中的 Activity 类中放置的内容相同。我希望摆脱它的冗长本质并简化。如果那是不可能的/太多的努力是真正值得的,我可能只是继续前进。你怎么看?
    • 在我的第三个链接中,你会找到“Utils.makeJsonObjectRequest_Callable”,不知道是不是你喜欢的。如果没有,我认为没有比你更漂亮的语法了。或者你可以在这里阅读stackoverflow.com/questions/16904741/…
    【解决方案2】:

    Volley 擅长用于填充 UI 的 RPC 类型的操作,例如 获取一页搜索结果作为结构化数据。它集成了 轻松使用任何协议,开箱即用,支持原始 字符串、图像和 JSON。通过提供内置支持 您需要的功能,Volley 将您从编写样板代码和 允许您专注于特定于您的应用的逻辑。

    如何使用 Volley 创建通用 GET/POST 方法。

    创建应用程序类

    Android 中的 Application 类是 Android 中的基类 包含所有其他组件(例如活动和服务)的应用

        public class MyApplication extends Application {
    
        public static final String TAG = MyApplication.class
                .getSimpleName();
    
        private RequestQueue mRequestQueue;
    
        private static MyApplication mInstance;
    
        @Override
        public void onCreate() {
            super.onCreate();
            mInstance = this;
        }
    
        public static synchronized MyApplication getInstance() {
            return mInstance;
        }
    
        public RequestQueue getRequestQueue() {
            if (mRequestQueue == null) {
                mRequestQueue = Volley.newRequestQueue(getApplicationContext());
            }
    
            return mRequestQueue;
        }
    
        public <T> void addToRequestQueue(Request<T> req, String tag) {
            // set the default tag if tag is empty
            req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
            getRequestQueue().add(req);
        }
    
        public <T> void addToRequestQueue(Request<T> req) {
            req.setTag(TAG);
            getRequestQueue().add(req);
        }
    
        public void cancelPendingRequests(Object tag) {
            if (mRequestQueue != null) {
                mRequestQueue.cancelAll(tag);
            }
        }
    }
    

    确保添加此 Manifest 部分。

     <application
        .....
        android:name=".MyApplication"
        >
    

    现在,您需要创建 Singleton 类。

    单例模式说只定义一个只有一个的类 实例并提供对其的全局访问点。

       public class MySingleton
      {
        private static MySingleton mInstance;
        private RequestQueue mRequestQueue;
        private static Context mCtx;
    
        private MySingleton(Context context)
        {
            mCtx = context;
            mRequestQueue = getRequestQueue();
        }
    
        public static synchronized MySingleton getInstance(Context context)
        {
            if (mInstance == null)
            {
                mInstance = new MySingleton(context);
            }
            return mInstance;
        }
    
        public RequestQueue getRequestQueue()
        {
            if (mRequestQueue == null)
            {
                mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
            }
            return mRequestQueue;
        }
    
        public <T> void addToRequestQueue(Request<T> req)
        {
            getRequestQueue().add(req);
        }
    
     }
    

    现在通用类

     public class VolleyUtils {
    
        public static void GET_METHOD(Context context, String url, final VolleyResponseListener listener)
        {
    
            // Initialize a new StringRequest
            StringRequest stringRequest = new StringRequest(
                    Request.Method.GET,
                    url,
                    new Response.Listener<String>() {
                        @Override
                        public void onResponse(String response) {
                            listener.onResponse(response);
    
                        }
                    },
                    new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            listener.onError(error.toString());
    
                        }
                    })
    
            {
    
    
            };
    
            // Access the RequestQueue through singleton class.
            MySingleton.getInstance(context).addToRequestQueue(stringRequest);
        }
    
        public static void POST_METHOD(Context context, String url,final Map<String,String> getParams, final VolleyResponseListener listener)
        {
    
            // Initialize a new StringRequest
            StringRequest stringRequest = new StringRequest(
                    Request.Method.POST,
                    url,
                    new Response.Listener<String>() {
                        @Override
                        public void onResponse(String response) {
                            listener.onResponse(response);
    
                        }
                    },
                    new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            listener.onError(error.toString());
    
                        }
                    })
    
            {
    
                /**
                 * Passing some request headers
                 * */
                @Override
                public Map<String, String> getHeaders() throws AuthFailureError {
                    HashMap<String, String> headers = new HashMap<String, String>();
                    getParams.put("Content-Type", "application/json; charset=utf-8");
                    return headers;
                }
    
            };
    
            // Access the RequestQueue through singleton class.
            MySingleton.getInstance(context).addToRequestQueue(stringRequest);
        }
    }
    

    现在您应该创建 Interface

    一个类实现一个接口,从而继承抽象 接口的方法。

     /**
     * Created by Intellij Amiyo  on 10-06-2017.
     * Please follow standard Java coding conventions.
     * http://source.android.com/source/code-style.html
     */
    public interface VolleyResponseListener {
    
        void onError(String message);
    
        void onResponse(Object response);
    }
    

    如何打电话

    public void _loadAPI()
    {
        //GET 
        String URL_GET = "";
        VolleyUtils.GET_METHOD(MainActivity.this, URL_GET, new VolleyResponseListener() {
            @Override
            public void onError(String message) {
                System.out.println("Error" + message);
            }
    
            @Override
            public void onResponse(Object response) {
    
                System.out.println("SUCCESS" + response);
            }
        });
    
    
        //POST
        String URL_POST=" ";
        VolleyUtils.POST_METHOD(MainActivity.this, URL_POST,getParams(), new VolleyResponseListener() {
            @Override
            public void onError(String message) {
                System.out.println("Error" + message);
            }
    
            @Override
            public void onResponse(Object response) {
    
                System.out.println("SUCCESS" + response);
            }
        });
    
    
    }
    
    public Map<String,String> getParams()
    {
        Map<String, String> params = new HashMap<String, String>();
        params.put("YOUR_KEY", "VALUE");
        return params;
    }
    

    对于演示,您应该下载Volley-Common-Method

    【讨论】:

      【解决方案3】:

      如果您遵循Android Volley - How to isolate requests in another class 中的一般示例,(包括有关单例的东西)并寻找解析部分(或者,如何实际使用您收到的对象),那么这是(再次非常笼统的)添加

      假设你有一个 Json 对象进来,看起来有点像这样:

      {“用户”: [{"username":"Jon Doe","userid":83}, {"username":"Jane Doe",userid":84}]}

      我们的用户对象看起来像这样:

      public class User
      {
       String username;
       int userid;
      
       public String getName()
       {
       return username;
       }
      
       public int getId()
       {
       return userid;
       }
      }
      

      重要提示:使用 Gson 时(稍后会看到),对象 字段应根据您在 Json 中获得的参数命名,这 某种反射是解析的工作方式。

      然后,请求本身看起来像这样 (注意监听器回调返回一个

      List<User>
      

      对象返回给调用者,稍后你会看到):

      public class NetworkManager
      {
      
       //... other stuff
      
       public void getUsers(final SomeCustomListener<List<User>> listener)
       {
          final String URL = "http://httpbin.org/ip";
      
          StringRequest request = new StringRequest(Request.Method.GET, url,
                  new Response.Listener<String>()
                  {
                      @Override
                      public void onResponse(String response)
                      {
                          Log.d(TAG + ": ", "getUsers Response: " + response);
                          List<User> users = MyJsonParser.getListObjects(response, "$.users[*]", User.class);
      
                          if(null != users)
                            listener.getResult(users);
                      }
                  },
                  new Response.ErrorListener()
                  {
                      @Override
                      public void onErrorResponse(VolleyError error)
                      {
                          if (null != error.networkResponse)
                          {
                              Log.d(TAG + ": ", "Error Response code: " + error.networkResponse.statusCode);
                              listener.getResult(null);
                          }
                      }
                  });
          requestQueue.add(request);
      
       // ... other stuff
      }
      

      您现在需要的是解析 Json 字符串的类,即对象列表,在此示例中我使用 Gson(再次 - 这是一个通用示例,根据您的需要更改和重新排序内容,您可能还可以再优化一下——这只是为了解释):

      public class MyJsonParser
      {
       //... other stuff
       public static <T> List<T> getListObjects(String json_text, String json_path, Class<T> c)
       {
          Gson gson = new Gson();
          try
          {
              List<T> parsed_list = new ArrayList<>();
              List<Object> nodes = JsonPath.read(json_text, json_path);
      
              for (Object node : nodes)
              {
                  parsed_list.add(gson.fromJson(node.toString(), c));
              }
              return (parsed_list);
          }
          catch (Exception e)
          {
              return (new ArrayList<>());
          }
       }
       //... other stuff
      }
      

      所以,在我们有了所有这些(以及前面提到的 SO 问题中的以下内容)之后,您所说的您正在寻找的是工作代码中的回调,这可以通过以下几种方式实现:

      直截了当:

      只需调用该方法并在那里覆盖它的回调,例如:

      public class SomeClass
      {
      
       private List<User> mUsers;
      
       private void someMethod()
       {
        // ... method does some stuff
      
          NetworkManager.getInstance().getUsers(new SomeCustomListener<List<User>>()
          {
              @Override
              public void getResult(List<User> all_users)
              {
                  if (null != allUsers)
                  {
                      mUsers = allUsers;
                      // ...  do other stuff with our info
                  }
              }
          });
      
         // ... method does some more stuff
        }
      }
      

      或者,以间接方式(考虑时间、内存消耗等),您可以将获得的信息保存在同一个 Singelton(或另一个容器)中,并创建一个 get 方法,稍后再获取对象(看起来更漂亮)

      记住:触发请求之前(考虑到响应的延迟),因为这些回调的性质取决于可能延迟的响应。

      它看起来像这样:

      private List<User> mUsers;
      
      private void someMethod()
      {
       // ... method does some stuff
      
       mUsers = NetworkManager.getInstance().getUsersObject();
      
       // ... method does some more stuff
      }
      

      完全不同的选择是考虑使用Retrofit,它为您进行解析,使用注释,并且据说速度更快,这可能是您正在寻找的(对于流线型外观) - 我会阅读基准,尤其是在新的 2.0 版本问世之后。

      希望这会有所帮助(虽然有点晚了)! :)

      【讨论】:

        猜你喜欢
        • 2021-09-12
        • 2016-05-09
        • 1970-01-01
        • 1970-01-01
        • 2016-06-08
        • 2018-05-20
        • 1970-01-01
        • 2016-06-04
        • 2018-10-14
        相关资源
        最近更新 更多