精华内容
下载资源
问答
  • 該函數僅會調用StreamAllocation的cancel函數,且最終調用到RealConnection的cancel函數: public void cancel() { // Close the raw socket so we don't end up doing synchronous I/O. Util.closeQuietly(raw...

    在Android中,我們訪問網絡時,最簡單的方式類似與:

    HttpURLConnection connection = null;

    try {

    //xxxxx為具體的網絡地址

    URL url = new URL("xxxxx");

    connection = (HttpURLConnection) url.openConnection();

    connection.connect();

    //進行一些操作

    ...............

    } catch (IOException e) {

    e.printStackTrace();

    } finally {

    if (connection != null) {

    connection.disconnect();

    }

    }

    最近在8.0的手機里跑類似上述代碼時,突然發現會概率性地打印類似如下的log:

    A connection to xxxxxx was leaked. Did you forget to close a response body?

    仔細check了一下代碼,發現connection用完后,已經disconnect了,

    怎么還會打印這種讓人覺得不太舒服的代碼?

    為了解決這個問題,在國內外的網站上找了很久,

    但都沒能找到真正可行的解決方案。

    無奈之下,只好硬擼了一邊源碼,總算是找到了問題的原因和一個解決方案。

    因此,在本片博客中記錄一下比較重要的地方。

    Android的源碼中,我們知道URL的openConnection函數的底層實現依賴於OkHttp庫,

    對於這部分的流程,我之后專門寫一篇文檔記錄一下。

    現在我們需要知道的是:

    OkHttp庫中的創建的Http鏈接為RealConnection對象。

    為了達到復用的效果,OkHttp專門創建了ConnectionPool對象來管理所有的RealConnection。

    這有點像線程池會管理所有的線程一樣。

    當我們創建一個新的RealConnection時,會調用ConnectionPool的put函數:

    void put(RealConnection connection) {

    assert (Thread.holdsLock(this));

    if (connections.isEmpty()) {

    //執行一個cleanupRunnable

    executor.execute(cleanupRunnable);

    }

    //將新的connection加入池子中

    connections.add(connection);

    }

    現在,我們來看看cleanupRunnable會干些啥:

    private Runnable cleanupRunnable = new Runnable() {

    @Override public void run() {

    while (true) {

    //容易看出,其實就是周期性地執行cleanup函數

    long waitNanos = cleanup(System.nanoTime());

    if (waitNanos == -1) return;

    if (waitNanos > 0) {

    long waitMillis = waitNanos / 1000000L;

    waitNanos -= (waitMillis * 1000000L);

    synchronized (ConnectionPool.this) {

    try {

    ConnectionPool.this.wait(waitMillis, (int) waitNanos);

    } catch (InterruptedException ignored) {

    }

    }

    }

    }

    }

    };

    cleanup函數的真面目如下:

    long cleanup(long now) {

    //記錄在使用的connection

    int inUseConnectionCount = 0;

    //記錄空閑的connection

    int idleConnectionCount = 0;

    //記錄空閑時間最長的connection

    RealConnection longestIdleConnection = null;

    //記錄最長的空閑時間

    long longestIdleDurationNs = Long.MIN_VALUE;

    synchronized (this) {

    for (Iterator i = connections.iterator(); i.hasNext(); ) {

    RealConnection connection = i.next();

    // If the connection is in use, keep searching.

    // 輪詢每一個RealConnection

    if (pruneAndGetAllocationCount(connection, now) > 0) {

    inUseConnectionCount++;

    continue;

    }

    idleConnectionCount++;

    //找到空閑時間最長的RealConnection

    long idleDurationNs = now - connection.idleAtNanos;

    if (idleDurationNs > longestIdleDurationNs) {

    longestIdleDurationNs = idleDurationNs;

    longestIdleConnection = connection;

    }

    }

    //空閑時間超過限制或空閑connection數量超過限制,則移除空閑時間最長的connection

    if (longestIdleDurationNs >= this.keepAliveDurationNs

    || idleConnectionCount > this.maxIdleConnections) {

    // We've found a connection to evict. Remove it from the list, then close it below (outside

    // of the synchronized block).

    connections.remove(longestIdleConnection);

    } else if (idleConnectionCount > 0) {

    // A connection will be ready to evict soon.

    //返回下一次執行cleanup需等待的時間

    return keepAliveDurationNs - longestIdleDurationNs;

    } else if (inUseConnectionCount > 0) {

    // All connections are in use. It'll be at least the keep alive duration 'til we run again.

    // 返回最大可等待時間

    return keepAliveDurationNs;

    } else {

    // No connections, idle or in use.

    return -1;

    }

    }

    //特意放到同步鎖的外面釋放,減少持鎖時間

    Util.closeQuietly(longestIdleConnection.getSocket());

    return 0;

    }

    通過cleanup函數,不難看出該函數主要的目的就是:

    逐步清理connectionPool中已經空閑的RealConnection。

    現在唯一的疑點就是上文中的pruneAndGetAllocationCount函數了:

    /**

    * Prunes any leaked allocations and then returns the number of remaining live allocations on

    * {@code connection}. Allocations are leaked if the connection is tracking them but the

    * application code has abandoned them. Leak detection is imprecise and relies on garbage

    * collection.

    */

    private int pruneAndGetAllocationCount(RealConnection connection, long now) {

    //獲取使用該RealConnection的對象的引用

    List> references = connection.allocations;

    for (int i = 0; i < references.size(); ) {

    Reference reference = references.get(i);

    //引用不為null,說明仍有java對象持有它

    if (reference.get() != null) {

    i++;

    continue;

    }

    //沒有持有它的對象,說明上層持有RealConnection已經被回收了

    // We've discovered a leaked allocation. This is an application bug.

    Internal.logger.warning("A connection to " + connection.getRoute().getAddress().url()

    + " was leaked. Did you forget to close a response body?");

    //移除引用

    references.remove(i);

    connection.noNewStreams = true;

    // If this was the last allocation, the connection is eligible for immediate eviction.

    //沒有任何引用時, 標記為idle,等待被cleanup

    if (references.isEmpty()) {

    connection.idleAtNanos = now - keepAliveDurationNs;

    return 0;

    }

    }

    return references.size();

    }

    從上面的代碼可以看出,pruneAndGetAllocationCount發現沒有被引用的RealConnection時,

    就會打印上文提到的leaked log。

    個人猜測,如果開頭的代碼執行完畢后,GC先回收HttpURLConnection(非直接持有)等持有RealConnection的對象,后回收RealConnection。

    且在回收HttpURLConnection后,回收RealConnection前,剛好執行了pruneAndGetAllocationCount,就可能會打印這種log。

    這也是注釋中提到的,pruneAndGetAllocationCount依賴於GC。

    不過從代碼來看,這並沒有什么問題,Android系統仍會回收這些資源。

    在文章開頭的代碼中,最后調用的HttpURLConnection的disconnect函數。

    該函數僅會調用StreamAllocation的cancel函數,且最終調用到RealConnection的cancel函數:

    public void cancel() {

    // Close the raw socket so we don't end up doing synchronous I/O.

    Util.closeQuietly(rawSocket);

    }

    可以看出,該方法僅關閉了socket,並沒有移除引用,不會解決我們遇到的問題。

    經過不斷地嘗試和閱讀源碼,我發現利用下述方式可以解決這個問題:

    HttpURLConnection connection = null;

    try {

    //xxxxx為具體的網絡地址

    URL url = new URL("xxxxx");

    connection = (HttpURLConnection) url.openConnection();

    connection.connect();

    //進行一些操作

    ...............

    } catch (IOException e) {

    e.printStackTrace();

    } finally {

    if (connection != null) {

    try {

    //主動關閉inputStream

    //這里不需要進行判空操作

    connection.getInputStream().close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    connection.disconnect();

    }

    }

    當我們主動關閉HttpURLConnection的inputStream時,將會先后調用到StreamAllocation的noNewStreams和streamFinished函數:

    public void noNewStreams() {

    deallocate(true, false, false);

    }

    public void streamFinished(HttpStream stream) {

    synchronized (connectionPool) {

    if (stream == null || stream != this.stream) {

    throw new IllegalStateException("expected " + this.stream + " but was " + stream);

    }

    }

    //調用deallocate

    deallocate(false, false, true);

    }

    //連續調用兩次,第1、3個參數分別為true

    private void deallocate(boolean noNewStreams, boolean released, boolean streamFinished) {

    RealConnection connectionToClose = null;

    synchronized (connectionPool) {

    if (streamFinished) {

    //第二次,stream置為null

    this.stream = null;

    }

    if (released) {

    this.released = true;

    }

    if (connection != null) {

    if (noNewStreams) {

    //第一次,noNewStreams置為true

    connection.noNewStreams = true;

    }

    //stream此時為null, 其它兩個條件滿足一個

    if (this.stream == null && (this.released || connection.noNewStreams)) {

    //就可以執行release函數

    release(connection);

    if (connection.streamCount > 0) {

    routeSelector = null;

    }

    //idle的RealConnection可以在下文被關閉

    if (connection.allocations.isEmpty()) {

    connection.idleAtNanos = System.nanoTime();

    if (Internal.instance.connectionBecameIdle(connectionPool, connection)) {

    connectionToClose = connection;

    }

    }

    connection = null;

    }

    }

    }

    if (connectionToClose != null) {

    Util.closeQuietly(connectionToClose.getSocket());

    }

    }

    //最后看看release函數

    private void release(RealConnection connection) {

    for (int i = 0, size = connection.allocations.size(); i < size; i++) {

    Reference reference = connection.allocations.get(i);

    //移除該StreamAllocation對應的引用

    //解決我們遇到的問題

    if (reference.get() == this) {

    connection.allocations.remove(i);

    return;

    }

    }

    throw new IllegalStateException();

    }

    到此,我們終於知道出現該問題的原因及對應的解決方案了。

    上述代碼省略了HttpURLConnection及底層OkHttp的許多流程,

    僅給出了重要的部分,后續我會專門寫一篇博客來補充分析這部分代碼。

    這個問題說實話,個人感覺並不是很重要,

    但想真正明白原理,還是需要細致閱讀源碼的。

    一旦真正搞懂,確實有點GAI爺歌里的感覺:

    一往無前虎山行,撥開雲霧見光明。

    展开全文
  • :param verify: (optional) Either a boolean, in which case it controls whether we verify the server's TLS certificate, or a string, in which case it must be a path to a CA bundle to use. Defaults to `...

    嗨各位大佬好,我现在是应接不暇,无暇顾及我的模型种种,只因忙于内卷,这个问题不想面对却始终无法逃脱,我特么一腔热血洒热土。大佬让用用es呗,不好意思,不给你用,我特么。。还有。。算了算了,小明哥不是一般的小明哥,加油吧。总有柳暗花明之时,而你还记得我们曾经讨论的话题。相关博文阅读:服务端设置

    For Recommendation in Deep learning QQ Group 277356808

    For Visual in deep learning QQ Group 629530787

    I'm here waiting for you

    不接受这个网页的私聊/私信!!!

     1-首先下载postman请求通过了,感谢运维同事大佬。

    get请求地址是对应的单个id查询,post是多个,其中相同的是账号密码都在下面输入

    get请求的参数可以直接放在params中k-v,其实就是地址上带参数

    其中header相同的是json,另外一个也相同,是http服务方提供的监控项,加入白名单所用的,小明哥不知道咋整的监控,不表。

    post请求的参数不放在params,而是body-raw下json格式,如下,可能其他情况也可,这里符合http服务方要求。

    2-py脚本请求(当然也可用java格式的,阿里有个fastjson模块包装)

    首先使用get请求,先看下其解释,意思是参数不全,需要参考另一个函数的

    >>> help(requests.get)
    Help on function get in module requests.api:
    
    get(url, params=None, **kwargs)
        Sends a GET request.
        
        :param url: URL for the new :class:`Request` object.
        :param params: (optional) Dictionary, list of tuples or bytes to send
            in the query string for the :class:`Request`.
        :param \*\*kwargs: Optional arguments that ``request`` takes.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
    >>> help(requests.request)
    Help on function request in module requests.api:
    
    request(method, url, **kwargs)
        Constructs and sends a :class:`Request <Request>`.
        
        :param method: method for the new :class:`Request` object.
        :param url: URL for the new :class:`Request` object.
        :param params: (optional) Dictionary, list of tuples or bytes to send
            in the query string for the :class:`Request`.
        :param data: (optional) Dictionary, list of tuples, bytes, or file-like
            object to send in the body of the :class:`Request`.
        :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
        :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
        :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
        :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload.
            ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')``
            or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string
            defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers
            to add for the file.
        :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
        :param timeout: (optional) How many seconds to wait for the server to send data
            before giving up, as a float, or a :ref:`(connect timeout, read
            timeout) <timeouts>` tuple.
        :type timeout: float or tuple
        :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``.
        :type allow_redirects: bool
        :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
        :param verify: (optional) Either a boolean, in which case it controls whether we verify
                the server's TLS certificate, or a string, in which case it must be a path
                to a CA bundle to use. Defaults to ``True``.
        :param stream: (optional) if ``False``, the response content will be immediately downloaded.
        :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response

    本文也推荐这个函数,直接GET与POST都可以用这个函数,只是换了个参数(method)这就简单多了。重点参数如下:

    method
    url
    params: (optional) Dictionary, list of tuples or bytes to send
    data: (optional) Dictionary, list of tuples, bytes, or file-like
    headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
    auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
    timeout: (optional) How many seconds to wait for the server to send data
    

    get请求通过,按照上面的参数介绍写格式即可,注意auth是账号密码的元组(),下面看post多个ids请求,只需将请求的参数采用json.dumps包装一下即可解决,perfect!

    拜拜,愿我们终有重逢之时,而你还记得我曾经的微笑。

     

    展开全文
  • growup_grow 和grow up 的区别

    千次阅读 2020-12-23 20:02:25
    广告位API接口通信错误,查看德得广告获取帮助grow 和grow up 的区别grow和grow up的区别如下。grow可以作及物动词或不及物动词,也可以作联系动词,表示成长、种植或变得怎么样的意思,如:一、及物动词用法。I ...

    广告位API接口通信错误,查看德得广告获取帮助

    grow 和grow up 的区别

    grow和grow up的区别如下。

    grow可以作及物动词或不及物动词,也可以作联系动词,表示成长、种植或变得怎么样的意思,如:

    一、及物动词用法。

    I always grow a few red onions.

    Lettuce was grown by the Ancient Romans.

    I started growing my hair.

    二、不及物动词用法。

    We stop growing at maturity.

    The hair began to grow again and I felt terrific.

    They began to grow as persons.

    三、联系动词用法:

    He is growing old.

    Faint grew the sound of the bell.

    The hair of the dog grows thick.

    grow up只有不及物动词的用法,表示长大成人,成熟的意思,如果主语为事物,则表示形成、兴起或逐渐发展的意思,如:

    She grew up in Tokyo.

    It is time that my son grew up.

    A variety of heavy industries grew up alongside the port.

    grow up的歌词翻译中文

    歌曲:Grow Up

    歌手:Cher Lloyd / Busta Rhymes

    所属专辑:Sticks & Stones

    We ain't ever gonna grow up

    我们永远长不大

    We just wanna get down

    我们只想躁起来

    Tell the DJ turn it up real loud

    告诉DJ把音量调大

    No we'll never grow up

    不我们永远长不大

    And if we had our way

    如果我们有自己的路

    We would do this everyday

    我们将会每天这样

    I got a flow that'll make you drop

    我会让你掉下来

    I got a flow that'll make you pop

    我会让你躁起来

    I got a flow that'll make your mother and your father call the cops

    我会让你爸爸妈妈打电话叫警察

    We're gon make this go blow we gon system overload

    我们要让它升天,让系统过载

    We're gonna be the generation that makes everything explode

    我们这一代人要让世界爆炸

    And when I say explode I don't mean that we're using bombs

    我说的爆炸不是说我们要用炸药

    We're doing stuff that we don't ever have to tell our mums

    我们正在做一些从来没要告诉妈妈的事

    Love this stuff we got, we got it all up in a bomb

    我们喜欢我们做的事,比炸弹还重要的事

    Paper chasin' girl divided everything we won

    我们赢的东西都被追逐成绩的女孩破坏

    Somehow someway

    不知怎的,不知如何

    We're gonna have it our way

    我们将用自己的方式

    We don't give a what what you say

    我们不会放弃你所说的

    No we don't

    不,我们不会

    We ain't ever gonna grow up

    我们永远长不大

    We just wanna get down

    我们只想躁起来

    Tell the DJ turn it up real loud

    告诉DJ把音量调大

    No we'll never grow up

    我们永远长不大

    And if we had our way

    如果我们有自己的路

    We would do this everyday

    我们将会每天这样

    We ain't ever gonna grow up

    我们永远长不大

    We just wanna get down

    我们只想躁起来

    Show everybody who runs this town

    告诉所有人这个地方谁说了算

    No we'll never grow up

    我们永远长不大

    And if we had our way

    如果我们有自己的路

    We would do this everyday

    我们将会每天这样

    Do you, do you, do you know what I mean

    你知道我什么意思吗,什么意思吗,么意思吗,意思吗,思吗,吗

    I'm a princess I don't wanna be the queen

    我是国王,我不想当王后

    Please don't say a thing Mr Bean

    憨豆先生请不要再说了

    Every time you talk grr it makes me wanna scream

    每次你一张嘴说话都让我想要尖叫

    I don't know what you heard bout me

    我不知道你听了关于我的哪些谣言

    Don't make me hold out my pinky

    别逼我抓着自己的小指

    I'm gonna finish off these MCs

    我会收拾这烂摊子

    Like they were my cup of tea

    就像是杯子里的茶

    I got a flow that'll make you drop

    我会让你掉下来

    I got a flow that'll make you pop

    我会让你躁起来

    I got a flow that'll make your mother and your father call the cops

    我会让你爸爸妈妈打电话叫警察

    Somehow, someway

    不知怎的,不知如何

    We're gonna have it our way

    我们将有自己的路

    We don't give a what saywhat you

    我们不在乎你说什么

    No we don't

    不,我们不会

    We ain't ever gonna grow up

    我们永远长不大

    We just wanna get down

    我们只想躁起来

    Tell the DJ turn it up real loud

    告诉DJ把音量调大

    No we'll never grow up

    我们永远长不大

    And if we had our way

    如果我们有自己的路

    We would do this everyday.

    我们将会每天这样

    We ain't ever gonna grow up

    我们永远长不大

    We just wanna get down

    我们只想躁起来

    Show everybody who runs this town

    告诉所有人这个地方谁说了算

    No we'll never grow up

    我们永远长不大

    And if we had our way

    如果我们有自己的路

    We would do this everyday

    我们将会每天这样

    Bulls-eye again

    又一次正中靶心

    I got'em in a target put'em in a pocket put'em on a market

    我把它们放在靶上,放在兜里,放在菜市场

    That's the way we live you can see the way I walk and I talk

    这是我们生活的方式,你能看到我怎样走路和说话

    Every time I show up I got'em strung I don't grow wanna up forever young

    每一次我炫耀着上弦,我不想长大,想永远年轻

    No I never wanna leave you better believe me trust me she is the one

    不,我从不想离你而去,相信我她是唯一

    Gonna make all the people get up pump they fist when they hear that beat

    要让听到这个节奏的人们挥起拳头

    We gonna jump like this, leanin bend they body all around

    我们将会像这样跳,让他们的身体到处旋转

    And then they gonna turn and twist

    他们会转过身扭成一团

    I guess it's time for pictures and my close-up

    我想是时候给我个特写拍些照片了

    I can do this till infinity I pray I never grow up

    我能永无止境地做下去,我祈祷我永远不长大

    We ain't ever gonna grow up

    我们永远长不大

    We just wanna get down

    我们只想躁起来

    Show everybody who runs this town!

    告诉所有人这个地方谁说了算

    No we'll never grow up

    我们永远长不大

    And if we had our way

    如果我们有了自己的路

    We would do this everyday.

    我们将会每天这样

    We ain't ever gonna grow up

    我们永远长不大

    We just wanna get down

    我们只想躁起来

    Tell the DJ turn it up real loud

    告诉DJ把音量调大

    No we'll never grow up

    我们永远长不大

    And if we had our way

    如果我们有了自己的路

    We would do this everyday.

    我们将会每天这样

    We ain't ever gonna grow up

    我们永远长不大

    We just wanna get down

    我们只想躁起来

    Show everybody who runs this town!

    告诉所有人这个地方谁说了算

    No we'll never grow up

    我们永远长不大

    And if we had our way

    如果我们有了自己的路

    We would do this everyday.

    我们每天都会这样

    grow up 和grow into的区别

    grow into表示 长成,变为,更强调结果。

    grow up 表示成熟了,长大成人,更强调过程。

    ggrow up更强调结果 grow 表示长大、长高等更强调过程。

    例如:1、Their childern have all grown up and left home now. 他们的孩子都已长大成人离开家。

    2、In its natural habitat, the hibiscus will grow up to 25ft. 在原生境中,木槿能长到25英尺高。

    grow into例如:1、It's a bit big, but she'll soon grow into it. 这件衣服稍大了点,但是过不了多久她就会长到可以穿了。

    grow up 和 grow into 的区别

    grow up是长大,后面不加宾语, grow into 是长成。。。或者发展成。。。 后面需要加宾语。

    例如:she has grown into a beautiful young lady. 说长成。。。 用grow up into 也行,很牵强,罗嗦。没必要

    grow up和 grow old的区别

    grow up是长大的意思,较用于小孩成年后

    例:I want to be a teacher when I grow up当我长大后我想当一名老师

    而grow old是成熟,老去的意思,较用于中年人老了以后

    例:Those who love deeply never grow old那些彼此深爱的人会永保青春。

    这里的never grow old是不会老去的意思

    grow up\ grown-up\grown up这些有什么区别

    grow up\ grown-up\grown u的区别:

    1、三者词性不同。grow up,是一个短语且是一个动词;grown-up只算一个词,形容词,用于修饰名词;grown up则只是grow up的过去分词。

    2、三者用法不同。grow up是动词可以做谓语;grown-up性质是形容词,可以做定语;而grown up往往应用于完成时态。

    3、举例比较:

    I want to be a pilot when I grow up. 我想长大后当飞行员。

    What do you want to be when you're grown-up?你长大后想做什么?

    A new town has grown up in this industrial district. 在这个工业区兴起了一座新城市。

    扩展资料:

    与grow搭配的短语动词:

    1、grow apart:(关系)变得有隔阂,逐渐疏远

    2、grow into:长得适合穿

    3、grow on:越来越被…喜欢;逐渐为…所喜爱

    4、grow out of:1(因自身长大或改变而)改掉(或戒除)(习惯、爱好等); 2(孩子)长大穿不下(原来的衣服)

    5、grow up;1长大成人;成熟;2别犯傻;别孩子气; 3形成;兴起;逐渐发展

    grow与grow up的区别

    grow up

    v.

    长大, 成人, 崛起

    he was grew in a small village

    grow

    [^rEu]

    vi.

    生长, 成长, 渐渐变得, 增长, 增高

    vt.

    种植, 栽培, 培育

    He grows vegetables.

    他种植蔬菜

    bring up 与grow up 有何区别

    grow up

    成长,逐渐形成

    bring up

    提出;教育;养育;呕出;(船等)停下。

    I grew up in China. 我在中国长大。

    I was brought up by my parents.我是父母带大的。

    都是动词词组 grow up不及物,bring up及物并且是 主语对谓语的一种行文。

    纯手打,望~

    grow 和grow up有什么区别?

    grow是长大,gorw up是生长

    grow up 和grow on的区别

    grow up,长大

    补充

    grow on,正在长大

    (责任编辑:admin)

    展开全文
  • Android Volley解析(一)之GET、POST请求篇

    万次阅读 多人点赞 2015-03-09 16:05:28
    // Create network dispatchers (and corresponding threads) up to the pool size. //启动网络请求处理线程,默认为5个,可以自己设定 size for ( int i = 0 ; i ; i++) { NetworkDispatcher ...

    一、 Volley 的地位

    自2013年Google I/O 大会上,Google 推出 Volley 之后,一直到至今,由于其使用简单、代码轻量、通信速度快、并发量大等特点,倍受开发者们的青睐。
    先看两张图,让图片告诉我们 Volley 的用处;
    第一张 Volley 的经典图
    这里写图片描述
    通过上图,我们可以发现 Volley适合网络通信频繁操作,并能同时实现多个网络通信。
    第二张图
    这里写图片描述
    我们在以前在 ListView 的 item 中如果有网络请求,一般都是通过Task 异步任务来完成,并在完成之后通知 Adapter 更新数据。而Volley 不需要这么麻烦,因为里面已经为我们封装好了处理的线程,网络请求,缓存的获取,数据的回掉都是对应不同的线程。

    二、Volley使用步骤及基本分析

    volley 的使用遵循以下四步:
    1、获取请求队里RequestQueue
    RequestQueue mRequestQueue = Vollay.newRequestQueue(Context context) ;
    2、启动请求队列
    mRequestQueue.start();
    以上这两步通常也归为一步
    3、获取请求Request
    Request mRequest = new ObjectRequest(…) ;
    ObjectRequest需要根据自己请求返回的数据来定制,继承之抽象类Request,Vollay 已经为我们实现了 StringRequest、JsonArrayRequest、JsonObjectRequest、ImageRequest请求;
    4、把请求添加到请求队列中
    mRequestQueue.add(mRequest);
    说明:在一个项目中,请求队列不需要出现多个,一般整个项目中共用同一个mRequestQueue,因为请求队列启动的时候会做以下事情

        /**
         * Starts the dispatchers in this queue.
         */
        public void start() {
        //结束队列中所有的线程
            stop();  // Make sure any currently running dispatchers are stopped.
            // Create the cache dispatcher and start it.
            //初始化缓存处理线程
            mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
            //启动缓存线程
            mCacheDispatcher.start();
    
            // Create network dispatchers (and corresponding threads) up to the pool size.
            //启动网络请求处理线程,默认为5个,可以自己设定 size
            for (int i = 0; i < mDispatchers.length; i++) {
                NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                        mCache, mDelivery);
                //保存网络请求线程
                mDispatchers[i] = networkDispatcher;
                //启动网络请求处理线程
                networkDispatcher.start();
            }
        }

    启动一个缓存mCacheDispatcher线程,用来读取缓存数据,启动若干个网络请求mDispatchers线程,用来实现网络通信。
    mCacheDispatcher线程的 run 方法

        @Override
        public void run() {
            if (DEBUG) VolleyLog.v("start new dispatcher");
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    
            // Make a blocking call to initialize the cache.
            //初始化缓存
            mCache.initialize();
            //循环获取缓存请求
            while (true) {
                try {
                    // Get a request from the cache triage queue, blocking until
                    // at least one is available.
                    //从缓存队列中获取缓存请求,如果没有缓存请求,这个方法会阻塞在这里
                    final Request request = mCacheQueue.take();
                    //打印 log 信息
                    request.addMarker("cache-queue-take");
    
                    // If the request has been canceled, don't bother dispatching it.
                    //如果请求终止了,结束本次循环
                    if (request.isCanceled()) {
                        request.finish("cache-discard-canceled");
                        continue;
                    }
    
                    // Attempt to retrieve this item from cache.
                   //获取缓存数据,如果没有,把请求加入到网络请求的队列中
                    Cache.Entry entry = mCache.get(request.getCacheKey());
                    if (entry == null) {
                        request.addMarker("cache-miss");
                        Log.i("CacheDispatcher", "没有缓存数据:" + request.getUrl());
                        mNetworkQueue.put(request);
                        continue;
                    }
    
                    // If it is completely expired, just send it to the network.
                    //判断缓存是否已经过期,如果过期,把请求加入到网络请求的队列中,直接请求网络获取数据
                    if (entry.isExpired()) {
                        request.addMarker("cache-hit-expired");
                        request.setCacheEntry(entry);
                        Log.i("CacheDispatcher", "缓存数据过期:" + request.getUrl());
                        mNetworkQueue.put(request);
                        continue;
                    }
    
                    // We have a cache hit; parse its data for delivery back to the request.
                    // 已经获取到了有效的缓存数据,回调给 request 的parseNetworkResponse,需要自己根据需求来解析数据
                    request.addMarker("cache-hit");
                    Response<?> response = request.parseNetworkResponse(
                            new NetworkResponse(entry.data, entry.responseHeaders));
                    request.addMarker("cache-hit-parsed");
                    //判断缓存是否需要刷新
                    if (!entry.refreshNeeded()) {
                        // Completely unexpired cache hit. Just deliver the response.
                        Log.i("CacheDispatcher", "获取缓存数据:" + request.getUrl());
                        mDelivery.postResponse(request, response);
                    } else {
                        // Soft-expired cache hit. We can deliver the cached response,
                        // but we need to also send the request to the network for
                        // refreshing.
                        request.addMarker("cache-hit-refresh-needed");
                        request.setCacheEntry(entry);
    
                        // Mark the response as intermediate.
                        response.intermediate = true;
    
                        // Post the intermediate response back to the user and have
                        // the delivery then forward the request along to the network.
                        mDelivery.postResponse(request, response, new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    mNetworkQueue.put(request);
                                } catch (InterruptedException e) {
                                    // Not much we can do about this.
                                }
                            }
                        });
                    }
    
                } catch (InterruptedException e) {
                    // We may have been interrupted because it was time to quit.
                    if (mQuit) {
                        return;
                    }
                    continue;
                }
            }
        }

    mDispatchers线程的 run 方法

        @Override
        public void run() {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            Request request;
            while (true) {
                try {
                    // Take a request from the queue.
                    //获取网络请求,当队列中为空的时候,阻塞
                    request = mQueue.take();
                } catch (InterruptedException e) {
                    // We may have been interrupted because it was time to quit.
                    if (mQuit) {
                        return;
                    }
                    continue;
                }
    
                try {
                    request.addMarker("network-queue-take");
    
                    // If the request was cancelled already, do not perform the
                    // network request.
                    if (request.isCanceled()) {
                        request.finish("network-discard-cancelled");
                        continue;
                    }
    
                    // Tag the request (if API >= 14)
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                        TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
                    }
    
                    // Perform the network request.
                    //网络请求的基本操作(核心操作),从网络中获取数据
                    NetworkResponse networkResponse = mNetwork.performRequest(request);
                    request.addMarker("network-http-complete");
    
                    // If the server returned 304 AND we delivered a response already,
                    // we're done -- don't deliver a second identical response.
                    if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                        request.finish("not-modified");
                        continue;
                    }
    
                    // Parse the response here on the worker thread.
                    Response<?> response = request.parseNetworkResponse(networkResponse);
                    request.addMarker("network-parse-complete");
    
                    // Write to cache if applicable.
                    // TODO: Only update cache metadata instead of entire record for 304s.
                    //判断是否需要缓存,如果需要则缓存。
                    if (request.shouldCache() && response.cacheEntry != null) {
                        mCache.put(request.getCacheKey(), response.cacheEntry);
                        request.addMarker("network-cache-written");
                    }
    
                    // Post the response back.
                    request.markDelivered();
                    mDelivery.postResponse(request, response);
                } catch (VolleyError volleyError) {
                    parseAndDeliverNetworkError(request, volleyError);
                } catch (Exception e) {
                    VolleyLog.e(e, "Unhandled exception %s", e.toString());
                    mDelivery.postError(request, new VolleyError(e));
                }
            }
        }

    这两个线程处理类型基本相同,都是采用循环的方法,在队列中获取请求,有请求则执行相应的请求,没有则阻塞在下面两行代码中

    //阻塞线程的执行
    //缓存线程阻塞的地方
    final Request request = mCacheQueue.take();
    //网络请求阻塞的地方
    request = mQueue.take();

    所以我们一般只需要根据不同的接口,实例化不同的请求 Request,往队列中添加 即可,它首先判断请求是否需要缓存,如果不需要,直接添加到网络请求的队列中,结束下面的操作,如果需要缓存,则把请求添加到缓存队列中,具体看代码。

        public Request add(Request request) {
            // Tag the request as belonging to this queue and add it to the set of current requests.
            request.setRequestQueue(this);
            synchronized (mCurrentRequests) {
                mCurrentRequests.add(request);
            }
    
            // Process requests in the order they are added.
            request.setSequence(getSequenceNumber());
            request.addMarker("add-to-queue");
    
            // If the request is uncacheable, skip the cache queue and go straight to the network.
            //判断请求是否需要缓存,如果不需要,直接添加到网络请求的队列中,结束下面的操作,如果需要缓存,则把请求添加到缓存队列中
            if (!request.shouldCache()) {
                mNetworkQueue.add(request);
                return request;
            }
    
            // Insert request into stage if there's already a request with the same cache key in flight.
            synchronized (mWaitingRequests) {
                String cacheKey = request.getCacheKey();
                if (mWaitingRequests.containsKey(cacheKey)) {
                    // There is already a request in flight. Queue up.
                    Queue<Request> stagedRequests = mWaitingRequests.get(cacheKey);
                    if (stagedRequests == null) {
                        stagedRequests = new LinkedList<Request>();
                    }
    
                    stagedRequests.add(request);
                    mWaitingRequests.put(cacheKey, stagedRequests);
                    if (VolleyLog.DEBUG) {
                        VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
                    }
                } else {
                    // Insert 'null' queue for this cacheKey, indicating there is now a request in
                    // flight.
                    mWaitingRequests.put(cacheKey, null);
                    mCacheQueue.add(request);
                }
                return request;
            }
        }

    所以如果需要缓存的话,一开始会从mCacheQueue.take()会得到执行,当不符合要求的时候,请求会添加到真正的网络请求队列中,以下是不符合要求的代码

                    //没有缓存
                    if (entry == null) {
                        request.addMarker("cache-miss");
                        Log.i("CacheDispatcher", "没有缓存数据:" + request.getUrl());
                        mNetworkQueue.put(request);
                        continue;
                    }
    
                    // If it is completely expired, just send it to the network.
                    //缓存已过期
                    if (entry.isExpired()) {
                        request.addMarker("cache-hit-expired");
                        request.setCacheEntry(entry);
                        Log.i("CacheDispatcher", "缓存数据过期:" + request.getUrl());
                        mNetworkQueue.put(request);
                        continue;
                    }

    如果缓存不符合要求,网络线程终止阻塞得到执行;
    我们一般习惯用法是在 Application 中全局初始化RequestQueue mRequestQueue,并启动它,让整个应用都能获取到。具体运用将会在下面用到。

    三、Volley 实战 GET 请求和 POST 请求

    先来来看下测试的接口http://www.minongbang.com/test.php?test=minongbang
    返回数据:
    这里写图片描述
    这里 get 请求和 post 请求都是用同一个接口来测试,所以先把返回的基本数据类型定义出来

    /**
     * Created by gyzhong on 15/3/3.
     */
    public class TestBean {
        @Expose
        private int id ;
        @Expose
        private String name ;
        @Expose
        private int download ;
        @Expose
        private int version ;
    
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getDownload() {
            return download;
        }
    
        public void setDownload(int download) {
            this.download = download;
        }
    
        public int getVersion() {
            return version;
        }
    
        public void setVersion(int version) {
            this.version = version;
        }
    }

    1、GET 请求
    第一步:在 Application 中初始化RequestQueue,

        //初始化请求队列
        private void initRequestQueue(){
            //初始化 volley
            VolleyUtil.initialize(mContext);
        }
    /**
     * Created by gyzhong on 15/3/1.
     */
    public class VolleyUtil {
    
        private static RequestQueue mRequestQueue ;
    
        public static void initialize(Context context){
            if (mRequestQueue == null){
                synchronized (VolleyUtil.class){
                    if (mRequestQueue == null){
                        mRequestQueue = Volley.newRequestQueue(context) ;
                    }
                }
            }
            mRequestQueue.start();
        }
    
        public static RequestQueue getRequestQueue(){
            if (mRequestQueue == null)
                throw new RuntimeException("请先初始化mRequestQueue") ;
            return mRequestQueue ;
        }
    }

    第二步:定制 Request
    先来分析接口所返回的数据,我们看到是一条 json 数据,虽然 Volley 中已经为我们定制好了JsonObjectRequest请求,但我们知道,在数据具体显示的时候,是需要把 json 数据转化为对象进行处理,所以这里我们可以定制通用的对象请求。如何定制呢?
    先看StringRequest的实现代码

    //继承Request<String>,String 为请求解析之后的数据
    public class StringRequest extends Request<String> {
        //正确数据回调接口
        private final Listener<String> mListener;
        public StringRequest(int method, String url, Listener<String> listener,
                ErrorListener errorListener) {
            super(method, url, errorListener);
            mListener = listener;
        }
        public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
            this(Method.GET, url, listener, errorListener);
        }
    
        //回调解析之后的数据
        @Override
        protected void deliverResponse(String response) {
            mListener.onResponse(response);
        }
    
        //解析数据,把网络请求,或者中缓存中获取的数据,解析成 String
        @Override
        protected Response<String> parseNetworkResponse(NetworkResponse response) {
            String parsed;
            try {
                parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            } catch (UnsupportedEncodingException e) {
                parsed = new String(response.data);
            }
            return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
        }
    }

    通过上面代码可知,StringRequest继承了 Request 并实现了两个抽象方法parseNetworkResponse()和 deliverResponse(),这两个方法很好理解,parseNetworkResponse()把获取到的数据解析成我们所定义的数据类型;deliverResponse()把所解析的数据通过回调接口回调给展示处。
    为了简化回调接口,这里把错误回调Response.ErrorListener 和正确的数据回调Response.Listener合并成一个ResponseListener

    /**
     * Created by gyzhong on 15/3/1.
     * 简化回调接口
     */
    public interface ResponseListener<T> extends Response.ErrorListener,Response.Listener<T> {
    }

    根据 StringRequest,如法炮制

    /**
     * Created by gyzhong on 15/3/1.
     */
    public class GetObjectRequest<T> extends Request<T> {
    
        /**
         * 正确数据的时候回掉用
         */
        private ResponseListener mListener ;
        /*用来解析 json 用的*/
        private Gson mGson ;
        /*在用 gson 解析 json 数据的时候,需要用到这个参数*/
        private Type mClazz ;
    
        public GetObjectRequest(String url,Type type, ResponseListener listener) {
            super(Method.GET, url, listener);
            this.mListener = listener ;
            mGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() ;
            mClazz = type ;
        }
    
        /**
         * 这里开始解析数据
         * @param response Response from the network
         * @return
         */
        @Override
        protected Response<T> parseNetworkResponse(NetworkResponse response) {
            try {
                T result ;
                String jsonString =
                        new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                result = mGson.fromJson(jsonString,mClazz) ;
                return Response.success(result,
                        HttpHeaderParser.parseCacheHeaders(response));
            } catch (UnsupportedEncodingException e) {
                return Response.error(new ParseError(e));
            }
        }
    
        /**
         * 回调正确的数据
         * @param response The parsed response returned by
         */
        @Override
        protected void deliverResponse(T response) {
            mListener.onResponse(response);
        }
    }

    以上代码中在实例化 Gson 的时候用到的是mGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation(),主要是用于过滤字段用的.如果有疑问的同学可以参考我前面写的一篇文章Gson 过滤字段的几种方法
    第三步:获取 request

    Request request = new GetObjectRequest(url,new TypeToken<TestBean>(){}.getType(),listener) ;

    1、url -> http://www.minongbang.com/test.php?test=minongbang
    2、new TypeToken(){}.getType() ->为 gson 解析 json 数据所要的 type
    3、listener -> 为我们定义的ResponseListener回调接口
    第四步:添加请求到队列中

    VolleyUtil.getRequestQueue().add(request) ;

    所以,此接口的代码即为

        /**
         * Minong 测试数据get网络请求接口
         * @param value 要搜索的关键字
         * @param listener 回调接口,包含错误回调和正确的数据回调
         */
        public static void getObjectMiNongApi(String value,ResponseListener listener){
            String url ;
            try {
                url = Constant.MinongHost +"?test="+ URLEncoder.encode(value, "utf-8") ;
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                url = Constant.MinongHost +"?test="+ URLEncoder.encode(value) ;
            }
            Request request = new GetObjectRequest(url,new TypeToken<TestBean>(){}.getType(),listener) ;
            VolleyUtil.getRequestQueue().add(request) ;
        }

    第五步:代码测试

    public class GetRequestActivity extends ActionBarActivity {
    
        /*数据显示的View*/
        private TextView mIdTxt,mNameTxt,mDownloadTxt,mLogoTxt,mVersionTxt ;
        /*弹出等待对话框*/
        private ProgressDialog mDialog ;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_get);
            mIdTxt = (TextView) findViewById(R.id.id_id) ;
            mNameTxt = (TextView) findViewById(R.id.id_name) ;
            mDownloadTxt = (TextView) findViewById(R.id.id_download) ;
            mLogoTxt = (TextView) findViewById(R.id.id_logo) ;
            mVersionTxt = (TextView) findViewById(R.id.id_version) ;
            mDialog = new ProgressDialog(this) ;
            mDialog.setMessage("get请求中...");
            mDialog.show();
            /*请求网络获取数据*/
            MiNongApi.getObjectMiNongApi("minongbang",new ResponseListener<TestBean>() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    mDialog.dismiss();
                }
    
                @Override
                public void onResponse(TestBean response) {
                    mDialog.dismiss();
                    /*显示数据*/
                    mIdTxt.setText(response.getId()+"");
                    mNameTxt.setText(response.getName());
                    mDownloadTxt.setText(response.getDownload()+"");
                    mLogoTxt.setText(response.getLogo());
                    mVersionTxt.setText(response.getVersion()+"");
                }
            });
        }
    
    }

    测试效果图如下:
    这里写图片描述 这里写图片描述
    可以看到和我们在浏览器中请求的数据一模一样!

    2、POST请求
    因为在讲 get 请求的时候花了很大篇幅讲原理,所以在 post 请求的时候,需要注意的东西相对来说比较少, 不管是 get 请求还是 post 请求,实现步骤是不会变。 这里post 请求,我们也是用http://www.minongbang.com/test.php?test=minongbang这个 api 来测试!
    在前面我们已经讲到了,在同一个应用中共用同一个 RequestQueue,所以第一步可以省略,因为我们已经实现过了。这里直接到定制Request,我们在学习网络编程的时候就已经知道,用 GET方式请求,请求的数据是直接跟在 URL的后面用”?”去分开了,如果有多个数据则用”&”分开。而 POST则把数据直接封装在HTTP的包体中,两者各有优缺点,自己衡量着用。
    因为 api 接口还是同一个,所以返回的数据类型肯定是一样的,在解析数据的时候就可以和 GetObjectRequest 复用,所以 PostObjectRequest 的实现可以通过继承GetObjectRequest的方式,也可以直接拷贝一份出来,为了更好的区分,我这里就直接拷贝一份,然后再稍加修改。

    /**
     * Created by gyzhong on 15/3/1.
     */
    public class PostObjectRequest<T> extends Request<T> {
    
        /**
         * 正确数据的时候回掉用
         */
        private ResponseListener mListener ;
        /*用来解析 json 用的*/
        private Gson mGson ;
        /*在用 gson 解析 json 数据的时候,需要用到这个参数*/
        private Type mClazz ;
        /*请求 数据通过参数的形式传入*/
        private Map<String,String> mParams;
        //需要传入参数,并且请求方式不能再为 get,改为 post
        public PostObjectRequest(String url, Map<String,String> params,Type type, ResponseListener listener) {
            super(Method.POST, url, listener);
            this.mListener = listener ;
            mGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() ;
            mClazz = type ;
            setShouldCache(false);
            mParams = params ;
        }
    
        /**
         * 这里开始解析数据
         * @param response Response from the network
         * @return
         */
        @Override
        protected Response<T> parseNetworkResponse(NetworkResponse response) {
            try {
                T result ;
                String jsonString =
                        new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                Log.v("zgy", "====jsonString===" + jsonString);
                result = mGson.fromJson(jsonString,mClazz) ;
                return Response.success(result,
                        HttpHeaderParser.parseCacheHeaders(response));
            } catch (UnsupportedEncodingException e) {
                return Response.error(new ParseError(e));
            }
        }
    
        /**
         * 回调正确的数据
         * @param response The parsed response returned by
         */
        @Override
        protected void deliverResponse(T response) {
            mListener.onResponse(response);
        }
    
    //关键代码就在这里,在 Volley 的网络操作中,如果判断请求方式为 Post 则会通过此方法来获取 param,所以在这里返回我们需要的参数,
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            return mParams;
        }
    }

    再来看看 api 接口怎么实现,

        /*
        * *Minong 测试数据post网络请求接口
        * @param value 测试数据
        * @param listener 回调接口,包含错误回调和正确的数据回调
        */
        public static void postObjectMinongApi(String value,ResponseListener listener){
            Map<String,String> param = new HashMap<String,String>() ;
            param.put("test",value) ;
            Request request = new PostObjectRequest(Constant.MinongHost,param,new TypeToken<TestBean>(){}.getType(),listener);
            VolleyUtil.getRequestQueue().add(request) ;
        }

    跟 get 请求还是很相似的,只是在实例化 Request 的时候多传入了一个param参数,并且 url 不能再是包含请求数据的 url。
    接口 api测试代码

    public class PostRequestActivity extends ActionBarActivity {
    
        /*数据显示的View*/
        private TextView mIdTxt,mNameTxt,mDownloadTxt,mLogoTxt,mVersionTxt ;
        /*弹出等待对话框*/
        private ProgressDialog mDialog ;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_get);
            mIdTxt = (TextView) findViewById(R.id.id_id) ;
            mNameTxt = (TextView) findViewById(R.id.id_name) ;
            mDownloadTxt = (TextView) findViewById(R.id.id_download) ;
            mLogoTxt = (TextView) findViewById(R.id.id_logo) ;
            mVersionTxt = (TextView) findViewById(R.id.id_version) ;
            mDialog = new ProgressDialog(this) ;
            mDialog.setMessage("post请求中...");
            mDialog.show();
            /*请求网络获取数据*/
            MiNongApi.postObjectMinongApi("minongbang",new ResponseListener<TestBean>() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    mDialog.dismiss();
                }
    
                @Override
                public void onResponse(TestBean response) {
                    mDialog.dismiss();
                    /*显示数据*/
                    mIdTxt.setText(response.getId()+"");
                    mNameTxt.setText(response.getName());
                    mDownloadTxt.setText(response.getDownload()+"");
                    mLogoTxt.setText(response.getLogo());
                    mVersionTxt.setText(response.getVersion()+"");
                }
            });
        }
    }

    测试数据显示跟 get 请求完全相同;ok,以上就是 Volley GET请求和 POST请求的全部内容!接下来又到了总结的时候

    四、总结

    1、volley 适用于轻量高并发的网络请求,这里补充一个知识点,因为 Volley 请求网络的数据全部保存在内存中,所以 volley 不适合请求较大的数据,比如下载文件,下载大图片等。

    2、volley 的使用遵循四个步骤
    a、RequestQueue mRequestQueue = Vollay.newRequestQueue(Context context) ;
    b、mRequestQueue.start()
    c、Request mRequest = new ObjectRequst(…)
    d、mRequestQueue.add(mRequest)

    3、同一个程序中最好共用一个 RequestQueue。

    4、可以根据接口的放回数据类型定制任意的 Request,volley 已经默认为我们实现了 StringRequest、JsonArrayRequest、JsonObjectRequest、ImageRequest四个请求类型。

    最后如果觉得有用请继续关注我的 blog,我将会在下篇 blog 中讲解,Volley解析(二)之表单提交篇

    展开全文
  • 1. Get方法长度限制 Http Get方法提交的数据大小长度并没有限制,HTTP协议规范没有对URL长度进行限制。这个限制是特定的浏览器及服务器对它的限制。下面就是对各种浏览器和服务器的最大处理能力做一些说明. 浏览器...
  • 获取body的长度和宽度

    千次阅读 2012-08-13 01:13:54
    Window size and scrolling Finding the size of the browser window ...Clue browser can only work out window width.Tkhtml Hv3 has the body/documentElement clientHeight/Width values reversed - versions b
  • 1. Get方法长度限制 Http Get方法提交的数据大小长度并没有限制,HTTP协议规范没有对URL长度进行限制。这个限制是特定的浏览器及服务器对它的限制。 如:IE对URL长度的限制是2083字节(2K+35)。 下面就是对各种...
  • Full Body Biped IK

    千次阅读 2018-12-08 10:46:50
    Full Body Biped IK 解析: Final IK includes an extremely flexible and powerful high speed lightweight FBIK solver for biped characters. Final IK 是一个基于双足行走人物的非常强大并灵活,高效率的FBIK ...
  • A barber today does not cut a boy’s hair in the same way as he used to, and girls do not make up in the same way as their mothers and grandmothers did. The advertisers show us the latest fashionable...
  • resp, err := http.Get(...) if err != nil { .. } defer resp.Body.Close() 为啥必须 resp.Body.Close() 呢? 回答这个问题其实需要回答两个问题: resp.Body.Close() 做了啥? 为啥这么做? 1 resp.Body.Clo...
  • go get无法安装golang.org/x/的解决方法

    千次阅读 2019-11-13 15:35:41
    因为golang.org/x/服务器在境外,所以正常情况下go get是不能安装的,需要科学上网才可! 下面是博主提供的文件,可以先搜索你需要的文件是否存在,存在你再下载! github地址:...
  • 关于 HTTP GET/POST 请求参数长度最大值的一个理解误区 2014-09-24 14:02:11 分类: Java ...1. Get方法长度限制 Http Get方法提交的数据大小长度并没有限制,HTTP协议规范没有对URL长度进行限制。这个
  • Get方法长度限制 Http Get方法提交的数据大小长度并没有限制,HTTP协议规范没有对URL长度进行限制。这个限制是特定的浏览器及服务器对它的限制。 如:IE对URL长度的限制是2083字节(2K+35)。 下面就是对各种...
  • So when we think of nonverbals, we think of how we judge others and how they judge us and what the outcomes are.We tend to forget, though,the other audience that's influenced by nonverbals and that's...
  • python urllib/urllib2 get/post使用详解

    万次阅读 2015-08-12 14:51:54
    1、urllib2可以接受一个Request类的实例来设置...2、urllib提供urlencode方法用来GET查询字符串的产生,而urllib2没有。这是为何urllib常和urllib2一起使用的原因。 urllib get数据的方法 (params是关键字) #!/usr/
  • Best Practices for Speeding Up Your Web Site

    千次阅读 2010-10-21 10:58:00
    Best Practices for Speeding Up Your Web Site
  • 本文转载于: http://www.cracked.com/article_18461_5-creepy-ways-video-games-are-trying-to-get-you-addicted.html 译文请看: http://bbs.a9vg.com/thread-1984642-1-2.html ---------------------------...
  • 在互网企业当中网关的重要性我就不再赘述了,相信大家都比较清楚。我们公司网关采用的是 Spring Cloud Gateway。并且是通过自定义 ...下面就是读取 requestBody 里面的主动参数,然后解析请求对象里面的 biz
  • Web 站点提速的最佳实践(Best Practices for Speeding Up Your Web Site)
  • ExpressJs--入门(动态传参/get传参)

    千次阅读 2019-02-15 16:56:36
    ②原型是: res.send([body|status], [body]) 即既可以直接发送内容,也可以第一个参数状态,第二个参数内容。 如果直接发送内容的话,状态会被自动补全; ③发送的内容: 示例: res.send(newBuffer('whoop')); ...
  • 死磕Android_OkHttp3 原理探究

    千次阅读 2019-07-22 22:42:52
    /** A mutable map of tags, or an immutable empty map if we don't have any. */ Map < Class < ? > , Object > tags = Collections . emptyMap ( ) ; public Builder ( ) { this . method = ...
  • Android 8.0学习(28)--- 解决OkHttp问题

    千次阅读 2018-04-27 08:43:51
    Android 8.0 解决OkHttp问题:A... Did you forget to close a response body?2535Android中,我们访问网络时,最简单的方式类似与:HttpURLConnection connection = null; try { //xxxxx为具体的网络地址 URL url...
  • 以下是斯坦福教授李飞飞...https://www.ted.com/talks/fei_fei_li_how_we_re_teaching_computers_to_understand_pictures?language=zh-cnEnglish Transcript:0:13 Let me show you something.0:17 (Video) Girl:
  • http请求之GET、POST对比分析

    千次阅读 2014-05-09 09:37:46
    刚看到群里又有同学在说 HTTP 协议下的 Get 请求参数长度是有大小限制的,最大不能超过  XX,而 Post 是无限制的,看到这里,我想他们定是看多了一些以讹传讹的博客或者书籍, 导致一种理解上的误区: 1...
  • 转自:http://kubecloud.io/getting-up-and-running-with-kubernetes-io/ The following post is based on this link written by Arjen Wassink. Arjen demonstrated the Kubernetes.io cluster at ...
  • HTTP GET/POST 请求参数长度

    千次阅读 2015-03-16 13:57:44
    http get方式参数的长度 http: http://www.cnblogs.com/Arlen/articles/1748026.html posted on 2010-05-31 11:15 Arlen 这个问题一直以来似乎是被N多人误解,其实Http Get方法提交的数据大小长度并没有限制...
  • photo credit: Gian Franco Costa Albertini Over the past year and a half I have developed the bad habit of staying up late.... I rarely get to bed before 2am as I am up working on my bus
  • We figured when we couldn't find you, you'd gone home to make up with Rachel. Which is probably what you shoulda done. Huh? Ross: You think?! God, I, ah, I'm in hell. I mean what, what am I gonna do?...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,970
精华内容 10,788
关键字:

bodygetupwe

友情链接: 8.rar