分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
新浪微博客户端开发之授权登录+获取微博列表
闲篇:
最近实在是乱得不行,至于怎么乱我也不知该怎么说,那么久没发博客就证明了这点,一般如果小巫有做详尽的计划,并把时间投入到上面的话,我是可以用最短的时间里把新浪微博客户端给整出来的,但现在进度很慢,我越来越不像个称职的程序猿,因为现在的生活已经不再是代码,更多的是想多享受跟朋友们在一起的快乐。这些话也不多说了,关于这个项目,其实我也头痛了一整子,我很久之前就买了一本李宁的Android应用开发实战,里面很大篇幅就是介绍这个客户端的开发,因为一开始我是比较迷惑的,迷惑他到底有没有使用新浪开发平台提供的SDK,然而整个授权过程到获取微博的各种数据又是怎样的?我还在考虑我要做成一个怎样的,是否只是单纯的模仿呢?反正种种疑虑,一阵子找不到北了。后来我花时间研究了他的代码,慢慢的也找了了一些门道,明白了他从是怎么把整个客户端搭建起来的,他没有使用新浪给我们提供的SDK,而似乎是把SDK的实现给翻出来了,因为SDK仅仅提供了获取微博数据的封装,开发者就只需调用API,知道怎么传参数就行了,所以很多高手是不会直接使用新浪提供的Android SDK。要我从头到尾开发,把所有业务逻辑实现,我实在不行,所以会直接参考Android应用开发实战所提供的代码,把整个新浪微博客户端开发出来给大家看看,这也算是小巫的一个提升,与大家共同进步。
正篇:
本篇博客呢,主要介绍如何进行授权认证,如何获取微博列表,因为代码比较多,我不会全部都能贴出来,整个客户端也没有开发完毕,我也是实现一个功能,然后整理博客发表出来,如果想要项目源码的,可以直接找我,我的QQ:659982592, 如果我在的话,我会尽快答复你的。
先来看看本篇博客想要实现的效果图:
看到以上的效果,我想很多人都想知道是如何实现的,不急,我们慢慢来看,这个可不是能一口吃掉的螃蟹。
我先简单介绍一下以上效果图的业务流程,启动程序后,首先需要获取用户授权,假如已经授权过了,就不会出现提示用户输入登录的界面,授权成功后,直接获取微博数据,显示到微博列表当中。整个流程其实也蛮简单的,现在我们来看看代码。
/Wwj_sina_weibo/src/com/wwj/sina/weibo/WeiboMain.java
这个类用来切换底部标签的,比较高的版本已经不推荐用这种方法实现,不过没关系,反正高版本兼容低版本。
package com.wwj.sina.weibo;import android.app.TabActivity;import android.content.Intent;import android.os.Bundle;import android.widget.RadioButton;import android.widget.RadioGroup;import android.widget.RadioGroup.OnCheckedChangeListener;import android.widget.TabHost;import android.widget.TabHost.TabSpec;/** * 主Activity * @author wwj * 通过点击RadioGroup下的RadioButton来切换不同界面 */@SuppressWarnings("deprecation")public class WeiboMain extends TabActivity { public TabHost mTabhost; public static final String TAB_HOME = "TabHome"; public static final String TAB_MSG = "TabMsg"; public static final String TAB_SELF = "TabSelfInfo"; public static final String TAB_DISCOVE = "TabDiscove"; public static final String TAB_MORE = "TabMore"; RadioButton radio_button0; public static RadioGroup indexGroup; @SuppressWarnings("static-access") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 设置无标题 requestWindowFeature(getWindow().FEATURE_NO_TITLE); this.setContentView(R.layout.tabbar); radio_button0 = (RadioButton) this.findViewById(R.id.tabbar_home); radio_button0.setChecked(true); // 设置首页按钮默认是按下状态 mTabhost = (TabHost) findViewById(android.R.id.tabhost); // 获取TabHost // 设定标签、制定一个标签作为选项卡指示符 TabSpec tabSpec1 = mTabhost.newTabSpec(TAB_HOME).setIndicator(TAB_HOME); // 指定一个加载activity的Intent对象作为选项卡内容 tabSpec1.setContent(new Intent(WeiboMain.this, HomeActivity.class)); mTabhost.addTab(tabSpec1); // 添加第一个子页 TabSpec tabSpec2 = mTabhost.newTabSpec(TAB_MSG).setIndicator(TAB_MSG); tabSpec2.setContent(new Intent(WeiboMain.this, MessageActivity.class)); mTabhost.addTab(tabSpec2); // 添加第二个子页 TabSpec tabSpec3 = mTabhost.newTabSpec(TAB_SELF).setIndicator(TAB_SELF); tabSpec3.setContent(new Intent(WeiboMain.this, SelfInfoActivity.class)); mTabhost.addTab(tabSpec3); // 添加第三个子页 TabSpec tabSpec4 = mTabhost.newTabSpec(TAB_DISCOVE).setIndicator( TAB_DISCOVE); tabSpec4.setContent(new Intent(WeiboMain.this, DiscoveActivity.class)); mTabhost.addTab(tabSpec4); // 添加第四个子页 TabSpec tabSpec5 = mTabhost.newTabSpec(TAB_MORE).setIndicator(TAB_MORE); tabSpec5.setContent(new Intent(WeiboMain.this, MoreActivity.class)); mTabhost.addTab(tabSpec5); // 添加第一个子页 this.indexGroup = (RadioGroup) this.findViewById(R.id.main_radio); // 实现RadioGroup的子选项点击监听 indexGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { switch (checkedId) { case R.id.tabbar_home: // 首页 mTabhost.setCurrentTabByTag(TAB_HOME); break; case R.id.tabbar_message:// 信息 mTabhost.setCurrentTabByTag(TAB_MSG); break; case R.id.tabbar_me: // 个人资料 mTabhost.setCurrentTabByTag(TAB_SELF); break; case R.id.tabbar_discove: // 发现 mTabhost.setCurrentTabByTag(TAB_DISCOVE); break; case R.id.tabbar_more: // 更多 mTabhost.setCurrentTabByTag(TAB_MORE); } } }); }}
/Wwj_sina_weibo/src/com/wwj/sina/weibo/HomeActivity.java
这个Activity就是显示微博列表的界面,代码还不完善,这里只看关键点。
package com.wwj.sina.weibo;import java.util.List;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.MenuItem;import android.view.MenuItem.OnMenuItemClickListener;import android.view.View;import android.view.View.OnClickListener;import android.view.WindowManager;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.AdapterView.OnItemLongClickListener;import android.widget.Button;import android.widget.LinearLayout;import android.widget.TextView;import com.weibo.net.Weibo;import com.wwj.sina.weibo.adapter.WeiboListAdapter;import com.wwj.sina.weibo.interfaces.Const;import com.wwj.sina.weibo.library.StorageManager;import com.wwj.sina.weibo.library.WeiboData;import com.wwj.sina.weibo.library.WeiboManager;import com.wwj.sina.weibo.listener.impl.StatusRequestListenerImpl;import com.wwj.sina.weibo.object.Status;import com.wwj.sina.weibo.object.User;import com.wwj.sina.weibo.util.Tools;import com.wwj.sina.weibo.view.PullToRefreshListView;import com.wwj.sina.weibo.view.PullToRefreshListView.OnRefreshListener;import com.wwj.sina.weibo.workqueue.DoneAndProcess;import com.wwj.sina.weibo.workqueue.WorkQueueMonitor;import com.wwj.sina.weibo.workqueue.task.ParentTask;import com.wwj.sina.weibo.workqueue.task.PullFileTask;/** * 主界面 * * @author wwj 用于显示公共微博 */public class HomeActivity extends Activity implements Const, OnClickListener, OnItemClickListener, OnItemLongClickListener, OnMenuItemClickListener, DoneAndProcess { public PullToRefreshListView weiboListView; // 自定义ListView private Weibo weibo; // 微博对象 public HomeData homeData; // 主界面数据 public TextView username; // 用户名,显示在标题栏 public Button btn_post_weibo; // 发布微博 public Button btn_reload; // 加载新微博 private LinearLayout linearLayoutHome; private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { }; }; // 微博列表主界面的数据 public static class HomeData { public WeiboListAdapter weiboListAdapter; public WorkQueueMonitor imageWorkQueueMonitor; public WorkQueueMonitor taskWorkQueueMonitor; public User user; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.home); getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); loadView(); getWindow().setBackgroundDrawable(null); weibo = Tools.getWeibo(this); // 获取微博对象 homeData = (HomeData) getLastNonConfigurationInstance(); if (homeData == null) { homeData = new HomeData(); if (!(weibo == null || !weibo.isSessionValid())) { @SuppressWarnings("unchecked") List<Status> statuses = StorageManager.loadList(this, Const.HOME); if (statuses == null) { statuses = WeiboManager.getHomeTimeline(this); } homeData.weiboListAdapter = WeiboData.loadWeiboListData(this, Const.HOME, weiboListView, statuses); } } } @Override protected void onResume() { super.onResume(); } @Override public Object onRetainNonConfigurationInstance() { return homeData; } // 加载视图 private void loadView() { weiboListView = (PullToRefreshListView) findViewById(R.id.weibolist); linearLayoutHome = (LinearLayout) findViewById(R.id.ll_home_layout); username = (TextView) this.findViewById(R.id.tv_home_name); btn_post_weibo = (Button) this.findViewById(R.id.btn_home_post_weibo); btn_reload = (Button) this.findViewById(R.id.btn_home_reload); weiboListView.setOnItemClickListener(this); btn_post_weibo.setOnClickListener(this); btn_reload.setOnClickListener(this); } @Override public void onClick(View v) { Intent intent = null; GlobalObject globalObject = Tools.getGlobalObject(this); switch (v.getId()) { case R.id.btn_home_post_weibo: // 发布微博 intent = new Intent(HomeActivity.this, PostWeibo.class); startActivity(intent); break; case R.id.btn_home_reload: // 刷新列表 long sinceId = homeData.weiboListAdapter.getMaxId() + 1; WeiboManager.getHomeTimeline(this, sinceId, 0, DEFAULT_STATUS_COUNT, true, new StatusRequestListenerImpl( this, linearLayoutHome, HOME)); View homeReloadAnim = findViewById(R.id.pb_home_reload); View homeReload = findViewById(R.id.btn_home_reload); homeReloadAnim.setVisibility(View.VISIBLE); homeReload.setVisibility(View.GONE); break; } } @Override public void doneProcess(ParentTask task) { Message msg = new Message(); msg.obj = task; if (task instanceof PullFileTask) { msg.what = HANDLER_TYPE_LOAD_PROFILE_IMAGE; msg.obj = ((PullFileTask) task).fileUrl; } handler.sendMessage(msg); } @Override public boolean onMenuItemClick(MenuItem item) { return false; } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { return false; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Intent intent = null; switch (parent.getId()) { case R.id.weibolist: // 按更多项 // 注意:更多点击的位置 if (position == homeData.weiboListAdapter.getCount()) { long maxId = homeData.weiboListAdapter.getMinId() - 1; WeiboManager.getHomeTimeline(this, 0, maxId, DEFAULT_STATUS_COUNT, true, new StatusRequestListenerImpl(this, linearLayoutHome, HOME)); homeData.weiboListAdapter.showMoreAnim(); } else { // 点击列表项 Status status = homeData.weiboListAdapter.getStatus(position); if (status != null) { intent = new Intent(this, WeiboViewer.class); WeiboViewer.status = status; startActivity(intent); } } break; } }}
上面使用到一个Tools类,这是一个工具类,用来获取微博对象和一些转换操作,稍微看一下
/Wwj_sina_weibo/src/com/wwj/sina/weibo/util/Tools.java
package com.wwj.sina.weibo.util;import java.io.InputStream;import java.io.OutputStream;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Locale;import java.util.regex.Matcher;import java.util.regex.Pattern;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Color;import android.text.Spannable;import android.text.SpannableString;import android.text.Spanned;import android.text.style.ImageSpan;import android.view.View;import android.widget.ImageView;import com.weibo.net.Weibo;import com.wwj.sina.weibo.GlobalObject;import com.wwj.sina.weibo.interfaces.Const;import com.wwj.sina.weibo.library.FaceMan;public class Tools implements Const { /** * 获取微博对象 * @param activity * @return */ public static Weibo getWeibo(Activity activity) { GlobalObject globalObject = (GlobalObject) activity .getApplicationContext(); return globalObject.getWeibo(activity); } /** * 判断当前是否有微博对象 * @param activity * @return */ public static boolean hasWeibo(Activity activity) { GlobalObject globalObject = (GlobalObject) activity .getApplicationContext(); return globalObject.getWeibo() == null ? false : true; } public static GlobalObject getGlobalObject(Activity activity) { GlobalObject globalObject = (GlobalObject) activity .getApplicationContext(); return globalObject; } // 将微博的日期字符串转换为Date对象 public static Date strToDate(String str) { // sample:Tue May 31 17:46:55 +0800 2011 // E:周 MMM:字符串形式的月,如果只有两个M,表示数值形式的月 Z表示时区(+0800) SimpleDateFormat sdf = new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy", Locale.US); Date result = null; try { result = sdf.parse(str); } catch (Exception e) { // TODO: handle exception } return result; } public static void dataTransfer(InputStream is, OutputStream os) { byte[] buffer = new byte[8192]; int count = 0; try { while((count = is.read(buffer)) > -1) { os.write(buffer, 0, count); } } catch (Exception e) { } } public static void userVerified(ImageView imageView, int verifiedType) { if (verifiedType >= 0) { imageView.setVisibility(View.VISIBLE); switch (verifiedType) { case 0: case 220: imageView.setImageLevel(verifiedType); break; default: imageView.setImageLevel(1); break; } } } public static SpannableString changeTextToFace(Context context, Spanned spanned) { String text = spanned.toString(); SpannableString spannableString = new SpannableString(spanned); Pattern pattern = Pattern.compile("\\[[^\\]]+\\]"); Matcher matcher = pattern.matcher(text); boolean b = true; while (b = matcher.find()) { String faceText = text.substring(matcher.start(), matcher.end()); int resourceId = FaceMan.getResourceId(faceText); if (resourceId > 0) { Bitmap bitmap = BitmapFactory.decodeResource( context.getResources(), resourceId); ImageSpan imageSpan = new ImageSpan(bitmap); spannableString.setSpan(imageSpan, matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } return spannableString; } public static String atBlue(String s) { StringBuilder sb = new StringBuilder(); int commonTextColor = Color.BLACK; int signColor = Color.BLUE; int state = 1; String str = ""; for (int i = 0; i < s.length(); i++) { switch (state) { case 1: // 普通字符状态 // 遇到@ if (s.charAt(i) == '@') { state = 2; str += s.charAt(i); } // 遇到# else if (s.charAt(i) == '#') { str += s.charAt(i); state = 3; } // 添加普通字符 else { if (commonTextColor == Color.BLACK) sb.append(s.charAt(i)); else sb.append("<font color='" + commonTextColor + "'>" + s.charAt(i) + "</font>"); } break; case 2: // 处理遇到@的情况 // 处理@后面的普通字符 if (Character.isJavaIdentifierPart(s.charAt(i))) { str += s.charAt(i); } else { // 如果只有一个@,作为普通字符处理 if ("@".equals(str)) { sb.append(str); } // 将@及后面的普通字符变成蓝色 else { sb.append(setTextColor(str, String.valueOf(signColor))); } // @后面有#的情况,首先应将#添加到str里,这个值可能会变成蓝色,也可以作为普通字符,要看后面还有没有#了 if (s.charAt(i) == '#') { str = String.valueOf(s.charAt(i)); state = 3; } // @后面还有个@的情况,和#类似 else if (s.charAt(i) == '@') { str = String.valueOf(s.charAt(i)); state = 2; } // @后面有除了@、#的其他特殊字符。需要将这个字符作为普通字符处理 else { if (commonTextColor == Color.BLACK) sb.append(s.charAt(i)); else sb.append("<font color='" + commonTextColor + "'>" + s.charAt(i) + "</font>"); state = 1; str = ""; } } break; case 3: // 处理遇到#的情况 // 前面已经遇到一个#了,这里处理结束的# if (s.charAt(i) == '#') { str += s.charAt(i); sb.append(setTextColor(str, String.valueOf(signColor))); str = ""; state = 1; } // 如果#后面有@,那么看一下后面是否还有#,如果没有#,前面的#作废,按遇到@处理 else if (s.charAt(i) == '@') { if (s.substring(i).indexOf("#") < 0) { sb.append(str); str = String.valueOf(s.charAt(i)); state = 2; } else { str += s.charAt(i); } } // 处理#...#之间的普通字符 else { str += s.charAt(i); } break; } } if (state == 1 || state == 3) { sb.append(str); } else if (state == 2) { if ("@".equals(str)) { sb.append(str); } else { sb.append(setTextColor(str, String.valueOf(signColor))); } } return sb.toString(); } public static String setTextColor(String s, String color) { String result = "<font color='" + color + "'>" + s + "</font>"; return result; } public static String getTimeStr(Date oldTime, Date currentDate) { long time1 = currentDate.getTime(); long time2 = oldTime.getTime(); long time = (time1 - time2) / 1000; if (time >= 0 && time < 60) { return "刚才"; } else if (time >= 60 && time < 3600) { return time / 60 + "分钟前"; } else if (time >= 3600 && time < 3600 * 24) { return time / 3600 + "小时前"; } else { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); return sdf.format(oldTime); } }}
上面定义了一个getWeibo()的方法,可以看到它是通过GlobalObject来获取微博对象的,那在看看这个类
/Wwj_sina_weibo/src/com/wwj/sina/weibo/GlobalObject.java
package com.wwj.sina.weibo;import android.app.Activity;import android.app.Application;import com.weibo.net.Weibo;import com.wwj.sina.weibo.interfaces.Const;import com.wwj.sina.weibo.listener.AuthDialogListener;import com.wwj.sina.weibo.net.PullFile;import com.wwj.sina.weibo.object.Consumer;import com.wwj.sina.weibo.workqueue.WorkQueueMonitor;import com.wwj.sina.weibo.workqueue.WorkQueueStorage;public class GlobalObject extends Application implements Const{ private Weibo weibo; private WorkQueueStorage workQueueStorage; private WorkQueueMonitor imageWorkQueueMonitor; private WorkQueueMonitor taskWorkQueueMonitor; public Weibo getWeibo(Activity activity) { if (weibo == null || !weibo.isSessionValid()) { weibo = Weibo.getInstance(); // 获取Weibo对象 weibo.setupConsumerConfig(Consumer.consumerKey, Consumer.consumerSecret); weibo.setRedirectUrl(Consumer.redirectUrl); weibo.authorize(activity, new AuthDialogListener(activity)); } return weibo; } public Weibo getWeibo() { return weibo; } public WorkQueueStorage getWorkQueueStorage() { if (workQueueStorage == null){ workQueueStorage = new WorkQueueStorage(); } return workQueueStorage; } public WorkQueueMonitor getWorkQueueMonitor(Activity activity) { if (imageWorkQueueMonitor == null) { imageWorkQueueMonitor = new WorkQueueMonitor(activity, getWorkQueueStorage(), new PullFile(), MONITOR_TYPE_IMAGE); imageWorkQueueMonitor.start(); } return imageWorkQueueMonitor; } }
可以看到这个类是Application级别的,说明最先加载的是这个类,来看这个类定义的getWeibo()方法,现在很直观啦,这里就是获取授权认证的地方。设置好consumerKey和consumerSecret后,就可以调用authorize()方法进行授权了。这个方法在Weibo这个类当中,这个类很重要,能不能使用微博功能就看它了。
/Wwj_sina_weibo/src/com/weibo/net/Weibo.java
/* * Copyright 2011 Sina. * * Licensed under the Apache License and Weibo 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.open.weibo.com * 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. */package com.weibo.net;import java.io.IOException;import java.net.MalformedURLException;import android.Manifest;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.content.pm.PackageManager;import android.os.Bundle;import android.text.TextUtils;import android.util.Log;import android.webkit.CookieSyncManager;/** * Encapsulation main Weibo APIs, Include: 1. getRquestToken , 2. * getAccessToken, 3. url request. Used as a single instance class. Implements a * weibo api as a synchronized way. * * @author ZhangJie ([email protected]) */public class Weibo { // public static String SERVER = "http://api.t.sina.com.cn/"; public static String SERVER = "https://api.weibo.com/2/"; public static String URL_OAUTH_TOKEN = "http://api.t.sina.com.cn/oauth/request_token"; public static String URL_AUTHORIZE = "http://api.t.sina.com.cn/oauth/authorize"; public static String URL_ACCESS_TOKEN = "http://api.t.sina.com.cn/oauth/access_token"; public static String URL_AUTHENTICATION = "http://api.t.sina.com.cn/oauth/authenticate"; public static String URL_OAUTH2_ACCESS_TOKEN = "https://api.weibo.com/oauth2/access_token"; // public static String URL_OAUTH2_ACCESS_AUTHORIZE = // "http://t.weibo.com:8093/oauth2/authorize"; public static String URL_OAUTH2_ACCESS_AUTHORIZE = "https://api.weibo.com/oauth2/authorize"; private static String APP_KEY = ""; private static String APP_SECRET = ""; private static Weibo mWeiboInstance = null; private Token mAccessToken = null; private RequestToken mRequestToken = null; private WeiboDialogListener mAuthDialogListener; private static final int DEFAULT_AUTH_ACTIVITY_CODE = 32973; public static final String TOKEN = "access_token"; public static final String EXPIRES = "expires_in"; public static final String DEFAULT_REDIRECT_URI = "wbconnect://success";// 暂不支持 public static final String DEFAULT_CANCEL_URI = "wbconnect://cancel";// 暂不支持 private String mRedirectUrl; private Weibo() { Utility.setRequestHeader("Accept-Encoding", "gzip"); Utility.setTokenObject(this.mRequestToken); mRedirectUrl = DEFAULT_REDIRECT_URI; } /** * 获取单例 * @return */ public synchronized static Weibo getInstance() { if (mWeiboInstance == null) { mWeiboInstance = new Weibo(); } return mWeiboInstance; } // 设置accessToken public void setAccessToken(AccessToken token) { mAccessToken = token; } public Token getAccessToken() { return this.mAccessToken; } /** * 设置第三方key和secret * @param consumer_key * @param consumer_secret */ public void setupConsumerConfig(String consumer_key, String consumer_secret) { Weibo.APP_KEY = consumer_key; Weibo.APP_SECRET = consumer_secret; } public static String getAppKey() { return Weibo.APP_KEY; } public static String getAppSecret() { return Weibo.APP_SECRET; } public void setRequestToken(RequestToken token) { this.mRequestToken = token; } public static String getSERVER() { return SERVER; } public static void setSERVER(String sERVER) { SERVER = sERVER; } // 设置oauth_verifier public void addOauthverifier(String verifier) { mRequestToken.setVerifier(verifier); } public String getRedirectUrl() { return mRedirectUrl; } /** * 设置第三方回调页 * @param mRedirectUrl */ public void setRedirectUrl(String mRedirectUrl) { this.mRedirectUrl = mRedirectUrl; } /** * Requst sina weibo open api by get or post * * @param url * Openapi request URL. * @param params * http get or post parameters . e.g. * gettimeling?max=max_id&min=min_id max and max_id is a pair of * key and value for params, also the min and min_id * @param httpMethod * http verb: e.g. "GET", "POST", "DELETE" * @throws IOException * @throws MalformedURLException * @throws WeiboException */ public String request(Context context, String url, WeiboParameters params, String httpMethod, Token token) throws WeiboException { String rlt = Utility.openUrl(context, url, httpMethod, params, this.mAccessToken); return rlt; } /**/ public RequestToken getRequestToken(Context context, String key, String secret, String callback_url) throws WeiboException { Utility.setAuthorization(new RequestTokenHeader()); WeiboParameters postParams = new WeiboParameters(); postParams.add("oauth_callback", callback_url); String rlt; rlt = Utility.openUrl(context, Weibo.URL_OAUTH_TOKEN, "POST", postParams, null); RequestToken request = new RequestToken(rlt); this.mRequestToken = request; return request; } public AccessToken generateAccessToken(Context context, RequestToken requestToken) throws WeiboException { Utility.setAuthorization(new AccessTokenHeader()); WeiboParameters authParam = new WeiboParameters(); authParam.add("oauth_verifier", this.mRequestToken.getVerifier()/* "605835" */); authParam.add("source", APP_KEY); String rlt = Utility.openUrl(context, Weibo.URL_ACCESS_TOKEN, "POST", authParam, this.mRequestToken); AccessToken accessToken = new AccessToken(rlt); this.mAccessToken = accessToken; return accessToken; } public AccessToken getXauthAccessToken(Context context, String app_key, String app_secret, String usrname, String password) throws WeiboException { Utility.setAuthorization(new XAuthHeader()); WeiboParameters postParams = new WeiboParameters(); postParams.add("x_auth_username", usrname); postParams.add("x_auth_password", password); postParams.add("oauth_consumer_key", APP_KEY); String rlt = Utility.openUrl(context, Weibo.URL_ACCESS_TOKEN, "POST", postParams, null); AccessToken accessToken = new AccessToken(rlt); this.mAccessToken = accessToken; return accessToken; } /** * 获取Oauth2.0的accesstoken * * https://api.weibo.com/oauth2/access_token?client_id=YOUR_CLIENT_ID& * client_secret=YOUR_CLIENT_SECRET&grant_type=password&redirect_uri= * YOUR_REGISTERED_REDIRECT_URI&username=USER_NAME&pasword=PASSWORD * * @param context * @param app_key * @param app_secret * @param usrname * @param password * @return * @throws WeiboException */ public Oauth2AccessToken getOauth2AccessToken(Context context, String app_key, String app_secret, String usrname, String password) throws WeiboException { Utility.setAuthorization(new Oauth2AccessTokenHeader()); WeiboParameters postParams = new WeiboParameters(); postParams.add("username", usrname); postParams.add("password", password); postParams.add("client_id", app_key); postParams.add("client_secret", app_secret); postParams.add("grant_type", "password"); String rlt = Utility.openUrl(context, Weibo.URL_OAUTH2_ACCESS_TOKEN, "POST", postParams, null); Oauth2AccessToken accessToken = new Oauth2AccessToken(rlt); this.mAccessToken = accessToken; return accessToken; } /** * Share text content or image to weibo . * */ public boolean share2weibo(Activity activity, String accessToken, String tokenSecret, String content, String picPath) throws WeiboException { if (TextUtils.isEmpty(accessToken)) { throw new WeiboException("token can not be null!"); } // else if (TextUtils.isEmpty(tokenSecret)) { // throw new WeiboException("secret can not be null!"); // } if (TextUtils.isEmpty(content) && TextUtils.isEmpty(picPath)) { throw new WeiboException("weibo content can not be null!"); } Intent i = new Intent(activity, ShareActivity.class); i.putExtra(ShareActivity.EXTRA_ACCESS_TOKEN, accessToken); i.putExtra(ShareActivity.EXTRA_TOKEN_SECRET, tokenSecret); i.putExtra(ShareActivity.EXTRA_WEIBO_CONTENT, content); i.putExtra(ShareActivity.EXTRA_PIC_URI, picPath); activity.startActivity(i); return true; } private boolean startSingleSignOn(Activity activity, String applicationId, String[] permissions, int activityCode) { return false; } public static boolean flag = false; private void startDialogAuth(Activity activity, String[] permissions) { if(flag == true) return; WeiboParameters params = new WeiboParameters(); if (permissions.length > 0) { params.add("scope", TextUtils.join(",", permissions)); } CookieSyncManager.createInstance(activity); dialog(activity, params, new WeiboDialogListener() { public void onComplete(Bundle values) { flag = false; // ensure any cookies set by the dialog are saved CookieSyncManager.getInstance().sync(); if (null == mAccessToken) { mAccessToken = new Token(); } mAccessToken.setToken(values.getString(TOKEN)); mAccessToken.setExpiresIn(values.getString(EXPIRES)); if (isSessionValid()) { Log.d("Weibo-authorize", "Login Success! access_token=" + mAccessToken.getToken() + " expires=" + mAccessToken.getExpiresIn()); mAuthDialogListener.onComplete(values); } else { Log.d("Weibo-authorize", "Failed to receive access token"); mAuthDialogListener.onWeiboException(new WeiboException( "Failed to receive access token.")); } } public void onError(DialogError error) { flag = false; Log.d("Weibo-authorize", "Login failed: " + error); mAuthDialogListener.onError(error); } public void onWeiboException(WeiboException error) { flag = false; Log.d("Weibo-authorize", "Login failed: " + error); mAuthDialogListener.onWeiboException(error); } public void onCancel() { flag = false; Log.d("Weibo-authorize", "Login canceled"); mAuthDialogListener.onCancel(); } }); flag = true; } /** * User-Agent Flow * * @param activity * * @param listener * 授权结果监听器 */ public void authorize(Activity activity, final WeiboDialogListener listener) { authorize(activity, new String[] {}, DEFAULT_AUTH_ACTIVITY_CODE, listener); } @SuppressWarnings("unused") private void authorize(Activity activity, String[] permissions, final WeiboDialogListener listener) { authorize(activity, permissions, DEFAULT_AUTH_ACTIVITY_CODE, listener); } private void authorize(Activity activity, String[] permissions, int activityCode, final WeiboDialogListener listener) { Utility.setAuthorization(new Oauth2AccessTokenHeader()); boolean singleSignOnStarted = false; mAuthDialogListener = listener; // Prefer single sign-on, where available. if (activityCode >= 0) { singleSignOnStarted = startSingleSignOn(activity, APP_KEY, permissions, activityCode); } // Otherwise fall back to traditional dialog. if (!singleSignOnStarted) { startDialogAuth(activity, permissions); } } @SuppressWarnings("unused") private void authorizeCallBack(int requestCode, int resultCode, Intent data) { } public void dialog(Context context, WeiboParameters parameters, final WeiboDialogListener listener) { parameters.add("client_id", APP_KEY); parameters.add("response_type", "token"); parameters.add("redirect_uri", mRedirectUrl); parameters.add("display", "mobile"); if (isSessionValid()) { parameters.add(TOKEN, mAccessToken.getToken()); } String url = URL_OAUTH2_ACCESS_AUTHORIZE + "?" + Utility.encodeUrl(parameters); if (context.checkCallingOrSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) { Utility.showAlert(context, "Error", "Application requires permission to access the Internet"); } else { new WeiboDialog(this, context, url, listener).show(); } } public boolean isSessionValid() { if (mAccessToken != null) { return (!TextUtils.isEmpty(mAccessToken.getToken()) && (mAccessToken.getExpiresIn() == 0 || (System .currentTimeMillis() < mAccessToken.getExpiresIn()))); } return false; }}
你们自己找到authorize()看看呗,怎么弹出那个登录界面的自己研究去,这个方法需要传入一个listener,
就是这个类了AuthDialogListener
/Wwj_sina_weibo/src/com/wwj/sina/weibo/listener/AuthDialogListener.java
授权完成后,回调这个类的onComplete方法,然后就可以获取微博数据了。
package com.wwj.sina.weibo.listener;import android.app.Activity;import android.os.Bundle;import android.widget.Toast;import com.weibo.net.DialogError;import com.weibo.net.WeiboDialogListener;import com.weibo.net.WeiboException;import com.wwj.sina.weibo.HomeActivity;import com.wwj.sina.weibo.adapter.WeiboListAdapter;import com.wwj.sina.weibo.interfaces.Const;import com.wwj.sina.weibo.library.StorageManager;import com.wwj.sina.weibo.library.WeiboData;import com.wwj.sina.weibo.library.WeiboManager;import com.wwj.sina.weibo.object.User;import com.wwj.sina.weibo.util.SettingUtil;public class AuthDialogListener implements WeiboDialogListener { private Activity activity; public AuthDialogListener(Activity activity) { super(); this.activity = activity; } public void onComplete(Bundle values) { // 保存access_token 和 expires_in String token = values.getString("access_token"); String expires_in = values.getString("expires_in"); SettingUtil.set(activity, SettingUtil.ACCESS_TOKEN, token); SettingUtil.set(activity, SettingUtil.EXPIRES_IN, expires_in); Toast.makeText(activity, "认证成功", Toast.LENGTH_SHORT).show(); HomeActivity homeActivity = (HomeActivity) activity; WeiboListAdapter weiboListAdapter = null; long uid = Long.parseLong(values.getString("uid")); User user = WeiboManager.getUser(activity, uid); if (user != null) { homeActivity.username.setText(user.name); StorageManager.setValue(activity, "uid", uid); // 保存用户UID } weiboListAdapter = WeiboData.loadWeiboListData(activity, Const.HOME, homeActivity.weiboListView); homeActivity.homeData.weiboListAdapter = weiboListAdapter; } public void onWeiboException(WeiboException e) { // 当认证过程中捕获到WeiboException时调用 Toast.makeText(activity, "Auth exception:" + e.getMessage(), Toast.LENGTH_LONG).show(); } public void onError(DialogError e) { // Oauth2.0认证过程中,当认证对话框中的webView接收数据出现错误时调用此方法 Toast.makeText(activity, "Auth error:" + e.getMessage(), Toast.LENGTH_LONG).show(); } public void onCancel() { // Oauth2.0认证过程中,如果认证窗口被关闭或认证取消时调用 Toast.makeText(activity, "Auth cancel", Toast.LENGTH_LONG).show(); }}
执行完这个就已经把数据显示出来了
WeiboData.loadWeiboListData(activity, Const.HOME,homeActivity.weiboListView);
这里又有一个WeiboData这个类,看看就明白了
package com.wwj.sina.weibo.library;import java.util.List;import android.app.Activity;import android.widget.ListView;import com.wwj.sina.weibo.adapter.WeiboListAdapter;import com.wwj.sina.weibo.interfaces.Const;import com.wwj.sina.weibo.object.Status;import com.wwj.sina.weibo.util.Tools;public class WeiboData implements Const { public static WeiboListAdapter loadWeiboListData(Activity activity, int type, ListView listView) { return loadWeiboListData(activity, type, listView, null); } public static WeiboListAdapter loadWeiboListData(Activity activity, int type, ListView listView, List<Status> statuses) { WeiboListAdapter adapter = null; if (Tools.hasWeibo(activity)) { switch (type) { case HOME: if (statuses == null) statuses = WeiboManager.getHomeTimeline(activity); adapter = new WeiboListAdapter(activity, statuses, type); break; default: break; } listView.setAdapter(adapter); } return adapter; }}
可以看到,这里ListView就直接setAdapter了。来看到第二个loadWeiboListData方法,有一个List<Status> statuses参数,这个就是保存微博数据的参数了,是怎么得到的?我们又可以看到一个类WeiboManager里有一个getHomeTimeline的方法,这个就是返回微博数据的方法。
等不及了,进去看看。
/Wwj_sina_weibo/src/com/wwj/sina/weibo/library/WeiboManager.java
package com.wwj.sina.weibo.library;import java.io.File;import java.util.List;import android.app.Activity;import com.weibo.net.AsyncWeiboRunner;import com.weibo.net.AsyncWeiboRunner.RequestListener;import com.weibo.net.Weibo;import com.weibo.net.WeiboParameters;import com.wwj.sina.weibo.interfaces.Const;import com.wwj.sina.weibo.object.Consumer;import com.wwj.sina.weibo.object.Status;import com.wwj.sina.weibo.object.User;import com.wwj.sina.weibo.util.Tools;import com.wwj.sina.weibo.workqueue.DoneAndProcess;import com.wwj.sina.weibo.workqueue.WorkQueueStorage;import com.wwj.sina.weibo.workqueue.task.PullFileTask;/** * 微博管理类,提供方法获取微博数据 * * @author Administrator * */public class WeiboManager implements Const { public static List<Status> getHomeTimeline(Activity activity) { return getHomeTimeline(activity, 0, 0, DEFAULT_STATUS_COUNT); } private static List<Status> getHomeTimeline(Activity activity, long sinceId, long maxId, int count) { return getHomeTimeline(activity, sinceId, maxId, count, false, null); } /** * 获取当前登录用户及其所关注用户的最新微博 * * @param activity * @param sinceId * @param maxId * @param count * @param async * 是否同步 * @param listener * @return */ @SuppressWarnings("unchecked") public static List<Status> getHomeTimeline(Activity activity, long sinceId, long maxId, int count, boolean async, RequestListener listener) { // 访问接口url String url = Weibo.SERVER + "statuses/home_timeline.json"; // 获取微博对象 Weibo weibo = Tools.getWeibo(activity); if (weibo == null || !weibo.isSessionValid()) { return null; } WeiboParameters bundle = new WeiboParameters(); bundle.add("source", Consumer.consumerKey); if (sinceId != 0) bundle.add("since_id", String.valueOf(sinceId)); if (maxId != 0) bundle.add("max_id", String.valueOf(maxId)); if (count != 0) bundle.add("count", String.valueOf(count)); List<Status> statuses = null; try { if (!async) { // 请求获取JSON数据 String json = weibo.request(activity, url, bundle, "GET", weibo.getAccessToken()); statuses = JSONAndObject .convert(Status.class, json, "statuses"); } else { AsyncWeiboRunner asyncWeiboRunner = new AsyncWeiboRunner(weibo); asyncWeiboRunner .request(activity, url, bundle, "GET", listener); } } catch (Exception e) { } return statuses; } public static String getImageurl(Activity activity, String url) { return getImageurl(activity, url, null); } public static String getImageurl(Activity activity, String url, DoneAndProcess doneAndProcess) { String result = null; if (url == null || "".equals(url)) return result; result = PATH_FILE_CACHE + "/" + url.hashCode(); File file = new File(PATH_FILE_CACHE + "/" + url.hashCode()); if (file.exists()) { return result; } else { WorkQueueStorage workQueueStorage = Tools.getGlobalObject(activity) .getWorkQueueStorage(); if (workQueueStorage != null) { if (doneAndProcess == null) { workQueueStorage.addDoneWebFileUrl(url); } else { PullFileTask pullFileTask = new PullFileTask(); pullFileTask.doneAndProcess = doneAndProcess; pullFileTask.fileUrl = url; workQueueStorage.addTask(pullFileTask); } } result = null; } return result; } public static boolean hasPicture(Status status) { if (status.thumbnail_pic != null && !"".equals(status.thumbnail_pic)) return true; if (status.retweeted_status != null) { if (status.retweeted_status.thumbnail_pic != null && !"".equals(status.retweeted_status.thumbnail_pic)) { return true; } } return false; } public static User getUser(Activity activity, long uid) { return getUser(activity, uid, null, false, null); } public static User getUser(Activity activity, String screen_name) { return getUser(activity, 0, screen_name, false, null); } public static User getUser(Activity activity, long uid, String screen_name, boolean async, RequestListener listener) { String url = Weibo.SERVER + "users/show.json"; Weibo weibo = Tools.getWeibo(activity); if (weibo == null || !weibo.isSessionValid()) { return null; } User user = null; WeiboParameters bundle = new WeiboParameters(); bundle.add("source", Consumer.consumerKey); if (uid > 0) { bundle.add("uid", String.valueOf(uid)); } else if (screen_name != null) { bundle.add("screen_name", screen_name); } else { return user; } try { if (!async) { String json = weibo.request(activity, url, bundle, "GET", weibo.getAccessToken()); user = new User(); JSONAndObject.convertSingleObject((Object) user, json); } else { AsyncWeiboRunner asyncWeiboRunner = new AsyncWeiboRunner(weibo); asyncWeiboRunner .request(activity, url, bundle, "GET", listener); } } catch (Exception e) { } return user; }}
只看 getHomeTimeline()这个方法,一直追踪,很快就可以知道这个微博数据是怎么得到的了。
public static List<Status> getHomeTimeline(Activity activity, long sinceId, long maxId, int count, boolean async, RequestListener listener) { // 访问接口url String url = Weibo.SERVER + "statuses/home_timeline.json"; // 获取微博对象 Weibo weibo = Tools.getWeibo(activity); if (weibo == null || !weibo.isSessionValid()) { return null; } WeiboParameters bundle = new WeiboParameters(); bundle.add("source", Consumer.consumerKey); if (sinceId != 0) bundle.add("since_id", String.valueOf(sinceId)); if (maxId != 0) bundle.add("max_id", String.valueOf(maxId)); if (count != 0) bundle.add("count", String.valueOf(count)); List<Status> statuses = null; try { if (!async) { // 请求获取JSON数据 String json = weibo.request(activity, url, bundle, "GET", weibo.getAccessToken()); statuses = JSONAndObject .convert(Status.class, json, "statuses"); } else { AsyncWeiboRunner asyncWeiboRunner = new AsyncWeiboRunner(weibo); asyncWeiboRunner .request(activity, url, bundle, "GET", listener); } } catch (Exception e) { } return statuses; }
就是这个方法了,通过调用weibo对象的request()方法,返回Json字符串,通过解析得到的JSON字符串得到statuses数组。这里需要进行的转换,全靠JSONAndObject这个类
package com.wwj.sina.weibo.library;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.List;import org.json.JSONArray;import org.json.JSONObject;import android.util.Log;import com.wwj.sina.weibo.interfaces.WeiboObject;public class JSONAndObject { /** * 将一个对象转换为JSON格式的字符串,只转换public类型的变量 * * @param obj * @return */ public static String convertSingleObjectToJson(Object obj) { String json = null; if (obj == null) { return json; } Field[] fields = obj.getClass().getFields(); json = "{"; // 开始转换每一个public类型的变量 for (int i = 0; i < fields.length; i++) { try { Field field = fields[i]; if (field.getType() == String.class) { // 属性值为null, 用空字符串取代 String temp = ((field.get(obj) == null) ? "" : String .valueOf(field.get(obj))); // 处理字符串中的双引号 // JSON字符串中不能直接使用双引号 temp = temp.replaceAll("\"", "\\\\\""); json += "\"" + field.getName() + "\":\"" + temp + "\""; } // long类型 else if (field.getType() == long.class) { json += "\"" + field.getName() + "\":" + field.getLong(obj); } // int类型 else if (field.getType() == int.class) { json += "\"" + field.getName() + "\":" + field.getInt(obj); } // boolean类型 else if (field.getType() == boolean.class) { json += "\"" + field.getName() + "\":" + field.getBoolean(obj); } // Object类型(WeiboObject类型) else { Object fieldObject = field.get(obj); if (fieldObject instanceof WeiboObject) { // 如果对象中含有对象类型的变量 // 递归生成JSON字符串 json += "\"" + field.getName() + "\":" + convertSingleObjectToJson(fieldObject); } else { continue; } } if (i < fields.length - 1) { json += ","; } } catch (Exception e) { } } json += "}"; return json; } /** * 将obj转换为JSON字符串,该字符串必须是一个对象 其中obj必须是一个List,而且JSON字符串必须包含一个propertyName * 制定的属性,属性值是JSON数组,该数组与obj指定的List对应 类似于hometimeline.json返回的JSON字符串的逆过程 * * @param obj * @param propertyName * @return */ public static String covertObjectToJson(Object obj, String propertyName) { String json = null; if (obj == null