[Android] 噗浪姬Project - Day4 驗證頁面

大家好,又到了這個單位,嘛,我 Day 4 後面的數字其實根本就是形式上的流水號了...
對,這裡是明明喊著隔天要讓他出來結果莫明奇妙卡一堆事然後就一直生不出來XD
在 Day3 上我介紹過 OAuth ,而這章我就是要講解如何取得 Token 及 TokenSecret
然後透過取得的 Token 及 TokenSecret 結合原本我們申請 App 時取得的 AppKey 及 AppSecret 去呼叫 API
我大致介紹一下,我的頁面最後切成:
.EntryActivity:這個頁面是進入頁,會透過這個頁面確認使用者的 Token 是否可以正常呼叫 API ,如可,則進入主頁面,不然的話則進入登入頁面
.MainActivity:這個頁面是未來我們要開發功能的主頁面,目前上面我只有放一個呼叫 Profile/getOwnProfile 這 API 的函式在上面
.PlurkAuthActivity:這個頁面是登入頁面,使用者會透過這個頁面進行帳號的登入。

在這我要稍微提及一下,我本來的登入頁面是用 Dialog 的方式,可是我又覺得我的 MainActivity 很難判斷他倒底是正常登入了,還是他按了叉叉或旁邊的空白處所以沒登入
而這也關係著接下來要顯示的資訊,所以最後我放棄用 dialog 的方式,全都透過 startActivity 來跳轉頁面。

EntryActivity
package wct.apps.plurk;

import wct.apps.plurk.Database.DBHelper;
import wct.apps.plurk.OAuth.Plurk;
import wct.apps.plurk.OAuth.Plurk.OnRequestListener;
import wct.apps.plurk.OAuth.PlurkAuthActivity;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Window;

public class EntryActivity extends Activity {
 private DBHelper _dbHelper = null;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  _dbHelper = new DBHelper(this);
  
  String Token = _dbHelper.getConfigFactory().getToken();
  String TokenSecret = _dbHelper.getConfigFactory().getTokenSecret();
  
  requestWindowFeature(Window.FEATURE_NO_TITLE);
  
  Log.d("EntryActivity", "onCreate");
  
  Plurk _plurk = new Plurk();
  if(Token != null && Token != "" && TokenSecret != null && TokenSecret != "")
   _plurk.setTokenAndSecret(Token, TokenSecret);
  
  _plurk.authorize(this, new OnRequestListener() {

   @Override
   public void onComplete(String response) {
    // TODO Auto-generated method stub    
    Intent intent = new Intent();
    intent.setClass(EntryActivity.this, MainActivity.class);
    EntryActivity.this.startActivity(intent);
    EntryActivity.this.finish();
   }

   @Override
   public void onError() {
    // TODO Auto-generated method stub
    Intent intent = new Intent();
    intent.setClass(EntryActivity.this, PlurkAuthActivity.class);
    EntryActivity.this.startActivity(intent);
    EntryActivity.this.finish();
   }
  });
 }
 
 @Override
 protected void onDestroy() {
  super.onDestroy();
  _dbHelper.close();
  
  Log.d("EntryActivity", "onDestroy");
 }
}

以上就是我的 EntryActivity 程式碼,可以看到其實他就是很簡單的分派,當可以驗證正常時會跳到 MainActivity ,否則則是 PlurkAuthActivity
package wct.apps.plurk.OAuth;

import wct.apps.plurk.MainActivity;
import wct.apps.plurk.Database.DBHelper;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.ViewGroup.LayoutParams;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

public class PlurkAuthActivity extends Activity {
 private static PlurkAuthActivity _instance = null;
 
 private FrameLayout mContent = null;
 private WebView mWebView;
 private String mUrl = null;
 
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  _instance = this;
  
  Log.d("PlurkAuthActivity", "onCreate");
  
  requestWindowFeature(Window.FEATURE_NO_TITLE);  
  Plurk.getInstance();
  
  new wct.apps.plurk.OAuth.AsyncRequestTokenTask(Plurk.getInstance().getConsumer(), Plurk.getInstance().getProvider(), new wct.apps.plurk.OAuth.IAsyncResponse() {
   @Override
   public void processFinish(String response) {
    mUrl = response;
    
    Log.d("PlurkAuthActivity", mUrl);
    
    setUpWebView(0);
    
    addContentView(mContent, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
   }
  }).execute();
  
  mContent = new FrameLayout(this);
 }
 
 @SuppressLint("SetJavaScriptEnabled")
 private void setUpWebView(int margin) {
        LinearLayout webViewContainer = new LinearLayout(this);
        LinearLayout webViewContainerInner = new LinearLayout(this);
        mWebView = new WebView(this);
        mWebView.setVerticalScrollBarEnabled(false);
        mWebView.setHorizontalScrollBarEnabled(false);
        mWebView.setWebViewClient(new WebViewClient() {
         public void onPageStarted(WebView view, String url, Bitmap favicon){
         }
         public void onPageFinished(WebView view, String url){
         }
         public boolean shouldOverrideUrlLoading(WebView view, String url){
          
          Log.d("TAG", "url = " + url);
          
          if (url.contains(Plurk.CALLBACK_URL)){
           (new AsyncTask() {

      @Override
      protected Long doInBackground(String... params) {
       // TODO Auto-generated method stub
       if(params.length > 0)
       {
        Plurk.parseTokenAndSecret(params[0]);
        
        DBHelper _dbHelper = new DBHelper(PlurkAuthActivity.this);
        _dbHelper.getConfigFactory().setToken(Plurk.getInstance().getToken());
        _dbHelper.getConfigFactory().setTokenSecret(Plurk.getInstance().getSecret());
        _dbHelper.close();
        
        Intent intent = new Intent();
              intent.setClass(PlurkAuthActivity.this, MainActivity.class);
              startActivity(intent);
              PlurkAuthActivity.this.finish();
       }
       return (long) 0;
      }
            
           }).execute(url);
           return true;
          }
          if (url.compareToIgnoreCase("http://www.plurk.com/m/t") == 0){
           Log.d("TAG", "redirect to login");
           url = Plurk.user_aithorize_url;
              Log.d("TAG", "redirect to login url = " + url);
           view.loadUrl(url);
           
           return false;
          }
          
          view.loadUrl(url);
          return false;
         }
        });
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.loadUrl(mUrl);
        mWebView.setVisibility(View.VISIBLE);
        
        webViewContainer.setPadding(margin, margin, margin, margin);
        
        webViewContainer.addView(webViewContainerInner, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        webViewContainerInner.setPadding(10, 10, 10, 5);
        
        webViewContainerInner.addView(mWebView);
        
        mContent.addView(webViewContainer);
    }
 
 public static PlurkAuthActivity getInstance()
 {
  return _instance;
 }
}

以上是 PlurkAuthActivity 相關的程式碼,至於 Main 我就不附上了, gitHub 上有
那附程式碼就是有些東西想講的,其實我在取資料時一直遇到 OAuthCommunicationException 這個例外一直產生,由於整個錯誤都被包裝起來了,其實我真的看不懂為何發生錯誤
最後透過在 OAuthProvider 上透過 setListener 來抓問題,好不容易抓到... 原來是 HttpGet 丟出 NetworkOnMainThreadException 這個例外訊息,查了一下主要是不允許使用者在 UI 的執行緒上進行一些可能會耗時很久的操作(EX: 網路),所以在上面的 shouldOverrideUrlLoading 中包著一個 AsyncTask 來進行非同步的執行
當然,網路上也有教學是講可以透過 StrictMode.setThreadPolicy 的方式設定 ThreadPolicy 使其原本的程式碼正常運作,但是他會去阻檔在 UI 層的耗時運作一定是有其原因的,所以建議還是乖乖的用多執行緒的方式解決掉

接下來後面的我其實不知要教什麼了,有可能是 json 的解析,也有可能是版面動態載入的設計,我會想想再來弄的!
今天大概是這樣,有任何問題都可以提出來共同討論。


解決NetworkOnMainThreadException的問題
kswlee - github - PlurkAndroidOAuth

留言

這個網誌中的熱門文章

DB 資料庫呈現復原中

Outlook 刪除大量重覆信件

[VB.Net] If vs IIf ,兩者的差異