首页 > 代码库 > Android新浪微博客户端(四)——添加多个账户及认证

Android新浪微博客户端(四)——添加多个账户及认证

原文出自:方杰| http://fangjie.sinaapp.com/?p=75 转载请注明出处

最终效果演示:http://fangjie.sinaapp.com/?page_id=54
该项目代码已经放到github:https://github.com/JayFang1993/SinaWeibo

二.获取用户信息并保存数据库

上面说到加载AuthActivity有两种情况,其中一种就是授权成功回调,在授权回调成功后我们就开始通过微博API获取用户信息了,然后保存数据库了。这一系列操作我采用主框架模式,将任务发送给MainService来处理。

对于这个任务的具体处理过程,先通过token获取UID,再通过UID获取UserInfo。UserInfo中值得注意的是UserIcon是Bitmap类型的,这里涉及到一个通过url获取Bitmap的方法,这里就不细讲了。

MainService.java中的doTask方法:

public void doTask(Task task)
{
  Message msg=handler.obtainMessage();
  msg.what=task.getTaskID();
  switch(task.getTaskID())
  {
	  //登录操作
	  case Task.WEIBO_LOGIN:
	  	break;

	  //通过access_token获取用户信息,并保存到数据库操作
	  case Task.GET_USERINFO_BY_TOKEN:
	  {
		  Oauth2AccessToken access_token=(Oauth2AccessToken)task.getParams().get("token");
		  Log.i("OUTPUT", "access_token:"+access_token.getToken());
		  /**
		  * 步骤一:用授权码来获取用户Uid
		  */
		  //请求获取uid
		  String uid="";
		  GetUserInfo.reqUID(access_token);
		  //获取uid
		  do{
		  	uid=GetUserInfo.getUID();
		  }while(uid.equals(""));
		  /**
		  * 步骤二:通过uid,token获取UserInfo
		  */
		  //请求获取用户信息
		  long _uid=Long.parseLong(uid);
		  UserInfo user=new UserInfo();
		  GetUserInfo.reqUserInfo(access_token, _uid);
		  //获取UserInfo
		  do{
		  	user=GetUserInfo.getUserInfo();
		  }while(user.getUserName().equals(""));
		  user.setUserId(uid);
		  //Log.i("OUTPUT","username:"+user.getUserName()+"userid+"+user.getUserId()+"usericon"+user.getUserIcon());

		  /**
		  * 步骤三:把UserInfo的数据保存到数据库总
		  */
		  //创建数据库
		  DBUserInfo db=new DBUserInfo(getActivityByName("AuthActivity"));
		  //如果该数据不存在数据库中
		  if(db.getUserInfoByUserId(uid)==null)
		  {
			  //插入
			  db.insertUserInfo(user);
			  Log.i("OUTPUT","保存数据库成功");
		  }
		  //如果该数据已经存在数据库中
		  else
		  {
			  //修改
			  Log.i("OUTPUT","数据修改成功");
		  }
		  msg.obj="成功";
		}
	  	break;
	  //登录界面获取用户信息显示操作
	  case Task.GET_USERINFO_IN_LOGIN:

	  break;
	  default :
	  	break;
  }
  handler.sendMessage(msg);
}
上面的微博API操作都是异步的操作所以同样采取先请求,然后获取的操作。这种方式在授权部分已经讲的很清楚了。

然后就是保存数据库的操作,这里都是最基本的数据库使用方式了,就是有一点需要注意的是,UserIcon保存的是BOLB二进制数据。

GetUserInfo.java   //利用微博API获取用户信息的工具方法类

package com.fangjie.weibo.util;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import org.json.JSONException;
import org.json.JSONObject;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import com.fangjie.weibo.bean.UserInfo;
import com.weibo.sdk.android.Oauth2AccessToken;
import com.weibo.sdk.android.WeiboException;
import com.weibo.sdk.android.api.AccountAPI;
import com.weibo.sdk.android.api.UsersAPI;
import com.weibo.sdk.android.net.RequestListener;
/**
 * GetUserInfo类
 * 通过API获取用户信息
 * @author 方杰
 * @date 2013-7-29
 */
public class GetUserInfo {

  public static String UID="";
  private static UserInfo user;

  /**
  * 通过accessToken请求用户信息UID
  * @param accessToken
  */
  public static void reqUID(Oauth2AccessToken accessToken)
  {
	  AccountAPI account=new AccountAPI(accessToken);
	  account.getUid(new RequestListener(){
		  @Override
		  public void onComplete(String result) {
		  // TODO Auto-generated method stub
			  try {
				  JSONObject object =new JSONObject(result);
				  UID=object.getString("uid");
			  } catch (JSONException e) {
				  // TODO Auto-generated catch block
				  e.printStackTrace();
			  }
		  }
		  @Override
		  public void one rror(WeiboException arg0) {
		  	// TODO Auto-generated method stub
		  }
		  @Override
		  public void onIOException(IOException arg0) {
		  	// TODO Auto-generated method stub

		  }
	  });
  }

  /**
  * 请求UID之后,获取UID
  * @return string
  */
  public static String getUID()
  {
	  String id=UID;
	  UID="";
	  return id;
  }

  /**
  * 通过accessToken,uid请求获取用户信息UserInfo(name,icon......)
  * @param accessToken
  * @param uid
  */
  public static void reqUserInfo(final Oauth2AccessToken accessToken,long uid)
  {
	  user=new UserInfo();
	  UsersAPI userapi=new UsersAPI(accessToken);
	  userapi.show(uid, new RequestListener() {
		  @Override
		  public void onIOException(IOException arg0) {
		  // TODO Auto-generated method stub

		  }
		  @Override
		  public void one rror(WeiboException arg0) {
		  // TODO Auto-generated method stub

		  }

		  @Override
		  public void onComplete(String arg0) {
			  // TODO Auto-generated method stub
			  JSONObject object;
			  try {
				  object = new JSONObject(arg0);
				  Bitmap bm=GetUserInfo.getBitmap(object.getString("profile_image_url"));
				  GetUserInfo.user.setUserIcon(bm);
				  GetUserInfo.user.setToken(accessToken.getToken());
				  GetUserInfo.user.setIsDefault("0");
				  GetUserInfo.user.setUserName(object.getString("screen_name"));
			  } catch (JSONException e) {
			  	// TODO Auto-generated catch block
			  	e.printStackTrace();
			  }
	 	 }
	  });
	}

  public static UserInfo getUserInfo()
  {
	  Log.i("OUTPUT",user.getUserName());
	  return user;
  }

  public static Bitmap getBitmap(String biturl)
  {
	  Bitmap bitmap=null;

	  try {
	  URL url=new URL(biturl);
	  URLConnection conn=url.openConnection();
	  InputStream in =conn.getInputStream();
	  bitmap=BitmapFactory.decodeStream(new BufferedInputStream(in));
  	} catch (Exception e) {
	  	// TODO Auto-generated catch block
	  	e.printStackTrace();
	  }
	  return bitmap;
  }
}

DBUserInfo.java  //操作用户信息的数据库工具方法类

package com.fangjie.weibo.db;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;

import com.fangjie.weibo.bean.UserInfo;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.util.Log;

public class DBUserInfo {

  private DBHelper dbhelper;
  public DBUserInfo(Context context)
  {
  	dbhelper = new DBHelper(context);
  }
  /**
  * 添加用户信息
  * @param UserInfo
  */
  public void insertUserInfo(UserInfo user)
  {
	  SQLiteDatabase db = dbhelper.getWritableDatabase();

	  ByteArrayOutputStream baos=new ByteArrayOutputStream();
	  user.getUserIcon().compress(Bitmap.CompressFormat.PNG, 100, baos);
	  byte[] usericon=baos.toByteArray();
	  ContentValues values = new ContentValues(5);

	  values.put(UserInfo.USER_ID,user.getUserId());
	  values.put(UserInfo.USER_NAME, user.getUserName());
	  values.put(UserInfo.TOKEN,user.getToken());
	  values.put(UserInfo.IS_DEFAULT,user.getIsDefault());
	  values.put(UserInfo.USER_ICON,usericon);

	  db.insert(UserInfo.TB_NAME, null, values);//表名称
	  db.close();
  }
  /**
  * 根据用户userId获取用户对象
  * @param String
  * @return UserInfo
  */
  public UserInfo getUserInfoByUserId(String uid)
  {

	  SQLiteDatabase db = dbhelper.getReadableDatabase();

	  Cursor cursor =db.query(UserInfo.TB_NAME, new String[]{UserInfo.ID,UserInfo.IS_DEFAULT,UserInfo.TOKEN,
	  UserInfo.USER_ID,UserInfo.USER_NAME,UserInfo.USER_ICON},
	  UserInfo.USER_ID +"=?",new String[]{uid}, null, null, null);
	  UserInfo userInfo =null;

	  if(null != cursor)
	  {
		  if(cursor.getCount() >0)
		  {
			  cursor.moveToFirst();
			  userInfo = new UserInfo();
			  Long id =cursor.getLong(cursor.getColumnIndex(UserInfo.ID));
			  String uId = cursor.getString(cursor.getColumnIndex(UserInfo.USER_ID));
			  String userName = cursor.getString(cursor.getColumnIndex(UserInfo.USER_NAME));
			  String token = cursor.getString(cursor.getColumnIndex(UserInfo.TOKEN));
			  String isDefault = cursor.getString(cursor.getColumnIndex(UserInfo.IS_DEFAULT));
			  byte[] byteIcon = cursor.getBlob(cursor.getColumnIndex(UserInfo.USER_ICON));

			  userInfo.setId(id);
			  userInfo.setUserId(uId);
			  userInfo.setIsDefault(isDefault);
			  userInfo.setToken(token);
			  userInfo.setToken(token);
			  userInfo.setUserName(userName);
			  if(null !=byteIcon)
			  {
				  Bitmap userIcon=BitmapFactory.decodeByteArray(byteIcon, 0, byteIcon.length);
				  userInfo.setUserIcon(userIcon);
			  }
	  	}
  	}
	  db.close();
	  return userInfo;
  }

  /**
  * 获取数据库所有授权用户信息
  * @param
  * @return List<UserInfo>
  */

  public List<UserInfo> getAllUserInfo()
  {
	  List<UserInfo> users=new ArrayList<UserInfo>();

	  SQLiteDatabase db = dbhelper.getReadableDatabase();
	  Cursor cursor =db.query(UserInfo.TB_NAME, new String[]{UserInfo.ID,UserInfo.IS_DEFAULT,UserInfo.TOKEN,
	  UserInfo.USER_ID,UserInfo.USER_NAME,UserInfo.USER_ICON},
	  null,null, null, null, null);
	  UserInfo userInfo =null;

	  while(cursor.moveToNext())
	  {
		  userInfo = new UserInfo();
		  Long id =cursor.getLong(cursor.getColumnIndex(UserInfo.ID));
		  String uId = cursor.getString(cursor.getColumnIndex(UserInfo.USER_ID));
		  String userName = cursor.getString(cursor.getColumnIndex(UserInfo.USER_NAME));
		  String token = cursor.getString(cursor.getColumnIndex(UserInfo.TOKEN));
		  String isDefault = cursor.getString(cursor.getColumnIndex(UserInfo.IS_DEFAULT));
		  byte[] byteIcon = cursor.getBlob(cursor.getColumnIndex(UserInfo.USER_ICON));

		  userInfo.setId(id);
		  userInfo.setUserId(uId);
		  userInfo.setIsDefault(isDefault);
		  userInfo.setToken(token);
		  userInfo.setUserName(userName);

		  if(null !=byteIcon)
		  {
			  Bitmap userIcon=BitmapFactory.decodeByteArray(byteIcon, 0, byteIcon.length);
			  Log.i("OUTPUT","dbuserinfo"+userIcon);
			  userInfo.setUserIcon(userIcon);
		  }
		  users.add(userInfo);
		}
	  db.close();
	  return users;
  }
}

三.获取所有授权用户信息并显示在登录界面上

还记得在上面的AuthActivity中我们发送的GET_USERINFO_BY_TOKEN (获取授权用户信息并保存数据库)这个任务,这个任务完成后,我们会在refresh()方法中跳到LoginActivity。在LoginActivity的初始时,我们会发送GET_USERINFO_IN_LOGIN(获取所有授权用户信息),在做这个任务处理时也就是数据库的操作。

//登录界面获取用户信息显示操作
  case Task.GET_USERINFO_IN_LOGIN:
  {
	  DBUserInfo db=new DBUserInfo(getActivityByName("LoginActivity"));
	  List<UserInfo> users=db.getAllUserInfo();
	  msg.obj=users;
  }

其他:

讲完上面这些,我突然想讲讲这个addActivty,reMoveActivty,getActivityByName

/**
  * UI层向MainService中发送任务的同时,同样要发送自己Activity,
  * 以便在MainService中调用refresh();
  * @param task
  */
  public static void addActivty(Activity activity)
  {
  	appActivities.add(activity);
  }
  /**
  * UI层中有向MainService中传递Activity,在任务结束后(refresh),应去除该Activity,防止混淆!
  * eg:在LoginActivity中的GET_USERINFO_IN_LOGIN任务会随Activity的每次重新加载而开始一次,如果不去除
  * activity的话,会导致本次refresh的是上次的activity的实例。因为获取activity是通过getActivityByName,这两
  * 次的activity实例的name是相同的。
  * @param activity
  */
  public static void reMoveActivty(Activity activity)
  {
 	 appActivities.remove(activity);
  }

特别是reMoveActivty这个方法,我自己在做项目的时候就忘记了在每次完成任务时去删除这个Activity实例,导致了这样一个错误

程序启动的时候会到LoginActivity,这时候做了一次GET_USERINFO_IN_LOGIN,就把LoginAcivity的一个实例传到activities中,当我再次添加一个授权用户信息,完成后再次跳到LoginActivity时,这时界面上就没有任何显示信息。因为当第二次跳到LoginActivity时,再次传一个LoginActivity的实例,而我在完成任务后refresh()时,刷新的是第一次的LoginActivity实例,所以对第二次的LoginActivity当然是没有显示。

通过上面这三个方法的配合我们就可以由Activity向一些工具类方法传递Context上下文的参数,比如在建立数据库时需要Context这个参数,还有在工具类中跳转的时候也需要用到Context参数。虽然这种传参可能会增加层与层之间的耦合度,但是我目前就这水平,也请大家给我指点。

 欢迎各位关注我的个人站点:http://fangjie.sinaapp.com/