如何为跨类 Volley 方法调用创建适当的 Volley 侦听器

Posted

技术标签:

【中文标题】如何为跨类 Volley 方法调用创建适当的 Volley 侦听器【英文标题】:How to create a proper Volley Listener for cross class Volley method calling 【发布时间】: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 调用和从另一个类检索数据,特别是如何正确构建回调?

【问题讨论】:

【参考方案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”,不知道是不是你喜欢的。如果没有,我认为没有比你更漂亮的语法了。或者你可以在这里阅读***.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 版本问世之后。

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

【讨论】:

以上是关于如何为跨类 Volley 方法调用创建适当的 Volley 侦听器的主要内容,如果未能解决你的问题,请参考以下文章

如何为 Android M 及更高版本的 Volley 编写 OkHttp3 堆栈?

如何为适当的架构选择可执行的二进制文件?

我们如何为异步 .net 方法创建调用上下文?

如何为方法动态创建参数?

如何为多个 UILabel 创建一个 tapGestureRecognizer?

如何为本地通知界面编写适当的测试?