NAPI 是 Linux 上采用的一种提高网络处理效率的技术,它的核心概念就是不采用中断的方式读取数据,而代之以首先采用中断唤醒数据接收的服务程序,然后 通过poll的方法来轮询数据。采用NAPI技术可以大大改善短长度数据包接收的效率,减少中断触发的时间。
可以这样理解,在NAPI机制没有出现时,由于网络设备接收数据是采用中断方式的,假设每次数据包很小,小到只有几个字节。而刚好在1秒内有5000个这样的数据包。那么系统就是在1秒内产生5000个中断,这无疑给会占据CPU的大部分资源。NAPI的出现就是要解决这样的问题。
概念的东西就不多提了。下面开始源码之旅啦!
首先在分配CAN设备时,采用netif_napi_add函数注册轮询函数d_can_poll()。
struct net_device *alloc_d_can_dev(int num_objs)
{
struct net_device *dev;
struct d_can_priv *priv;
dev = alloc_candev(sizeof(struct d_can_priv), num_objs/2);
if (!dev)
return NULL;
priv = netdev_priv(dev);
netif_napi_add(dev, &priv->napi, d_can_poll, num_objs/2);
priv->dev = dev;
priv->can.bittiming_const = &d_can_bittiming_const;
priv->can.do_set_mode = d_can_set_mode;
priv->can.do_get_berr_counter = d_can_get_berr_counter;
priv->can.ctrlmode_supported = (CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_3_SAMPLES);
return dev;
}
netif_napi_add()函数原型如下:
void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
int (*poll)(struct napi_struct *, int), int weight)
{
INIT_LIST_HEAD(&napi->poll_list);
napi->gro_count = 0;
napi->gro_list = NULL;
napi->skb = NULL;
napi->poll = poll;
napi->weight = weight;
list_add(&napi->dev_list, &dev->napi_list);
napi->dev = dev;
#ifdef CONFIG_NETPOLL
spin_lock_init(&napi->poll_lock);
napi->poll_owner = -1;
#endif
set_bit(NAPI_STATE_SCHED, &napi->state);
}
轮询函数d_can_poll()如下:
static int d_can_poll(struct napi_struct *napi, int quota)
{
int lec_type = 0;
int work_done = 0;
struct net_device *dev = napi->dev;
struct d_can_priv *priv = netdev_priv(dev);
if (!priv->irqstatus)
goto end;
/* status events have the highest priority */
if (priv->irqstatus == STATUS_INTERRUPT) {
priv->current_status = d_can_read(priv, D_CAN_ES);
/* handle Tx/Rx events */
if (priv->current_status & D_CAN_ES_TXOK)
d_can_write(priv, D_CAN_ES,
priv->current_status & ~D_CAN_ES_TXOK);
if (priv->current_status & D_CAN_ES_RXOK)
d_can_write(priv, D_CAN_ES,
priv->current_status & ~D_CAN_ES_RXOK);
/* handle state changes */
if ((priv->current_status & D_CAN_ES_EWARN) &&
(!(priv->last_status & D_CAN_ES_EWARN))) {
netdev_dbg(dev, "entered error warning state\n");
work_done += d_can_handle_state_change(dev,
D_CAN_ERROR_WARNING);
}
if ((priv->current_status & D_CAN_ES_EPASS) &&
(!(priv->last_status & D_CAN_ES_EPASS))) {
netdev_dbg(dev, "entered error passive state\n");
work_done += d_can_handle_state_change(dev,
D_CAN_ERROR_PASSIVE);
}
if ((priv->current_status & D_CAN_ES_BOFF) &&
(!(priv->last_status & D_CAN_ES_BOFF))) {
netdev_dbg(dev, "entered bus off state\n");
work_done += d_can_handle_state_change(dev,
D_CAN_BUS_OFF);
}
/* handle bus recovery events */
if ((!(priv->current_status & D_CAN_ES_BOFF)) &&
(priv->last_status & D_CAN_ES_BOFF)) {
netdev_dbg(dev, "left bus off state\n");
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
if ((!(priv->current_status & D_CAN_ES_EPASS)) &&
(priv->last_status & D_CAN_ES_EPASS)) {
netdev_dbg(dev, "left error passive state\n");
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
priv->last_status = priv->current_status;
/* handle lec errors on the bus */
lec_type = d_can_has_handle_berr(priv);
if (lec_type)
work_done += d_can_handle_bus_err(dev, lec_type);
} else if ((priv->irqstatus >= D_CAN_MSG_OBJ_RX_FIRST) &&
(priv->irqstatus <= D_CAN_MSG_OBJ_RX_LAST)) {
/* handle events corresponding to receive message objects */
work_done += d_can_do_rx_poll(dev, (quota - work_done));
} else if ((priv->irqstatus >= D_CAN_MSG_OBJ_TX_FIRST) &&
(priv->irqstatus <= D_CAN_MSG_OBJ_TX_LAST)) {
/* handle events corresponding to transmit message objects */
d_can_do_tx(dev);
}
end:
if (work_done < quota) {
napi_complete(napi);
/* enable all IRQs */
d_can_interrupts(priv, ENABLE_ALL_INTERRUPTS);
}
return work_done;
}
在中断处理函数中,先禁止接收中断,且告诉网络子系统,将以轮询方式快速收包,其中禁止接收中断完全由硬件功能决定,而告诉内核将以轮询方式处理包则是使用函数napi_schedule()。
static irqreturn_t d_can_isr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct d_can_priv *priv = netdev_priv(dev);
priv->irqstatus = d_can_read(priv, D_CAN_INT);
if (!priv->irqstatus)
return IRQ_NONE;
/* disable all interrupts and schedule the NAPI */
d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS);
napi_schedule(&priv->napi);
return IRQ_HANDLED;
}
其中的napi_schedule_prep()函数是为了判定现在是否已经进入了轮询模式。
static inline void napi_schedule(struct napi_struct *n)
{
if (napi_schedule_prep(n))
__napi_schedule(n);
}
轮询功能的关闭则需要使用:
if (work_done < quota) {
napi_complete(napi);
/* enable all IRQs */
d_can_interrupts(priv, ENABLE_ALL_INTERRUPTS);
}
因为可能存在多个napi_struct的实例,要求每个实例能够独立的使能或者禁止。因此,需要驱动开发人员保证在网卡接口关闭时,禁止所有的napi_struct的实例。在d_can_open()函数中使用napi_enable(),在d_can_close()函数中使用napi_disable()。
napi_enable(&priv->napi);
napi_disable(&priv->napi);
网上找到的,备份一份
package com.example.bank; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Hashtable; import java.util.regex.Matcher; import java.util.regex.Pattern; public class CheckPCard { /*********************************** 身份证验证开始 ****************************************/ /** * 身份证号码验证 1、号码的结构 公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码, * 八位数字出生日期码,三位数字顺序码和一位数字校验码。 2、地址码(前六位数) * 表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260的规定执行。 3、出生日期码(第七位至十四位) * 表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符。 4、顺序码(第十五位至十七位) * 表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号, 顺序码的奇数分配给男性,偶数分配给女性。 5、校验码(第十八位数) * (1)十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和 * Ai:表示第i位置上的身份证号码数字值 Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 * 2 (2)计算模 Y = mod(S, 11) (3)通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 * X 9 8 7 6 5 4 3 2 */ /** * 功能:身份证的有效验证 * * @param IDStr * 身份证号 * @return 有效:返回"" 无效:返回String信息 * @throws ParseException */ @SuppressWarnings("unchecked") public static String IDCardValidate(String IDStr) throws ParseException { String errorInfo = "";// 记录错误信息 String[] ValCodeArr = { "1", "0", "x", "9", "8", "7", "6", "5", "4", "3", "2" }; String[] Wi = { "7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2" }; String Ai = ""; // ================ 号码的长度 15位或18位 ================ if (IDStr.length() != 15 && IDStr.length() != 18) { errorInfo = "身份证号码长度应该为15位或18位。"; return errorInfo; } // =======================(end)======================== // ================ 数字 除最后以为都为数字 ================ if (IDStr.length() == 18) { Ai = IDStr.substring(0, 17); } else if (IDStr.length() == 15) { Ai = IDStr.substring(0, 6) + "19" + IDStr.substring(6, 15); } if (isNumeric(Ai) == false) { errorInfo = "身份证15位号码都应为数字 ; 18位号码除最后一位外,都应为数字。"; return errorInfo; } // =======================(end)======================== // ================ 出生年月是否有效 ================ String strYear = Ai.substring(6, 10);// 年份 String strMonth = Ai.substring(10, 12);// 月份 String strDay = Ai.substring(12, 14);// 月份 if (isDate(strYear + "-" + strMonth + "-" + strDay) == false) { errorInfo = "身份证生日无效。"; return errorInfo; } GregorianCalendar gc = new GregorianCalendar(); SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd"); if ((gc.get(Calendar.YEAR) - Integer.parseInt(strYear)) > 150 || (gc.getTime().getTime() - s.parse( strYear + "-" + strMonth + "-" + strDay).getTime()) < 0) { errorInfo = "身份证生日不在有效范围。"; return errorInfo; } if (Integer.parseInt(strMonth) > 12 || Integer.parseInt(strMonth) == 0) { errorInfo = "身份证月份无效"; return errorInfo; } if (Integer.parseInt(strDay) > 31 || Integer.parseInt(strDay) == 0) { errorInfo = "身份证日期无效"; return errorInfo; } // =====================(end)===================== // ================ 地区码时候有效 ================ Hashtable h = GetAreaCode(); if (h.get(Ai.substring(0, 2)) == null) { errorInfo = "身份证地区编码错误。"; return errorInfo; } // ============================================== // ================ 判断最后一位的值 ================ int TotalmulAiWi = 0; for (int i = 0; i < 17; i++) { TotalmulAiWi = TotalmulAiWi + Integer.parseInt(String.valueOf(Ai.charAt(i))) * Integer.parseInt(Wi[i]); } int modValue = TotalmulAiWi % 11; String strVerifyCode = ValCodeArr[modValue]; Ai = Ai + strVerifyCode; if (IDStr.length() == 18) { if (Ai.equals(IDStr) == false) { errorInfo = "身份证无效,不是合法的身份证号码"; return errorInfo; } } else { return ""; } // =====================(end)===================== return ""; } /** * 功能:设置地区编码 * * @return Hashtable 对象 */ @SuppressWarnings("unchecked") private static Hashtable GetAreaCode() { Hashtable hashtable = new Hashtable(); hashtable.put("11", "北京"); hashtable.put("12", "天津"); hashtable.put("13", "河北"); hashtable.put("14", "山西"); hashtable.put("15", "内蒙古"); hashtable.put("21", "辽宁"); hashtable.put("22", "吉林"); hashtable.put("23", "黑龙江"); hashtable.put("31", "上海"); hashtable.put("32", "江苏"); hashtable.put("33", "浙江"); hashtable.put("34", "安徽"); hashtable.put("35", "福建"); hashtable.put("36", "江西"); hashtable.put("37", "山东"); hashtable.put("41", "河南"); hashtable.put("42", "湖北"); hashtable.put("43", "湖南"); hashtable.put("44", "广东"); hashtable.put("45", "广西"); hashtable.put("46", "海南"); hashtable.put("50", "重庆"); hashtable.put("51", "四川"); hashtable.put("52", "贵州"); hashtable.put("53", "云南"); hashtable.put("54", "西藏"); hashtable.put("61", "陕西"); hashtable.put("62", "甘肃"); hashtable.put("63", "青海"); hashtable.put("64", "宁夏"); hashtable.put("65", "新疆"); hashtable.put("71", "台湾"); hashtable.put("81", "香港"); hashtable.put("82", "澳门"); hashtable.put("91", "国外"); return hashtable; } /** * 功能:判断字符串是否为数字 * * @param str * @return */ private static boolean isNumeric(String str) { Pattern pattern = Pattern.compile("[0-9]*"); Matcher isNum = pattern.matcher(str); if (isNum.matches()) { return true; } else { return false; } } /** * 功能:判断字符串是否为日期格式 * * @param str * @return */ public static boolean isDate(String strDate) { Pattern pattern = Pattern .compile("^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1-2][0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$"); Matcher m = pattern.matcher(strDate); if (m.matches()) { return true; } else { return false; } } /*********************************** 身份证验证结束 ****************************************/ }
很多人不会使用第三方应用,特写此篇使用下第三方应用:代码具体如下:
【ConstantS.java】
public interface ConstantS { // 应用的key 请到官方申请正式的appkey替换APP_KEY public static final String APP_KEY = "2045436852"; // 替换为开发者REDIRECT_URL public static final String REDIRECT_URL = "http://www.sina.com"; // 新支持scope:支持传入多个scope权限,用逗号分隔 public static final String SCOPE = "email,direct_messages_read,direct_messages_write," + "friendships_groups_read,friendships_groups_write,statuses_to_me_read," + "follow_app_official_microblog," + "invitation_write"; public static final String CLIENT_ID = "client_id"; public static final String RESPONSE_TYPE = "response_type"; public static final String USER_REDIRECT_URL = "redirect_uri"; public static final String DISPLAY = "display"; public static final String USER_SCOPE = "scope"; public static final String PACKAGE_NAME = "packagename"; public static final String KEY_HASH = "key_hash"; }
【MainActivity.java】
import java.text.SimpleDateFormat; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; import android.widget.Toast; import com.weibo.sdk.android.Oauth2AccessToken; import com.weibo.sdk.android.Weibo; import com.weibo.sdk.android.WeiboAuthListener; import com.weibo.sdk.android.WeiboDialogError; import com.weibo.sdk.android.WeiboException; import com.weibo.sdk.android.sso.SsoHandler; import com.weibo.sdk.android.util.AccessTokenKeeper; public class MainActivity extends Activity { /** 显示认证后的信息,如AccessToken */ private TextView mText; /** 微博API接口类,提供登陆等功能 */ private Weibo mWeibo; /** 封装了 "access_token","expires_in","refresh_token",并提供了他们的管理功能 */ private Oauth2AccessToken mAccessToken; /** 注意:SsoHandler 仅当sdk支持sso时有效 */ private SsoHandler mSsoHandler; private Intent intent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mText = (TextView) findViewById(R.id.show); mWeibo = Weibo.getInstance(ConstantS.APP_KEY, ConstantS.REDIRECT_URL, ConstantS.SCOPE); // 触发sso测试button findViewById(R.id.share).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getApplicationContext(), ShareActivity.class); intent.putExtra("id", R.id.share); startActivity(intent); } }); // 触发sso测试button findViewById(R.id.sso).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mSsoHandler = new SsoHandler(MainActivity.this, mWeibo); mSsoHandler.authorize(new AuthDialogListener(), null); } }); // 从 SharedPreferences 中读取上次已保存好 AccessToken 等信息, // 第一次启动本应用,AccessToken 不可用 mAccessToken = AccessTokenKeeper.readAccessToken(this); if (mAccessToken.isSessionValid()) { String date = new java.text.SimpleDateFormat("yyyy/MM/dd hh:mm:ss") .format(new java.util.Date(mAccessToken.getExpiresTime())); mText.setText("access_token 仍在有效期内,无需再次登录: \naccess_token:" + mAccessToken.getToken() + "\n有效期:" + date); } else { mText.setText("使用SSO登录前,请检查手机上是否已经安装新浪微博客户端," + "目前仅3.0.0及以上微博客户端版本支持SSO;如果未安装,将自动转为Oauth2.0进行认证"); } } /** * 微博认证授权回调类。 1. SSO登陆时,需要在{@link #onActivityResult} * 中调用mSsoHandler.authorizeCallBack后, 该回调才会被执行。 2. 非SSO登陆时,当授权后,就会被执行。 * 当授权成功后,请保存该access_token、expires_in等信息到SharedPreferences中。 */ class AuthDialogListener implements WeiboAuthListener { @Override public void onComplete(Bundle values) { String token = values.getString("access_token"); String expires_in = values.getString("expires_in"); mAccessToken = new Oauth2AccessToken(token, expires_in); if (mAccessToken.isSessionValid()) { String date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss") .format(new java.util.Date(mAccessToken .getExpiresTime())); mText.setText("认证成功: \r\n access_token: " + token + "\r\n" + "expires_in: " + expires_in + "\r\n有效期:" + date); AccessTokenKeeper.keepAccessToken(MainActivity.this, mAccessToken); Toast.makeText(MainActivity.this, "认证成功", Toast.LENGTH_SHORT) .show(); } } @Override public void onError(WeiboDialogError e) { Toast.makeText(getApplicationContext(), "Auth error : " + e.getMessage(), Toast.LENGTH_LONG).show(); } @Override public void onCancel() { Toast.makeText(getApplicationContext(), "Auth cancel", Toast.LENGTH_LONG).show(); } @Override public void onWeiboException(WeiboException e) { Toast.makeText(getApplicationContext(), "Auth exception : " + e.getMessage(), Toast.LENGTH_LONG) .show(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // SSO 授权回调 // 重要:发起 SSO 登陆的Activity必须重写onActivityResult if (mSsoHandler != null) { mSsoHandler.authorizeCallBack(requestCode, resultCode, data); } } }
【ShareActivity.java】
import android.app.Activity; import android.content.Intent; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.sina.weibo.sdk.WeiboSDK; import com.sina.weibo.sdk.api.BaseResponse; import com.sina.weibo.sdk.api.IWeiboAPI; import com.sina.weibo.sdk.api.IWeiboHandler; import com.sina.weibo.sdk.api.ImageObject; import com.sina.weibo.sdk.api.SendMessageToWeiboRequest; import com.sina.weibo.sdk.api.SendMultiMessageToWeiboRequest; import com.sina.weibo.sdk.api.TextObject; import com.sina.weibo.sdk.api.WeiboMessage; import com.sina.weibo.sdk.api.WeiboMultiMessage; /** * 该Activity演示了第三方应用如何发送请求消息给微博客户端。发送的内容包括文字、图片、视频、音乐等。 执行流程: 从本应用->微博->本应用 */ public class ShareActivity extends Activity implements OnClickListener, IWeiboHandler.Response { /** 微博OpenAPI访问入口 */ IWeiboAPI mWeiboAPI = null; // UI元素列表 /** 分享文本 */ private TextView mTitle; /** 分享图片 */ private ImageView mImage; /** 分享按钮 */ private Button mSharedBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.share); initViews(); // 创建微博对外接口实例 mWeiboAPI = WeiboSDK.createWeiboAPI(this, ConstantS.APP_KEY); mWeiboAPI.responseListener(getIntent(), this); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); mWeiboAPI.responseListener(intent, this); } /** * 从本应用->微博->本应用 接收响应数据,该方法被调用。 注意:确保{@link #onCreate(Bundle)} 与 * {@link #onNewIntent(Intent)}中, 调用 mWeiboAPI.responseListener(intent, * this) */ @Override public void onResponse(BaseResponse baseResp) { switch (baseResp.errCode) { case com.sina.weibo.sdk.constant.Constants.ErrorCode.ERR_OK: Toast.makeText(this, "成功!!", Toast.LENGTH_LONG).show(); break; case com.sina.weibo.sdk.constant.Constants.ErrorCode.ERR_CANCEL: Toast.makeText(this, "用户取消!!", Toast.LENGTH_LONG).show(); break; case com.sina.weibo.sdk.constant.Constants.ErrorCode.ERR_FAIL: Toast.makeText(this, baseResp.errMsg + ":失败!!", Toast.LENGTH_LONG) .show(); break; } } /** * 用户点击分享按钮,唤起微博客户端进行分享。 */ @Override public void onClick(View v) { if (R.id.sharedBtn == v.getId()) { mWeiboAPI.registerApp(); reqMsg(true, true, false, false, false, false); } } private void initViews() { mSharedBtn = (Button) findViewById(R.id.sharedBtn); mSharedBtn.setOnClickListener(this); mTitle = (TextView) findViewById(R.id.titleText); mImage = (ImageView) findViewById(R.id.image); } private void reqMsg(boolean hasText, boolean hasImage, boolean hasWebpage, boolean hasMusic, boolean hasVedio, boolean hasVoice) { if (mWeiboAPI.isWeiboAppSupportAPI()) { Toast.makeText(this, "当前微博版本支持SDK分享", Toast.LENGTH_SHORT).show(); int supportApi = mWeiboAPI.getWeiboAppSupportAPI(); if (supportApi >= 10351) { Toast.makeText(this, "当前微博版本支持多条消息,Voice消息分享", Toast.LENGTH_SHORT).show(); reqMultiMsg(hasText, hasImage, hasWebpage, hasMusic, hasVedio, hasVoice); } else { Toast.makeText(this, "当前微博版本只支持单条消息分享", Toast.LENGTH_SHORT) .show(); reqSingleMsg(hasText, hasImage, hasWebpage, hasMusic, hasVedio/* * , * hasVoice */); } } else { Toast.makeText(this, "当前微博版本不支持SDK分享", Toast.LENGTH_SHORT).show(); } } /** * 第三方应用发送请求消息到微博,唤起微博分享界面。 注意:当isWeiboAppSupportAPI() >= 10351 * 时,支持同时分享多条消息, 同时可以分享文本、图片以及其它媒体资源(网页、音乐、视频、声音中的一种), 并且支持Voice消息。 * * @param hasText * 分享的内容是否有文本 * @param hasImage * 分享的内容是否有图片 * @param hasWebpage * 分享的内容是否有网页 * @param hasMusic * 分享的内容是否有音乐 * @param hasVideo * 分享的内容是否有视频 * @param hasVoice * 分享的内容是否有声音 */ private void reqMultiMsg(boolean hasText, boolean hasImage, boolean hasWebpage, boolean hasMusic, boolean hasVideo, boolean hasVoice) { // 1. 初始化微博的分享消息 WeiboMultiMessage weiboMessage = new WeiboMultiMessage(); if (hasText) { weiboMessage.textObject = getTextObj(); } if (hasImage) { weiboMessage.imageObject = getImageObj(); } // 2. 初始化从第三方到微博的消息请求 SendMultiMessageToWeiboRequest req = new SendMultiMessageToWeiboRequest(); // 用transaction唯一标识一个请求 req.transaction = String.valueOf(System.currentTimeMillis()); req.multiMessage = weiboMessage; // 3. 发送请求消息到微博,唤起微博分享界面 mWeiboAPI.sendRequest(this, req); } /** * 第三方应用发送请求消息到微博,唤起微博分享界面。 当isWeiboAppSupportAPI() < 10351 只支持分享单条消息,即 * 文本、图片、网页、音乐、视频中的一种,不支持Voice消息。 * * @param hasText * 分享的内容是否有文本 * @param hasImage * 分享的内容是否有图片 * @param hasWebpage * 分享的内容是否有网页 * @param hasMusic * 分享的内容是否有音乐 * @param hasVideo * 分享的内容是否有视频 */ private void reqSingleMsg(boolean hasText, boolean hasImage, boolean hasWebpage, boolean hasMusic, boolean hasVideo/* * , boolean * hasVoice */) { // 1. 初始化微博的分享消息 // 用户可以分享文本、图片、网页、音乐、视频中的一种 WeiboMessage weiboMessage = new WeiboMessage(); if (hasText) { weiboMessage.mediaObject = getTextObj(); } if (hasImage) { weiboMessage.mediaObject = getImageObj(); } // 2. 初始化从第三方到微博的消息请求 SendMessageToWeiboRequest req = new SendMessageToWeiboRequest(); // 用transaction唯一标识一个请求 req.transaction = String.valueOf(System.currentTimeMillis()); req.message = weiboMessage; // 3. 发送请求消息到微博,唤起微博分享界面 mWeiboAPI.sendRequest(this, req); } /** * 文本消息构造方法。 * * @return 文本消息对象。 */ private TextObject getTextObj() { TextObject textObject = new TextObject(); textObject.text = mTitle.getText().toString(); return textObject; } /** * 图片消息构造方法。 * * @return 图片消息对象。 */ private ImageObject getImageObj() { ImageObject imageObject = new ImageObject(); BitmapDrawable bitmapDrawable = (BitmapDrawable) mImage.getDrawable(); imageObject.setImageObject(bitmapDrawable.getBitmap()); return imageObject; } }
完整代码下载===》》》 weibo.sdk.android.demo.zip