使用libcurl第三方库实现Android异步任务

本文承接自前篇博客将Cocos2d-x的libcurl单独打包到Android 

在此基础上,又进行了进一步的使用:

1)增加libcurl异步方法

2)实现Android异步任务

下面直接上代码:

1】jni之first.c:first.h无变化,first.c添加如下代码,切记C变量必须把声明方法函数的开始

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include "first.h"

int  first(int  x, int  y)
{
    return x + y;
}

#define MULTI_CURL_NUM 3
char* URL = "http://www.baidu.com";
char* PROXY = "";
unsigned int TIMEOUT = 10000;
char* urlA[3] = {"http://www.baidu.com","http://www.cocoachina.com/bbs/read.php?tid=228963","http://www.cnblogs.com/zhaoyl/p/4001151.html"};

//异步方法获取返回数据
size_t curl_writer(void* buffer,size_t size,size_t count,void* stream)
{
//    std::string* pStream = static_cast<std::string*>(stream);
//    (*pStream).append((char*)buffer,size * count);
//    log("pStream=%s",pStream);
    return size*count;
}
//增加URL请求,异步实质上是多个同步请求的组合
CURL* curl_easy_handler(const char* sUrl,const char* sProxy,char* sRsp,unsigned int uiTimeout)
{
    CURL* curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL,sUrl);
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL,1);

    if(uiTimeout > 0)
    {
        curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS,uiTimeout);
    }
    if(sProxy[0]!='\0')
    {
        curl_easy_setopt(curl, CURLOPT_PROXY,sProxy);
    }
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,curl_writer);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA,&sRsp);
//    log("curl_write = %lu",sizeof(sRsp));
    return curl;
}
//select方法,选择当前可读写的文件
int curl_multi_select(CURLM* curl_m)
{
    int ret = 0;
    int idx1 = 0;
    struct timeval timeout_tv;
    fd_set fd_read;
    fd_set fd_write;
    fd_set fd_except;
    int max_fd = -1;
    int ret_code;

    FD_ZERO(&fd_read);
    FD_ZERO(&fd_write);
    FD_ZERO(&fd_except);

    timeout_tv.tv_sec = 60;
    timeout_tv.tv_usec = 0;

    curl_multi_fdset(curl_m, &fd_read, &fd_write, &fd_except, &max_fd);
//    log("max_fd = %d",max_fd);
    if(max_fd == -1)
    {
        return -1;
    }

//    ret_code = ::select(max_fd+1, &fd_read, &fd_write, &fd_except, &timeout_tv);
    ret_code = select(max_fd+1, &fd_read, &fd_write, &fd_except, &timeout_tv);
//    log("ret_code = %d",ret_code);
    switch (ret_code) {
        case -1:
            ret = -1;
            break;
        case 0:
        default:
            ret = 0;
            break;
    }
    return ret;
}
//异步方法入口
int curl_multi_demo(int num,CURLcode* result)
{
	int idx;
	static int count = 0;
    CURLM* curl_m = curl_multi_init();
    char* RspArray[num];
    int running_handles = 0;

    int msgs_left;
    CURLMsg* msg;

//    int s[num];
    CURL*       CurlArray[num];

    for(idx = 0; idx < num; ++idx)
    {
        CurlArray[idx] = NULL;
        CurlArray[idx] = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);
        if(CurlArray[idx] == NULL)

        {
            return -1;
        }
        curl_multi_add_handle(curl_m, CurlArray[idx]);
    }

//    log("running_handles out up = %d",running_handles);
    while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles))
    {
//        log("running_handles = %d",running_handles);
    }
//    log("running_handles out = %d",running_handles);
    while(running_handles)
    {
        if(-1 == curl_multi_select(curl_m))
        {
//            log( "select error" );
            break;
        }else{
            while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles))
            {
//                log("select:%d ",running_handles);
            }
        }
//        log("select: %d",running_handles);
    }


    while ((msg = curl_multi_info_read(curl_m, &msgs_left)))
    {
        if(CURLMSG_DONE == msg->msg);
        {
            int idx;
            for(idx = 0; idx < num; ++idx)
            {
                if(msg->easy_handle == CurlArray[idx]) break;
            }

            if(idx == num)
            {
//                log("curl not found");
            }else{
//                log("curl [%d] completed with status: %d",idx,msg->data.result);
//                log("rsp: %s",RspArray[idx]);
            	result[count++] = msg->data.result;//将求求结果状态传入result数组,该数组是指针
            }
        }
    }

    for(idx = 0; idx < num; ++idx)
    {
        curl_multi_remove_handle(curl_m, CurlArray[idx]);
    }

    for(idx = 0; idx < num; ++idx)
    {
        curl_easy_cleanup(CurlArray[idx]);
    }

    curl_multi_cleanup(curl_m);

    return 0;
}
//同步方法入口
int curl_easy_demo(int num)
{
	int idx = 0;
    char* RspArray[num];
    for(idx = 0; idx < num; ++idx)
    {
        CURL* curl = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);
        CURLcode code = curl_easy_perform(curl);
//        log("curl [%d] completed with status:%d",idx,code);
        curl_easy_cleanup(curl);
    }
    return 0;
}

2】jni之second.c

#include "first.h"
#include <jni.h>
#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>

//extern "C"

jint
Java_com_example_libdemo_MainActivity_add( JNIEnv*  env,
                                      jobject  this,
                                      jint     x,
                                      jint     y)
{
/*	//libcurl同步方法案例
	CURL* curl;
	CURLcode res;
	curl = curl_easy_init();
	if(NULL == curl)
	{
		return first(1,999);
	}
    curl_easy_setopt(curl, CURLOPT_URL,"http://www.baidu.com");
    curl_easy_setopt(curl, CURLOPT_READFUNCTION,NULL);
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL,1);
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT,20);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT,20);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);

*/
	//libcurl异步方法案例
	CURLcode result[3];
	int sum;
    gettimeofday(&begin_tv, NULL);

    curl_multi_demo(3,result);

    gettimeofday(&end_tv, NULL);

    long eclapsed = (end_tv.tv_sec - begin_tv.tv_sec)*1000 + (end_tv.tv_usec - begin_tv.tv_usec) / 1000;
//    log("eclapsed time: %ld ms",eclapsed);
    sum = (int)result[0] + (int)result[1];
    return first(sum,(int)result[2]);
}
3】src之MainActivity.java

package com.example.libdemo;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {

	private Button button;
	private TextView tv;
	private TextView textView;
	private ProgressBar progressBar;
	private static final String TAG = "ASYNC_TASK";
	private int x  = 123;
    private int y  = 456;
    private MyTask mTask;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        System.loadLibrary("twolib-second");
        tv = (TextView)findViewById(R.id.textView2);
        button = (Button) this.findViewById(R.id.button1);
        textView = (TextView) findViewById(R.id.textView3);
        this.button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				 mTask = new MyTask();
				 mTask.execute("test");
			}
		});
    }
    public native int add(int x,int y);
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    //异步任务
    private class MyTask extends AsyncTask<String, Integer, String> { 
    	@Override
    	protected void onPreExecute() {
    		// TODO Auto-generated method stub
//    		super.onPreExecute();
    		Log.i(TAG, "onPreExecute() called");
    		textView.setText("Loading...");
    		
    	}
    	//处理耗时任务
    	@Override
    	protected String doInBackground(String... arg0) {
    		// TODO Auto-generated method stub
    	
            try {  
            	int  z = add(x, y);
                tv = (TextView) findViewById(R.id.textView2);
                tv.setText( "The sum dskdshd of " + x + " and " + y + " is " + z );
                return new String("test");
            } catch (Exception e) {  
                Log.e(TAG, e.getMessage());  
            }  
            return null;  
    	}
    	
    	@Override
    	protected void onProgressUpdate(Integer... values) {
    		// TODO Auto-generated method stub
//    		super.onProgressUpdate(values);
    		progressBar.setProgress(values[0]);
    		textView.setText("loading..." + "%");
    	}
    	
    	@Override
    	protected void onPostExecute(String result) {
    		// TODO Auto-generated method stub
//    		super.onPostExecute(result);
    		textView.setTag(result);
    	}
    }
    
}

注意:

1、关于代码中用到的UI,读者自行拖到layout中,此处不在详细介绍

2、Android中目前比较常用的为handle机制,由于作者Android水平有限,选择了最简单的异步任务实现。有兴趣的读者,自行实现其他方法

3、运行截图:点击最左侧按钮后,返回下面的结果,如果是0表面程序中的3个URL请求成功,如果返回其他则失败,curl返回错误码见上面博客。


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。