1. 程式人生 > >新浪微部落格戶端開發之授權登入+獲取微博列表

新浪微部落格戶端開發之授權登入+獲取微博列表

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!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 Constprivate 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;    }