開始接觸學習android已經有3個禮拜了,一直都是對着android的sdk文檔寫Tutorials從Hello World到Notepad Tutorial算是初步入門了吧,恰好最近對微博感興趣就打算開發個android版本的新浪微博客戶端做爲練手項目,而且以隨筆的方式詳細的記錄開發的全過程。本人對java語言以及eclipse Ide都是初次應用基本上屬於邊學邊用,作移動設備上的東西也是第一次,總的來講屬於無基礎、無經驗、無天賦的純三無人員,還請廣大同窗們多多給予指點。
開發第一件事情,那就是開發工具以及環境,個人配置是Eclipse Helios (3.6.1) + Adroid2.2,具體的環境搭建我就不羅嗦了,google一下一大堆,光博客園裏都能搜到不少篇了。
開發第二件事情,既然是開發新浪的微博客戶端,那就先去新浪申請微博帳號而後登錄後到新浪的開放平臺,新浪的開放平臺提供的新浪微博對外的api接口,在個人應用中建立一個新的應用獲取App Key和App Secret,這2個值後面會有用到先記錄下來。在新浪的開放平臺中提供了開發文檔、SDK、接口測試工具等,本人決定直接經過新浪的Rest Api進行開發並不打算使用新浪提供的SDK,聽說新浪提供的java版的SDK並不能直接用來進行android的開發須要進行必定的修改才能使用,只是據說我沒有試過不必定準確。
最後在說一下,我準備分爲UI和功能兩部分分別進行說明講解,據我本身的狀況大部分的時間都花在的UI的設計和實現上了,編碼倒反而工做量小多了,因此特別把UI部分分出來說。
最後還要在說一下,很抱歉上面內容基本上屬於廢話沒有什麼實質內容了可是既然是第一篇仍是得象徵性的交代一下,從下篇開始講具體的內容。
本軟件設定用戶第一個接觸到的功能就是頁面載入等待功能,這個功能對使用者來講就是一個持續一、2秒鐘的等待頁面,在用戶等待的同時程序作一些必要的檢查以及數據準備工做,載入頁面分爲UI篇和功能篇,從表及裏首先是UI的實現,一個軟件除功能以外還得有一個光鮮的外表也是很是重要的,儘管本人設計水平通常可是仍是親自操刀用ps先作了一下設計效果圖以下:
6 天前 上傳
下載附件 (131.9 KB)
1、接下來的任務就是在android中實現這樣的效果顯示,從這個效果的設計分別把圖片分紅背景、版本號部分、軟件名稱和圖標、做者名稱和blog四個部分,按照這樣的思路把分別生成4張png的圖片,背景部分考慮實現橫屏和豎屏切換額外添加一張橫屏背景圖,而後新建android工程,我這裏的名稱爲MySinaWeibo,android版本勾選2.2,而且建立名爲MainActivity的Activity做爲整個軟件的起始頁面,而後把上面的這些圖片保存到項目的res/drawable-mdpi文件夾下,關於res目錄下的drawable-mdpi、drawable-ldpi,、drawable-hdpi三個文件夾的區別,mdpi 裏面主要放中等分辨率的圖片,如HVGA (320x480)。ldpi裏面主要放低分辨率的圖片,如QVGA (240x320)。hdpi裏面主要放高分辨率的圖片,如WVGA (480x800),FWVGA (480x854)。android系統會根據機器的分辨率來分別到這幾個文件夾裏面去找對應的圖片,在開發程序時爲了兼容不一樣平臺不一樣屏幕,建議各自文件夾根據需求均存放不一樣版本圖片,我這裏就不進行這麼多的考慮了。
2、完成圖片資源的準備後接下就是layout文件的編寫, 在res/layout文件夾下新建main.xml文件,這個layout採用LinearLayout控件做爲頂層控件,而後用ImageView控件分別實現版本號圖片頂部靠左對齊顯示、軟件名稱和圖標圖片居中對齊、做者名稱和blog圖片底部靠右對齊。注意在版本號圖片顯示ImageView控件下面添加一個RelativeLayout控件做爲軟件名稱和圖標圖片ImageVIew和做者名稱和blog圖片ImageView的父控件用來控制居中對齊已經底部對齊的實現,具體代碼以下:代碼
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ver"
android:layout_marginTop="15dip"
android:layout_marginLeft="15dip">
</ImageView>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo"
android:layout_centerInParent="true">
</ImageView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/dev"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="5dip"
android:layout_marginBottom="35dip">
</ImageView>
</RelativeLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ver"
android:layout_marginTop="15dip"
android:layout_marginLeft="15dip">
</ImageView>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo"
android:layout_centerInParent="true">
</ImageView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/dev"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="5dip"
android:layout_marginBottom="35dip">
</ImageView>
</RelativeLayout>
</LinearLayout>
3、在ec打開名爲MainActivity的Activity源代碼文件進行編輯,onCreate部分代碼以下:
view plaincopy to clipboardprint?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
而後運行項目能夠在模擬器中顯示,上面的幾個圖片都按照設計的位置和效果進行顯示只是整個頁面的背景仍是黑色的,接下來就是背景部分的顯示實現,因爲爲了實現橫豎屏切換顯示,背景圖的顯示採用代碼進行控制顯示,首先用以下方法獲取當前手機是橫屏仍是豎屏:
view plaincopy to clipboardprint?
//獲取屏幕方向
public static int ScreenOrient(Activity activity)
{
int orient = activity.getRequestedOrientation();
if(orient != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE && orient != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
//寬>高爲橫屏,反正爲豎屏
WindowManager windowManager = activity.getWindowManager();
Display display = windowManager.getDefaultDisplay();
int screenWidth = display.getWidth();
int screenHeight = display.getHeight();
orient = screenWidth < screenHeight ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
}
return orient;
}
//獲取屏幕方向
public static int ScreenOrient(Activity activity)
{
int orient = activity.getRequestedOrientation();
if(orient != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE && orient != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
//寬>高爲橫屏,反正爲豎屏
WindowManager windowManager = activity.getWindowManager();
Display display = windowManager.getDefaultDisplay();
int screenWidth = display.getWidth();
int screenHeight = display.getHeight();
orient = screenWidth < screenHeight ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
}
return orient;
}
而後編寫一個名爲AutoBackground的公共方法用來實現屏幕背景的自動切換,後面的幾乎每個功能頁面都須要用到這個方法
view plaincopy to clipboardprint?
public static void AutoBackground(Activity activity,View view,int Background_v, int Background_h)
{
int orient=ScreenOrient(activity);
if (orient == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { //縱向
view.setBackgroundResource(Background_v);
}else{ //橫向
view.setBackgroundResource(Background_h);
}
}
public static void AutoBackground(Activity activity,View view,int Background_v, int Background_h)
{
int orient=ScreenOrient(activity);
if (orient == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { //縱向
view.setBackgroundResource(Background_v);
}else{ //橫向
view.setBackgroundResource(Background_h);
}
}
完成上述兩方法後在 MainActivity的onCreate方法中調用AutoBackground方法進行屏幕自動切換:
view plaincopy to clipboardprint?
LinearLayout layout=(LinearLayout)findViewById(R.id.layout);
//背景自動適應
AndroidHelper.AutoBackground(this, layout, R.drawable.bg_v, R.drawable.bg_h);
LinearLayout layout=(LinearLayout)findViewById(R.id.layout);
//背景自動適應
AndroidHelper.AutoBackground(this, layout, R.drawable.bg_v, R.drawable.bg_h);
到此完成了載入頁面的UI部分的實現,測試運行模擬器中查看效果,基本上跟最上面的設計效果圖相符,測試效果圖以下:
6 天前 上傳
下載附件 (94.6 KB)
經過上一篇文章(android開發個人新浪微博客戶端-載入頁面UI篇(1.1))已經完成了載入頁面的UI部分的實現,效果如上圖,接下來在上面的基礎上完成載入頁面的功能代碼。
6 天前 上傳
下載附件 (94.6 KB) 首先說明一下新浪微博提供了OAuth和Base OAuth兩種認證方式(若是不知道什麼是OAuth和Base OAuth請本身google一下惡補,同時接下來的2篇隨筆也會對這方面進行詳細的說明以及具體實現),本項目是採用OAuth認證方式,採用這種方式就須要有用戶的新浪UserID、Access Token、Access Secret這3樣東西才能自由便利的調用新浪的開放接口,本項目是這樣作的當用戶第一次使用軟件時進行受權認證獲取這3樣東西的時候存儲到sqlite庫中以便用戶下次使用時不須要從新進行繁瑣的受權認證操做直接從sqlite庫中讀取出來便可,因爲這樣的需求載入頁面的功能設定是這樣:當用戶打開軟件顯示載入頁面時開始檢查sqlite庫中是否已經保存有用戶的新浪微博的UserID號、Access Token、Access Secret的記錄,若是一條記錄都沒有那就說明用戶是第一次使用本軟件那麼跳到認證受權頁面進行受權認證操做(認證受權功能在接下來的兩篇中進行實現講解)獲取這3個值保存到sqlite庫中,若是已經包括了記錄,那麼讀取這些記錄的UserID號、Access Token、Access Secret值而後根據這3個值調用新浪的api接口獲取這些記錄對應的用戶暱稱和用戶頭像圖標等信息。
上面功能設定中涉及到sqlite數據庫的建立、數據表的建立、數據記錄的添加、數據記錄的讀取等操做,這裏新建名爲SqliteHelper.java類文件提供sqlite數據表的建立、更新等,代碼以下:
view plaincopy to clipboardprint?
public class SqliteHelper extends SQLiteOpenHelper{
//用來保存
UserID、Access Token、Access Secret
的表名
public static final String TB_NAME="users";
public SqliteHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
//建立表
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS "+
TB_NAME+"("+
UserInfo.ID+" integer primary key,"+
UserInfo.USERID+" varchar,"+
UserInfo.TOKEN+" varchar,"+
UserInfo.TOKENSECRET+" varchar,"+
UserInfo.USERNAME+" varchar,"+
UserInfo.USERICON+" blob"+
")"
);
Log.e("Database","onCreate");
}
//更新表
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TB_NAME);
onCreate(db);
Log.e("Database","onUpgrade");
}
//更新列
public void updateColumn(SQLiteDatabase db, String oldColumn, String newColumn, String typeColumn){
try{
db.execSQL("ALTER TABLE " +
TB_NAME + " CHANGE " +
oldColumn + " "+ newColumn +
" " + typeColumn
);
}catch(Exception e){
e.printStackTrace();
}
}
}
public class SqliteHelper extends SQLiteOpenHelper{
//用來保存
UserID、Access Token、Access Secret
的表名
public static final String TB_NAME="users";
public SqliteHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
//建立表
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS "+
TB_NAME+"("+
UserInfo.ID+" integer primary key,"+
UserInfo.USERID+" varchar,"+
UserInfo.TOKEN+" varchar,"+
UserInfo.TOKENSECRET+" varchar,"+
UserInfo.USERNAME+" varchar,"+
UserInfo.USERICON+" blob"+
")"
);
Log.e("Database","onCreate");
}
//更新表
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TB_NAME);
onCreate(db);
Log.e("Database","onUpgrade");
}
//更新列
public void updateColumn(SQLiteDatabase db, String oldColumn, String newColumn, String typeColumn){
try{
db.execSQL("ALTER TABLE " +
TB_NAME + " CHANGE " +
oldColumn + " "+ newColumn +
" " + typeColumn
);
}catch(Exception e){
e.printStackTrace();
}
}
}
接下來新建名爲DataHelper.java類文件實現用戶記錄的建立、更新、刪除等,代碼以下
view plaincopy to clipboardprint?
public class DataHelper {
//數據庫名稱
private static String DB_NAME = "mysinaweibo.db";
//數據庫版本
private static int DB_VERSION = 2;
private SQLiteDatabase db;
private SqliteHelper dbHelper;
public DataHelper(Context context){
dbHelper=new SqliteHelper(context,DB_NAME, null, DB_VERSION);
db= dbHelper.getWritableDatabase();
}
public void Close()
{
db.close();
dbHelper.close();
}
//獲取users表中的UserID、Access Token、Access Secret的記錄
public List<UserInfo> GetUserList(Boolean isSimple)
{
List<UserInfo> userList = new ArrayList<UserInfo>();
Cursor cursor=db.query(SqliteHelper.TB_NAME, null, null, null, null, null, UserInfo.ID+" DESC");
cursor.moveToFirst();
while(!cursor.isAfterLast()&& (cursor.getString(1)!=null)){
UserInfo user=new UserInfo();
user.setId(cursor.getString(0));
user.setUserId(cursor.getString(1));
user.setToken(cursor.getString(2));
user.setTokenSecret(cursor.getString(3));
if(!isSimple){
user.setUserName(cursor.getString(4));
ByteArrayInputStream stream = new ByteArrayInputStream(cursor.getBlob(5));
Drawable icon= Drawable.createFromStream(stream, "image");
user.setUserIcon(icon);
}
userList.add(user);
cursor.moveToNext();
}
cursor.close();
return userList;
}
//判斷users表中的是否包含某個UserID的記錄
public Boolean HaveUserInfo(String UserId)
{
Boolean b=false;
Cursor cursor=db.query(SqliteHelper.TB_NAME, null, UserInfo.USERID + "=" + UserId, null, null, null,null);
b=cursor.moveToFirst();
Log.e("HaveUserInfo",b.toString());
cursor.close();
return b;
}
//更新users表的記錄,根據UserId更新用戶暱稱和用戶圖標
public int UpdateUserInfo(String userName,Bitmap userIcon,String UserId)
{
ContentValues values = new ContentValues();
values.put(UserInfo.USERNAME, userName);
// BLOB類型
final ByteArrayOutputStream os = new ByteArrayOutputStream();
// 將Bitmap壓縮成PNG編碼,質量爲100%存儲
userIcon.compress(Bitmap.CompressFormat.PNG, 100, os);
// 構造SQLite的Content對象,這裏也可使用raw
values.put(UserInfo.USERICON, os.toByteArray());
int id= db.update(SqliteHelper.TB_NAME, values, UserInfo.USERID + "=" + UserId, null);
Log.e("UpdateUserInfo2",id+"");
return id;
}
//更新users表的記錄
public int UpdateUserInfo(UserInfo user)
{
ContentValues values = new ContentValues();
values.put(UserInfo.USERID, user.getUserId());
values.put(UserInfo.TOKEN, user.getToken());
values.put(UserInfo.TOKENSECRET, user.getTokenSecret());
int id= db.update(SqliteHelper.TB_NAME, values, UserInfo.USERID + "=" + user.getUserId(), null);
Log.e("UpdateUserInfo",id+"");
return id;
}
//添加users表的記錄
public Long SaveUserInfo(UserInfo user)
{
ContentValues values = new ContentValues();
values.put(UserInfo.USERID, user.getUserId());
values.put(UserInfo.TOKEN, user.getToken());
values.put(UserInfo.TOKENSECRET, user.getTokenSecret());
Long uid = db.insert(SqliteHelper.TB_NAME, UserInfo.ID, values);
Log.e("SaveUserInfo",uid+"");
return uid;
}
//刪除users表的記錄
public int DelUserInfo(String UserId){
int id= db.delete(SqliteHelper.TB_NAME, UserInfo.USERID +"="+UserId, null);
Log.e("DelUserInfo",id+"");
return id;
}
}
public class DataHelper {
//數據庫名稱
private static String DB_NAME = "mysinaweibo.db";
//數據庫版本
private static int DB_VERSION = 2;
private SQLiteDatabase db;
private SqliteHelper dbHelper;
public DataHelper(Context context){
dbHelper=new SqliteHelper(context,DB_NAME, null, DB_VERSION);
db= dbHelper.getWritableDatabase();
}
public void Close()
{
db.close();
dbHelper.close();
}
//獲取users表中的UserID、Access Token、Access Secret的記錄
public List<UserInfo> GetUserList(Boolean isSimple)
{
List<UserInfo> userList = new ArrayList<UserInfo>();
Cursor cursor=db.query(SqliteHelper.TB_NAME, null, null, null, null, null, UserInfo.ID+" DESC");
cursor.moveToFirst();
while(!cursor.isAfterLast()&& (cursor.getString(1)!=null)){
UserInfo user=new UserInfo();
user.setId(cursor.getString(0));
user.setUserId(cursor.getString(1));
user.setToken(cursor.getString(2));
user.setTokenSecret(cursor.getString(3));
if(!isSimple){
user.setUserName(cursor.getString(4));
ByteArrayInputStream stream = new ByteArrayInputStream(cursor.getBlob(5));
Drawable icon= Drawable.createFromStream(stream, "image");
user.setUserIcon(icon);
}
userList.add(user);
cursor.moveToNext();
}
cursor.close();
return userList;
}
//判斷users表中的是否包含某個UserID的記錄
public Boolean HaveUserInfo(String UserId)
{
Boolean b=false;
Cursor cursor=db.query(SqliteHelper.TB_NAME, null, UserInfo.USERID + "=" + UserId, null, null, null,null);
b=cursor.moveToFirst();
Log.e("HaveUserInfo",b.toString());
cursor.close();
return b;
}
//更新users表的記錄,根據UserId更新用戶暱稱和用戶圖標
public int UpdateUserInfo(String userName,Bitmap userIcon,String UserId)
{
ContentValues values = new ContentValues();
values.put(UserInfo.USERNAME, userName);
// BLOB類型
final ByteArrayOutputStream os = new ByteArrayOutputStream();
// 將Bitmap壓縮成PNG編碼,質量爲100%存儲
userIcon.compress(Bitmap.CompressFormat.PNG, 100, os);
// 構造SQLite的Content對象,這裏也可使用raw
values.put(UserInfo.USERICON, os.toByteArray());
int id= db.update(SqliteHelper.TB_NAME, values, UserInfo.USERID + "=" + UserId, null);
Log.e("UpdateUserInfo2",id+"");
return id;
}
//更新users表的記錄
public int UpdateUserInfo(UserInfo user)
{
ContentValues values = new ContentValues();
values.put(UserInfo.USERID, user.getUserId());
values.put(UserInfo.TOKEN, user.getToken());
values.put(UserInfo.TOKENSECRET, user.getTokenSecret());
int id= db.update(SqliteHelper.TB_NAME, values, UserInfo.USERID + "=" + user.getUserId(), null);
Log.e("UpdateUserInfo",id+"");
return id;
}
//添加users表的記錄
public Long SaveUserInfo(UserInfo user)
{
ContentValues values = new ContentValues();
values.put(UserInfo.USERID, user.getUserId());
values.put(UserInfo.TOKEN, user.getToken());
values.put(UserInfo.TOKENSECRET, user.getTokenSecret());
Long uid = db.insert(SqliteHelper.TB_NAME, UserInfo.ID, values);
Log.e("SaveUserInfo",uid+"");
return uid;
}
//刪除users表的記錄
public int DelUserInfo(String UserId){
int id= db.delete(SqliteHelper.TB_NAME, UserInfo.USERID +"="+UserId, null);
Log.e("DelUserInfo",id+"");
return id;
}
}
完成上面的代碼後,咱們須要在載入頁面中調用上面的方法實現sqlite庫中是否已經保存有用戶的新浪微博的UserID號、Access Token、Access Secret的記錄的功能在MainActivity的onCreate方法添加代碼:
view plaincopy to clipboardprint?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
......
//獲取帳號列表
dbHelper=new DataHelper(this);
List<UserInfo> userList= dbHelper.GetUserList(true);
if(userList.isEmpty())//若是爲空說明第一次使用跳到AuthorizeActivity頁面進行OAuth認證
{
Intent intent = new Intent();
intent.setClass(MainActivity.this, AuthorizeActivity.class);
startActivity(intent);
}
else//若是不爲空讀取這些記錄的UserID號、Access Token、Access Secret值
//而後根據這3個值調用新浪的api接口獲取這些記錄對應的用戶暱稱和用戶頭像圖標等信息。
{
for(UserInfo user:userList){
......
}
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
......
//獲取帳號列表
dbHelper=new DataHelper(this);
List<UserInfo> userList= dbHelper.GetUserList(true);
if(userList.isEmpty())//若是爲空說明第一次使用跳到AuthorizeActivity頁面進行OAuth認證
{
Intent intent = new Intent();
intent.setClass(MainActivity.this, AuthorizeActivity.class);
startActivity(intent);
}
else//若是不爲空讀取這些記錄的UserID號、Access Token、Access Secret值
//而後根據這3個值調用新浪的api接口獲取這些記錄對應的用戶暱稱和用戶頭像圖標等信息。
{
for(UserInfo user:userList){
......
}
}
}
本篇說說關於OAuth受權認證的事情,新浪開放api都必須在這個基礎上才能調用,因此有必要專門來說講,前面的文章中已經提到過關於新浪微博提供了OAuth和Base OAuth兩種認證方式,而且本項目採用OAuth認證方式,至於爲何採用這個OAuth認證而不採用Base OAuth認證緣由很簡單,自從Twitter只支持OAuth認證方式以來,各大應用都紛紛轉向OAuth認證方式,而新浪微博的開放平臺也將在近日中止Base OAuth的認證方式。
6 天前 上傳
下載附件 (30.41 KB) OAuth的基本概念,OAUTH協議爲用戶資源的受權提供了一個安全的、開放而又簡易的標準。與以往的受權方式不一樣之處是OAUTH的受權不會使第三方觸及到用戶的賬號信息(如用戶名與密碼),即第三方無需使用用戶的用戶名與密碼就能夠申請得到該用戶資源的受權,所以OAUTH是安全的。一樣新浪微博提供OAuth認證也是爲了保證用戶帳號和密碼的安全,在這裏經過OAuth創建普通新浪微博用戶、客戶端程序(咱們正在開發的這個android客戶端程序)、新浪微博三者之間的相互信任關係,讓客戶端程序(咱們正在開發的這個android客戶端程序)不須要知道用戶的帳號和密碼也能瀏覽、發佈微博,這樣有效的保護了用戶帳號的安全性不須要把帳號密碼透露給客戶端程序又達到了經過客戶端程序寫微博看微博目的。這個是OAuth的做用。
結合新浪微博的OAuth認證來講說具體的功能實現,首先羅列一下關鍵字組,下面四組關鍵字跟咱們接下來OAuth認證有很是大的關係。
第一組:(App Key和App Secret),這組參數就是本系列文本第一篇提到的建一個新的應用獲取App Key和App Secret。
第二組:(Request Token和Request Secret)
第三組:(oauth_verifier)
第四組:(user_id、Access Token和Access Secret)
新浪微博的OAuth認證過程,當用戶第一次使用本客戶端軟件時,客戶端程序用第一組做爲參數向新浪微博發起請求,而後新浪微博通過驗證後返回第二組參數給客戶端軟件同時表示新浪微博信任本客戶端軟件,當客戶端軟件獲取第二組參數時做爲參數引導用戶瀏覽器跳至新浪微博的受權頁面,而後用戶在新浪的這個受權頁面裏輸入本身的微博帳號和密碼進行受權,完成受權後根據客戶端設定的回調地址把第三組參數返回給客戶端軟件並表示用戶也信任本客戶端軟件,接下客戶端軟件把第二組參數和第三組參數做爲參數再次向新浪微博發起請求,而後新浪微博返回第四組參數給客戶端軟件,第四組參數須要好好的保存起來這個就是用來代替用戶的新浪帳號和密碼用的,在後面調用api時都須要。從這個過程來看用戶只是在新浪微博的認證網頁輸入過帳戶和密碼並無在客戶端軟件裏輸入過帳戶和密碼,客戶端軟件只保存了第四組數據並無保存用戶的帳戶和密碼,這樣有效的避免了帳戶和密碼透露給新浪微博以外的第三方應用程序,保證 了安全性。
本項目用爲了方便開發採用了oauth-signpost開源項目進行OAuth認證開發,新建OAuth.java類文件對OA進行簡單的封裝,OAuth類主要有RequestAccessToken、GetAccessToken、SignRequest三個方法,第一個方法RequestAccessToken就是上面過程當中用來獲取第三組參數用的,GetAccessToken方法是用來獲取第四組參數用,SignRequest方法是用來調用api用。因爲採用了oauth-signpost開源項目簡單了不少。具體代碼以下:
view plaincopy to clipboardprint?
public class OAuth {
private CommonsHttpOAuthConsumer httpOauthConsumer;
private OAuthProvider httpOauthprovider;
public String consumerKey;
public String consumerSecret;
public OAuth()
{
// 第一組:(App Key和App Secret)
// 這組參數就是本系列文本第一篇提到的建一個新的應用獲取App Key和App Secret。
this("3315495489","e2731e7grf592c0fd7fea32406f86e1b");
}
public OAuth(String consumerKey,String consumerSecret)
{
this.consumerKey=consumerKey;
this.consumerSecret=consumerSecret;
}
public Boolean RequestAccessToken(Activity activity,String callBackUrl){
Boolean ret=false;
try{
httpOauthConsumer = new CommonsHttpOAuthConsumer(consumerKey,consumerSecret);
httpOauthprovider = new DefaultOAuthProvider("http://api.t.sina.com.cn/oauth/request_token","http://api.t.sina.com.cn/oauth/access_token","http://api.t.sina.com.cn/oauth/authorize");
String authUrl = httpOauthprovider.retrieveRequestToken(httpOauthConsumer, callBackUrl);
activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
ret=true;
}catch(Exception e){
}
return ret;
}
public UserInfo GetAccessToken(Intent intent){
UserInfo user=null;
Uri uri = intent.getData();
String verifier = uri.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);
try {
httpOauthprovider.setOAuth10a(true);
httpOauthprovider.retrieveAccessToken(httpOauthConsumer,verifier);
} catch (OAuthMessageSignerException ex) {
ex.printStackTrace();
} catch (OAuthNotAuthorizedException ex) {
ex.printStackTrace();
} catch (OAuthExpectationFailedException ex) {
ex.printStackTrace();
} catch (OAuthCommunicationException ex) {
ex.printStackTrace();
}
SortedSet<String> user_id= httpOauthprovider.getResponseParameters().get("user_id");
String userId=user_id.first();
String userKey = httpOauthConsumer.getToken();
String userSecret = httpOauthConsumer.getTokenSecret();
user=new UserInfo();
user.setUserId(userId);
user.setToken(userKey);
user.setTokenSecret(userSecret);
return user;
}
public HttpResponse SignRequest(String token,String tokenSecret,String url,List params)
{
HttpPost post = new HttpPost(url);
//HttpClient httpClient = null;
try{
post.setEntity(new UrlEncodedFormEntity(params,HTTP.UTF_8));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//關閉Expect:100-Continue握手
//100-Continue握手需謹慎使用,由於遇到不支持HTTP/1.1協議的服務器或者代理時會引發問題
post.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
return SignRequest(token,tokenSecret,post);
}
public HttpResponse SignRequest(String token,String tokenSecret,HttpPost post){
httpOauthConsumer = new CommonsHttpOAuthConsumer(consumerKey,consumerSecret);
httpOauthConsumer.setTokenWithSecret(token,tokenSecret);
HttpResponse response = null;
try {
httpOauthConsumer.sign(post);
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
//取得HTTP response
try {
response = new DefaultHttpClient().execute(post);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
}
public class OAuth {
private CommonsHttpOAuthConsumer httpOauthConsumer;
private OAuthProvider httpOauthprovider;
public String consumerKey;
public String consumerSecret;
public OAuth()
{
// 第一組:(App Key和App Secret)
// 這組參數就是本系列文本第一篇提到的建一個新的應用獲取App Key和App Secret。
this("3315495489","e2731e7grf592c0fd7fea32406f86e1b");
}
public OAuth(String consumerKey,String consumerSecret)
{
this.consumerKey=consumerKey;
this.consumerSecret=consumerSecret;
}
public Boolean RequestAccessToken(Activity activity,String callBackUrl){
Boolean ret=false;
try{
httpOauthConsumer = new CommonsHttpOAuthConsumer(consumerKey,consumerSecret);
httpOauthprovider = new DefaultOAuthProvider("http://api.t.sina.com.cn/oauth/request_token","http://api.t.sina.com.cn/oauth/access_token","http://api.t.sina.com.cn/oauth/authorize");
String authUrl = httpOauthprovider.retrieveRequestToken(httpOauthConsumer, callBackUrl);
activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
ret=true;
}catch(Exception e){
}
return ret;
}
public UserInfo GetAccessToken(Intent intent){
UserInfo user=null;
Uri uri = intent.getData();
String verifier = uri.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);
try {
httpOauthprovider.setOAuth10a(true);
httpOauthprovider.retrieveAccessToken(httpOauthConsumer,verifier);
} catch (OAuthMessageSignerException ex) {
ex.printStackTrace();
} catch (OAuthNotAuthorizedException ex) {
ex.printStackTrace();
} catch (OAuthExpectationFailedException ex) {
ex.printStackTrace();
} catch (OAuthCommunicationException ex) {
ex.printStackTrace();
}
SortedSet<String> user_id= httpOauthprovider.getResponseParameters().get("user_id");
String userId=user_id.first();
String userKey = httpOauthConsumer.getToken();
String userSecret = httpOauthConsumer.getTokenSecret();
user=new UserInfo();
user.setUserId(userId);
user.setToken(userKey);
user.setTokenSecret(userSecret);
return user;
}
public HttpResponse SignRequest(String token,String tokenSecret,String url,List params)
{
HttpPost post = new HttpPost(url);
//HttpClient httpClient = null;
try{
post.setEntity(new UrlEncodedFormEntity(params,HTTP.UTF_8));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//關閉Expect:100-Continue握手
//100-Continue握手需謹慎使用,由於遇到不支持HTTP/1.1協議的服務器或者代理時會引發問題
post.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
return SignRequest(token,tokenSecret,post);
}
public HttpResponse SignRequest(String token,String tokenSecret,HttpPost post){
httpOauthConsumer = new CommonsHttpOAuthConsumer(consumerKey,consumerSecret);
httpOauthConsumer.setTokenWithSecret(token,tokenSecret);
HttpResponse response = null;
try {
httpOauthConsumer.sign(post);
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
//取得HTTP response
try {
response = new DefaultHttpClient().execute(post);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
}
這樣就完成了OAuth功能類的開發,後面都會用到這個類相關的方法。本篇到這裏就算是完結請繼續關注後面的文章。
上一篇講了講OAuth受權認證的事情,大概的介紹了OAuth的原理,而且完成了一個OAuth.java的類庫,提供了幾個OAuth認證必要的方法,本篇開始具體講本項目的用戶受權功能,用戶受權頁面是當用戶第一次使用本軟件的時候自動從載入頁面跳轉過來的顯示的頁面,涉及OAuth認證相關都是在上一篇的OAuth.java的類基礎上開發。用戶受權頁面分爲UI篇和功能篇兩篇,本篇先來說講UI的實現,此次就不貼PS的效果圖了直接貼實現後的功能截圖以下:
6 天前 上傳
下載附件 (84.47 KB) 看上面的圖,其實這個頁面的UI實現不復雜,首先是背景部分的實現這個參考 android開發個人新浪微博客戶端-載入頁面UI篇(1.1),重點來說講這個半透明的彈出對話框窗口是如何實現的,首先新建名爲AuthorizeActivity.java的Activity,而且在AndroidManifest.xml文件中添加這個Activity,這樣這個Activity才能被使用,接下來爲這個Activity新建名爲authorize.xml的Layout,這個Layout很簡單隻負責logo小圖標顯示,背景部分和透明窗口都是有代碼來實現,因此很是簡單參考 android開發個人新浪微博客戶端-載入頁面UI篇(1.1)。
完成Layout創建後在AuthorizeActivity的onCreate方法添加以下代碼,設置authorize.xml爲AuthorizeActivity的頁面Layout:
view plaincopy to clipboardprint?
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.authorize);
.......
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.authorize);
.......
}
接下來是本文的重點部分,半透明彈窗用Dialog控件進行實現,首先爲這個半透明彈窗新建一個名爲dialog.xml的Layout,這個Layout主要是對4個元素進行佈局,如圖所示分別爲i小圖標、信息提示、中間文字、開始按鈕,首先用LinearLayout對i小圖標和信息提示進行水平佈局,中間文字以一個TextView跟在下面,對於開始按鈕是用RelativeLayout進行底部對齊顯示。具體代碼以下:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dip">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/info_icon">
</ImageView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="信息提示"
android:textSize="13px"
android:textColor="#219ac6"
android:layout_marginLeft="5dip">
</TextView>
</LinearLayout>
<TextView
android:id="@+id/text_info"
android:layout_marginTop="6px"
android:layout_width="200px"
android:layout_height="wrap_content"
android:textColor="#686767"
android:textSize="14px"
android:text="第一次使用須要輸入您的新浪微博帳號和密碼進行登陸受權">
</TextView>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="40px">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true">
<ImageButton
android:id="@+id/btn_start"
android:layout_width="80px"
android:layout_height="31px"
android:src="@drawable/btn_start_selector">
</ImageButton>
<ImageButton
android:id="@+id/btn_cancel"
android:layout_width="80px"
android:layout_height="31px"
android:layout_marginLeft="8px"
android:src="@drawable/btn_cancel_selector">
</ImageButton>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dip">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/info_icon">
</ImageView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="信息提示"
android:textSize="13px"
android:textColor="#219ac6"
android:layout_marginLeft="5dip">
</TextView>
</LinearLayout>
<TextView
android:id="@+id/text_info"
android:layout_marginTop="6px"
android:layout_width="200px"
android:layout_height="wrap_content"
android:textColor="#686767"
android:textSize="14px"
android:text="第一次使用須要輸入您的新浪微博帳號和密碼進行登陸受權">
</TextView>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="40px">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true">
<ImageButton
android:id="@+id/btn_start"
android:layout_width="80px"
android:layout_height="31px"
android:src="@drawable/btn_start_selector">
</ImageButton>
<ImageButton
android:id="@+id/btn_cancel"
android:layout_width="80px"
android:layout_height="31px"
android:layout_marginLeft="8px"
android:src="@drawable/btn_cancel_selector">
</ImageButton>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
完成了半透明彈窗的Layout定義接下來咱們要作的就是爲它寫一個自定義樣式來實現咱們想要的顯示效果,首先咱們需準備一個圓角的半透明png圖片名爲dia_bg.png而且添加到drawable中,接下來再res/values文件夾新建名爲 dialogStyle.xml的resources樣式文件,具體代碼以下:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<resources>
<mce:style name="dialog" parent="@android:style/Theme.Dialog"><!--
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@drawable/dia_bg</item>
<item name="android:backgroundDimEnabled">false</item>
--></mce:style><style name="dialog" parent="@android:style/Theme.Dialog" mce_bogus="1"><item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@drawable/dia_bg</item>
<item name="android:backgroundDimEnabled">false</item></style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<mce:style name="dialog" parent="@android:style/Theme.Dialog"><!--
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@drawable/dia_bg</item>
<item name="android:backgroundDimEnabled">false</item>
--></mce:style><style name="dialog" parent="@android:style/Theme.Dialog" mce_bogus="1"><item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@drawable/dia_bg</item>
<item name="android:backgroundDimEnabled">false</item></style>
</resources>
這個樣式文件的說明以下
parent="@android:style/Theme.Dialog" :在系統Dialog樣式基礎上,至關於繼承系統樣式
<item name="android:windowFrame">@null</item> :Dialog的windowFrame框爲無
<item name="android:windowIsFloating">true</item>:是否浮如今activity之上
<item name="android:windowIsTranslucent">false</item>:是否半透明
<item name="android:windowNoTitle">true</item>:是否顯示title
<item name="android:windowBackground">@drawable/dia_bg</item>:設置dialog的背景
<item name="android:backgroundDimEnabled">false</item>: 背景是否模糊顯示
接下來寫java代碼把這個半透明彈窗顯示出來,在AuthorizeActivity的onCreate方法添加以下代碼:
view plaincopy to clipboardprint?
......
View diaView=View.inflate(this, R.layout.dialog, null);
dialog=new Dialog(AuthorizeActivity.this,R.style.dialog);
dialog.setContentView(diaView);
dialog.show();
......
......
View diaView=View.inflate(this, R.layout.dialog, null);
dialog=new Dialog(AuthorizeActivity.this,R.style.dialog);
dialog.setContentView(diaView);
dialog.show();
......
最後運行查看效果,到這裏咱們的任務已經完成了。請關注下一篇功能篇。
android開發個人新浪微博客戶端-用戶受權頁面功能篇(3.2)
6 天前 上傳
下載附件 (30.41 KB)
6 天前 上傳
下載附件 (84.47 KB)
在上一篇實現了用戶受權頁面的UI,如上圖,接下來要作的就是在這個基礎上完成功能部分真正實現用戶的受權認證,這一篇是android開發個人新浪微博客戶端-OAuth篇(2.1)的具體應用篇原理就很少解釋了不懂的看OAuth篇便可。認證過程從點擊開始按鈕而後跳轉到新浪的受權頁面,接着用戶在新浪的頁面裏輸入本身的帳戶和密碼肯定後返回用戶受權頁面。首先給開始按鈕添加點擊事件代碼,代碼中主要是調用咱們前面android開發個人新浪微博客戶端-OAuth篇(2.1)完成的OAuth類的RequestAccessToken方法用來獲取oauth_verifier,具體代碼以下:
view plaincopy to clipboardprint?
ImageButton stratBtn=(ImageButton)diaView.findViewById(R.id.btn_start);
stratBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
auth=new OAuth();
auth.RequestAccessToken(AuthorizeActivity.this, CallBackUrl);
}
});
ImageButton stratBtn=(ImageButton)diaView.findViewById(R.id.btn_start);
stratBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
auth=new OAuth();
auth.RequestAccessToken(AuthorizeActivity.this, CallBackUrl);
}
});
上面的代碼中重點來講明一下 RequestAccessToken方法的第二參數CallBackUrl,這個參數是用戶在新浪的頁面中輸入帳戶密碼後完成認證後返回的地址,我這裏是這樣設置的CallBackUrl = "myapp://AuthorizeActivity",在AndroidManifest.xml中配置給AuthorizeActivity添加以下配置把myapp://AuthorizeActivity指向到AuthorizeActivity,這樣當頁面返回到AuthorizeActivity中就能夠獲取到傳過來的oauth_verifier參數。
view plaincopy to clipboardprint?
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="AuthorizeActivity" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="AuthorizeActivity" />
</intent-filter>
再AuthorizeActivity若是來接收返回的oauth_verifier參數呢?接下來在AuthorizeActivity添加以下方法:
view plaincopy to clipboardprint?
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//在這裏處理獲取返回的oauth_verifier參數
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//在這裏處理獲取返回的oauth_verifier參數
}
關於onNewIntent的說明是這樣的,onCreate是用來建立一個Activity也就是建立一個窗體,但一個Activty處於任務棧的頂端,若再次調用startActivity去建立它,則不會再次建立。若你想利用已有的Acivity去處理別的Intent時,你就能夠利用onNewIntent來處理。在onNewIntent裏面就會得到新的Intent,在這裏AuthorizeActivity是屬於已有的Acivity,因此須要onNewIntent來處理接收返回的參數,獲取oauth_verifier參數後OAuth尚未結束從android開發個人新浪微博客戶端-OAuth篇(2.1)描述來看還須要進行根據這個參數繼續向新浪微博請求獲取User_id、Access Token和Access Secret,在這裏我把這些操做所有寫在了GetAccessToken方法中。在onNewIntent添加以下代碼:
view plaincopy to clipboardprint?
UserInfo user= auth.GetAccessToken(intent);
if(user!=null){
DataHelper helper=new DataHelper(this);
String uid=user.getUserId();
if(helper.HaveUserInfo(uid))
{
helper.UpdateUserInfo(user);
Log.e("UserInfo", "update");
}else
{
helper.SaveUserInfo(user);
Log.e("UserInfo", "add");
}
}
UserInfo user= auth.GetAccessToken(intent);
if(user!=null){
DataHelper helper=new DataHelper(this);
String uid=user.getUserId();
if(helper.HaveUserInfo(uid))
{
helper.UpdateUserInfo(user);
Log.e("UserInfo", "update");
}else
{
helper.SaveUserInfo(user);
Log.e("UserInfo", "add");
}
}
經過上面的代碼完成了User_id、Access Token和Access Secret 獲取而且保存到了sqlite庫中,這樣就完成了用戶的OAuth認證,當須要調用新浪的api時只須要去sqlite庫中找該用戶的User_id、Access Token和Access Secret 便可。到這裏本篇就結束了,請關注下一篇。
android開發個人新浪微博客戶端-登陸頁面UI篇(4.1)
6 天前 上傳
下載附件 (83.17 KB)
6 天前 上傳
下載附件 (85.15 KB)
首先回顧一下功能流程當用戶開啓軟件顯示載入頁面時程序首先去sqlite庫查詢是否已經保存有用戶的新浪微博的UserID號、Access Token、Access Secret的記錄若是沒有一條記錄那麼跳轉到用戶受權功能頁面,這個已經由上面兩篇文章實現了,若是有記錄那麼頁面跳轉到用戶登陸頁面,也就是本篇以及下篇要實現的功能,本篇講UI的實現,本項目支持多微博帳號了,也就是用戶能夠設置多個微博帳號,登陸的時候選擇其中的一個登陸,具體效果如上圖,新建名LoginActivity.java的Activity而且在AndroidManifest.xml中進行相應配置,這個頁面就是咱們要實現的用戶登陸頁面。
看上面的效果,首先頁面分3部分實現,背景部分、底部菜單部分、用戶選擇以及頭像顯示部分,首先在res/layout的目錄下新建名爲login.xml的layout,而後根據頁面顯示要求編寫以下的佈局控制:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo_s"
android:layout_marginTop="5dip"
android:layout_marginLeft="5dip">
</ImageView>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
android:id="@+id/iconBtn"
android:layout_width="90px"
android:layout_height="80px"
android:background="@drawable/icon_selector"
android:layout_above="@+id/selectLayout"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dip">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
</ImageView>
</RelativeLayout>
<RelativeLayout
android:id="@+id/selectLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<EditText
android:id="@+id/iconSelect"
android:layout_width="200px"
android:layout_height="wrap_content"
android:maxLength="10"
android:paddingLeft="20px"
android:editable="false"
android:enabled="false"
android:textSize="13px"
android:background="@drawable/input_over" >
</EditText>
<ImageButton
android:id="@+id/iconSelectBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="1.0dip"
android:layout_alignTop="@+id/iconSelect"
android:layout_alignRight="@+id/iconSelect"
android:layout_alignBottom="@+id/iconSelect"
android:background="@drawable/more_selector" >
</ImageButton>
<ImageButton
android:id="@+id/login"
android:layout_width="40px"
android:layout_height="40px"
android:layout_marginLeft="5dip"
android:layout_alignTop="@+id/iconSelectBtn"
android:layout_toRightOf="@+id/iconSelectBtn"
android:layout_alignBottom="@+id/iconSelectBtn"
android:background="@drawable/btn_in_selector" >
</ImageButton>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="44dip"
android:layout_alignParentBottom="true"
android:background="#BB768e95">
<LinearLayout
android:id="@+id/addLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentLeft="true"
android:gravity="center"
android:layout_marginTop="3px">
<ImageButton
android:id="@+id/addIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/add_selector">
</ImageButton>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="12px"
android:text="添加帳號">
</TextView>
</LinearLayout>
<LinearLayout
android:id="@+id/exitLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true"
android:gravity="center"
android:layout_marginTop="3px">
<ImageButton
android:id="@+id/exitIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/exit_selector">
</ImageButton>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="12px"
android:text="退出軟件">
</TextView>
</LinearLayout>
<LinearLayout
android:id="@+id/delLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentRight="true"
android:gravity="center"
android:layout_marginTop="3px">
<ImageButton
android:id="@+id/delIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/del_selector">
</ImageButton>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="12px"
android:text="刪除帳號">
</TextView>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo_s"
android:layout_marginTop="5dip"
android:layout_marginLeft="5dip">
</ImageView>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
android:id="@+id/iconBtn"
android:layout_width="90px"
android:layout_height="80px"
android:background="@drawable/icon_selector"
android:layout_above="@+id/selectLayout"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dip">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
</ImageView>
</RelativeLayout>
<RelativeLayout
android:id="@+id/selectLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<EditText
android:id="@+id/iconSelect"
android:layout_width="200px"
android:layout_height="wrap_content"
android:maxLength="10"
android:paddingLeft="20px"
android:editable="false"
android:enabled="false"
android:textSize="13px"
android:background="@drawable/input_over" >
</EditText>
<ImageButton
android:id="@+id/iconSelectBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="1.0dip"
android:layout_alignTop="@+id/iconSelect"
android:layout_alignRight="@+id/iconSelect"
android:layout_alignBottom="@+id/iconSelect"
android:background="@drawable/more_selector" >
</ImageButton>
<ImageButton
android:id="@+id/login"
android:layout_width="40px"
android:layout_height="40px"
android:layout_marginLeft="5dip"
android:layout_alignTop="@+id/iconSelectBtn"
android:layout_toRightOf="@+id/iconSelectBtn"
android:layout_alignBottom="@+id/iconSelectBtn"
android:background="@drawable/btn_in_selector" >
</ImageButton>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="44dip"
android:layout_alignParentBottom="true"
android:background="#BB768e95">
<LinearLayout
android:id="@+id/addLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentLeft="true"
android:gravity="center"
android:layout_marginTop="3px">
<ImageButton
android:id="@+id/addIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/add_selector">
</ImageButton>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="12px"
android:text="添加帳號">
</TextView>
</LinearLayout>
<LinearLayout
android:id="@+id/exitLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true"
android:gravity="center"
android:layout_marginTop="3px">
<ImageButton
android:id="@+id/exitIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/exit_selector">
</ImageButton>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="12px"
android:text="退出軟件">
</TextView>
</LinearLayout>
<LinearLayout
android:id="@+id/delLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentRight="true"
android:gravity="center"
android:layout_marginTop="3px">
<ImageButton
android:id="@+id/delIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/del_selector">
</ImageButton>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:textSize="12px"
android:text="刪除帳號">
</TextView>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
正對上面的login.xml的layout進行一下說明,背景部分前面已經講過了這裏也就不重複。
底部菜單實現,本來我是採用GridView實現的很是的方便可是後來因爲顯示位置很差控制改爲了用RelativeLayout和LinearLayout嵌套的方式,實現的比較土可是達到了顯示需求,首先是一個最外面的RelativeLayout目的是用來實現底部對齊顯示,而且把這個RelativeLayout的背景設置爲淺藍色半透明的效果,關鍵這2行:android:layout_alignParentBottom="true"和android:background="#BB768e95"。而後是在RelativeLayout內部添加3個LinearLayout分別是用來顯示添加帳號、退出軟件、刪除帳號3個功能按鈕菜單,而且分別設置爲左對齊、居中對齊、右對齊,3個LinearLayout都設置爲垂直佈局androidrientation="vertical",而後每LinearLayout添加相應的圖片和文字。
用戶選擇以及頭像顯示部分,這塊分紅3小塊,用來顯示用戶頭像的ImageView、用來顯示用戶名字而且點擊能夠出現選擇列表的EditText、用來點擊進入當前選擇用戶首頁的功能按鈕ImageButton,這3小塊的佈局實現也是採用elativeLayout和LinearLayout相互嵌套配合的方式實現的具體參考login.xml。這裏重點說說這個帳號選擇列表彈出窗口的實現,當點擊下拉箭頭按鈕的時候彈出並顯示,這個是用Dialog控件實現,首先準備好圓角的半透明背景圖mask_bg.png而後添加到res/drawable-mdpi文件夾下,接着自定義一個Dialog樣式文件,在res/values目錄下新建名爲dialogStyles2.xml的resources文件,在用戶受權驗證頁面的時候咱們也自定義過相似的Dialog的樣式,具體解釋能夠參考前面的戶受權驗證頁面功能,內容以下:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<resources>
<mce:style name="dialog2" parent="@android:style/Theme.Dialog"><!--
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@drawable/mask_bg</item>
<item name="android:backgroundDimEnabled">true</item>
--></mce:style><style name="dialog2" parent="@android:style/Theme.Dialog" mce_bogus="1"><item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@drawable/mask_bg</item>
<item name="android:backgroundDimEnabled">true</item></style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<mce:style name="dialog2" parent="@android:style/Theme.Dialog"><!--
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@drawable/mask_bg</item>
<item name="android:backgroundDimEnabled">true</item>
--></mce:style><style name="dialog2" parent="@android:style/Theme.Dialog" mce_bogus="1"><item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@drawable/mask_bg</item>
<item name="android:backgroundDimEnabled">true</item></style>
</resources>
接下來還須要定義選擇列表的layout,新建名爲dialog2.xml的layout文件,內容以下:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="4dip">
<ListView
android:id="@+id/list"
android:layout_width="240px"
android:layout_height="220px"
android:divider="#f1f2f2"
android:dividerHeight="1px"
android:layout_margin="5px"
android:background="#ffffff"
android:cacheColorHint="#00000000">
</ListView>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="4dip">
<ListView
android:id="@+id/list"
android:layout_width="240px"
android:layout_height="220px"
android:divider="#f1f2f2"
android:dividerHeight="1px"
android:layout_margin="5px"
android:background="#ffffff"
android:cacheColorHint="#00000000">
</ListView>
</LinearLayout>
完成了layout和樣式文件的編寫,接下來就是把dialogStyles2.xml樣式文件和dialog2.xml的列表layout用起來,當點擊id爲iconSelectBtn的ImageButton時顯示用戶選擇窗口,在LoginActivity的onCreate方法中添加以下代碼:
view plaincopy to clipboardprint?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
LinearLayout layout=(LinearLayout)findViewById(R.id.layout);
//背景自動適應
AndroidHelper.AutoBackground(this, layout, R.drawable.bg_v, R.drawable.bg_h);
ImageButton iconSelectBtn=(ImageButton)findViewById(R.id.iconSelectBtn);
iconSelectBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
View diaView=View.inflate(LoginActivity.this, R.layout.dialog2, null);
dialog=new Dialog(LoginActivity.this,R.style.dialog2);
dialog.setContentView(diaView);
dialog.show();
......
}
});
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
LinearLayout layout=(LinearLayout)findViewById(R.id.layout);
//背景自動適應
AndroidHelper.AutoBackground(this, layout, R.drawable.bg_v, R.drawable.bg_h);
ImageButton iconSelectBtn=(ImageButton)findViewById(R.id.iconSelectBtn);
iconSelectBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
View diaView=View.inflate(LoginActivity.this, R.layout.dialog2, null);
dialog=new Dialog(LoginActivity.this,R.style.dialog2);
dialog.setContentView(diaView);
dialog.show();
......
}
});
到這裏登陸的UI部分就實現的差很少了,剩下的都是一些功能部分代碼用來實現從sqlite中帳號列表的獲取,以及點擊選擇等交互操做等,這些在下一篇中來繼續的講。
android開發個人新浪微博客戶端-登陸頁面功能篇(4.2)
上一篇中完成了如上圖的UI部分的實現,如今繼續來說功能的實現,用戶登陸操做主要就是帳號列表顯示和選擇帳號登陸兩個功能其餘的都是些簡單的輔助功能,首先是點擊id爲iconSelectBtn的ImageButton時顯示用戶選擇窗口,這個時候去數據庫中獲取帳號記錄而後在選擇窗口中以列表方式顯示出來,經過上一篇已經知道Id爲list的ListView控件來顯示帳號列表,首先是從數據庫中獲取全部的帳戶記錄而後設置默認選中的用戶帳號代碼以下:
view plaincopy to clipboardprint?
private void initUser(){
//獲取帳號列表
dbHelper=new DataHelper(this);
userList = dbHelper.GetUserList(false);
if(userList.isEmpty())
{
Intent intent = new Intent();
intent.setClass(LoginActivity.this, AuthorizeActivity.class);
startActivity(intent);
}
else
{
SharedPreferences preferences = getSharedPreferences(Select_Name, Activity.MODE_PRIVATE);
String str= preferences.getString("name", "");
UserInfo user=null;
if(str!="")
{
user=GetUserByName(str);
}
if(user==null)
{
user=userList.get(0);
}
icon.setImageDrawable(user.getUserIcon());
iconSelect.setText(user.getUserName());
}
}
private void initUser(){
//獲取帳號列表
dbHelper=new DataHelper(this);
userList = dbHelper.GetUserList(false);
if(userList.isEmpty())
{
Intent intent = new Intent();
intent.setClass(LoginActivity.this, AuthorizeActivity.class);
startActivity(intent);
}
else
{
SharedPreferences preferences = getSharedPreferences(Select_Name, Activity.MODE_PRIVATE);
String str= preferences.getString("name", "");
UserInfo user=null;
if(str!="")
{
user=GetUserByName(str);
}
if(user==null)
{
user=userList.get(0);
}
icon.setImageDrawable(user.getUserIcon());
iconSelect.setText(user.getUserName());
}
}
這個initUser() 初始帳號的方法在LoginActivity的onCreate中調用,主要完成兩件事情,第一件獲取經過userList = dbHelper.GetUserList(false);獲取全部的帳戶記錄,關於DataHelper前面已經有說過了,若是獲取的用戶記錄爲空那麼就跳轉到用戶受權功能頁面讓用戶添加帳號,若是不爲空那麼經過SharedPreferences去讀取用戶上一次選擇的帳號名稱,若是沒有或者數據庫裏帳號記錄不包括這個帳戶名稱那麼默認顯示記錄的第一個帳號和頭像,若是有那麼顯示這個帳戶的名稱和頭像。關於SharedPreferences,是android提供給開發者用來存儲一些簡單的數據用的,很是方便相似於網站的Cookie,在這裏我就是用這個來保存上一次用戶選擇的是哪一個帳號,很是實用。
接下類首先爲Id爲list的ListView控件準備數據Adapter,這個Adapter很是簡單就是普通的adapter繼承BaseAdapter便可,代碼以下:
view plaincopy to clipboardprint?
public class UserAdapater extends BaseAdapter{
@Override
public int getCount() {
return userList.size();
}
@Override
public Object getItem(int position) {
return userList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.item_user, null);
ImageView iv = (ImageView) convertView.findViewById(R.id.iconImg);
TextView tv = (TextView) convertView.findViewById(R.id.showName);
UserInfo user = userList.get(position);
try {
//設置圖片顯示
iv.setImageDrawable(user.getUserIcon());
//設置信息
tv.setText(user.getUserName());
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}
public class UserAdapater extends BaseAdapter{
@Override
public int getCount() {
return userList.size();
}
@Override
public Object getItem(int position) {
return userList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.item_user, null);
ImageView iv = (ImageView) convertView.findViewById(R.id.iconImg);
TextView tv = (TextView) convertView.findViewById(R.id.showName);
UserInfo user = userList.get(position);
try {
//設置圖片顯示
iv.setImageDrawable(user.getUserIcon());
//設置信息
tv.setText(user.getUserName());
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}
接下就是爲這個ListView設定數據源Adapter,在帳號選擇窗口顯示的時候進行設置,添加到id爲iconSelectBtn的ImageButton的OnClickListener中代碼以下:
view plaincopy to clipboardprint?
ImageButton iconSelectBtn=(ImageButton)findViewById(R.id.iconSelectBtn);
iconSelectBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
......
dialog.show();
UserAdapater adapater = new UserAdapater();
ListView listview=(ListView)diaView.findViewById(R.id.list);
listview.setVerticalScrollBarEnabled(false);// ListView去掉下拉條
listview.setAdapter(adapater);
listview.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View view,int arg2, long arg3) {
TextView tv=(TextView)view.findViewById(R.id.showName);
iconSelect.setText(tv.getText());
ImageView iv=(ImageView)view.findViewById(R.id.iconImg);
icon.setImageDrawable(iv.getDrawable());
dialog.dismiss();
}
});
}
});
ImageButton iconSelectBtn=(ImageButton)findViewById(R.id.iconSelectBtn);
iconSelectBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
......
dialog.show();
UserAdapater adapater = new UserAdapater();
ListView listview=(ListView)diaView.findViewById(R.id.list);
listview.setVerticalScrollBarEnabled(false);// ListView去掉下拉條
listview.setAdapter(adapater);
listview.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View view,int arg2, long arg3) {
TextView tv=(TextView)view.findViewById(R.id.showName);
iconSelect.setText(tv.getText());
ImageView iv=(ImageView)view.findViewById(R.id.iconImg);
icon.setImageDrawable(iv.getDrawable());
dialog.dismiss();
}
});
}
});
經過上面代碼完成了帳號選擇的功能,接下來給id爲login的ImageButton添加OnClickListener,使得點擊後以當前選擇帳號進入微博首頁,代碼以下:
view plaincopy to clipboardprint?
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
......
ImageButton login=(ImageButton)findViewById(R.id.login);
login.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
GoHome();
}
});
}
//進入用戶首頁
private void GoHome(){
if(userList!=null)
{
String name=iconSelect.getText().toString();
UserInfo u=GetUserByName(name);
if(u!=null)
{
ConfigHelper.nowUser=u;//獲取當前選擇的用戶而且保存
}
}
if(ConfigHelper.nowUser!=null)
{
//進入用戶首頁
Intent intent = new Intent();
intent.setClass(LoginActivity.this, HomeActivity.class);
startActivity(intent);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
......
ImageButton login=(ImageButton)findViewById(R.id.login);
login.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
GoHome();
}
});
}
//進入用戶首頁
private void GoHome(){
if(userList!=null)
{
String name=iconSelect.getText().toString();
UserInfo u=GetUserByName(name);
if(u!=null)
{
ConfigHelper.nowUser=u;//獲取當前選擇的用戶而且保存
}
}
if(ConfigHelper.nowUser!=null)
{
//進入用戶首頁
Intent intent = new Intent();
intent.setClass(LoginActivity.this, HomeActivity.class);
startActivity(intent);
}
}
在上面的GoHome方法中ConfigHelper.nowUser是類型爲UserInfo的static類型用來保存當前登陸帳號的信息,替代web中session使用。
最後添加以下方法,用來當這個登陸LoginActivity結束的時候保存當前選擇的帳戶名稱到SharedPreferences中,以便幫用戶記住登陸帳號的功能,就是前面的initUser() 初始帳號的方法中會獲取保存在SharedPreferences中的帳戶名稱,代碼以下:
view plaincopy to clipboardprint?
@Override
protected void onStop() {
//得到SharedPreferences對象
SharedPreferences MyPreferences = getSharedPreferences(Select_Name, Activity.MODE_PRIVATE);
//得到SharedPreferences.Editor對象
SharedPreferences.Editor editor = MyPreferences.edit();
//保存組件中的值
editor.putString("name", iconSelect.getText().toString());
editor.commit();
super.onStop();
}
@Override
protected void onStop() {
//得到SharedPreferences對象
SharedPreferences MyPreferences = getSharedPreferences(Select_Name, Activity.MODE_PRIVATE);
//得到SharedPreferences.Editor對象
SharedPreferences.Editor editor = MyPreferences.edit();
//保存組件中的值
editor.putString("name", iconSelect.getText().toString());
editor.commit();
super.onStop();
}
至此登陸頁面功能篇結束,請繼續關注下一篇。
android開發個人新浪微博客戶端-用戶首頁面UI篇(5.1)
6 天前 上傳
下載附件 (101.43 KB) 在前篇完成了用戶登陸功能後開始用戶首頁的開發,用戶的首頁主要的內容是當前登陸用戶關注的微博列表,本篇先來說講UI的實現,效果如上圖,整個頁面分爲上、中、下三部分,上面部分是工具條,顯示當前登陸用戶的暱稱以及寫微博、刷新兩個功能按鈕;中間部分是當前用戶關注的最新微博列表,下面部分是功能切換欄,用來進行各個功能之間的切換。
首先新建名爲HomeActivity.java的Activity做爲用戶首頁,而後在res/layout目錄下新建名爲home.xml的Layout,具體代碼以下:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="3px">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo_ss">
</ImageView>
<TextView
android:id="@+id/showName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#343434"
android:textSize="15px">
</TextView>
<ImageButton
android:id="@+id/writeBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/refreshBtn"
android:background="@drawable/btn_write_selector">
</ImageButton>
<ImageButton
android:id="@+id/refreshBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="12px"
android:background="@drawable/btn_refresh_selector">
</ImageButton>
</RelativeLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/hr">
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="@+id/Msglist"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:divider="@drawable/divider"
android:dividerHeight="2px"
android:layout_margin="0px"
android:background="#BBFFFFFF"
android:cacheColorHint="#00000000"
android:layout_above="@+id/toolbarLayout"
android:fastScrollEnabled="true"
android:focusable="true">
</ListView>
<LinearLayout
android:id="@+id/loadingLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="invisible"
android:layout_centerInParent="true">
<ProgressBar
android:id="@+id/loading"
android:layout_width="31px"
android:layout_height="31px"
android:layout_gravity="center"
style="@style/progressStyle">
</ProgressBar>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在載入"
android:textSize="12px"
android:textColor="#9c9c9c"
android:layout_gravity="center"
android:layout_below="@+id/loading">
</TextView>
</LinearLayout>
<LinearLayout
android:id="@+id/toolbarLayout"
android:layout_width="fill_parent"
android:layout_height="44dip"
android:layout_alignParentBottom="true">
</LinearLayout>
</RelativeLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="3px">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo_ss">
</ImageView>
<TextView
android:id="@+id/showName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#343434"
android:textSize="15px">
</TextView>
<ImageButton
android:id="@+id/writeBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/refreshBtn"
android:background="@drawable/btn_write_selector">
</ImageButton>
<ImageButton
android:id="@+id/refreshBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="12px"
android:background="@drawable/btn_refresh_selector">
</ImageButton>
</RelativeLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/hr">
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="@+id/Msglist"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:divider="@drawable/divider"
android:dividerHeight="2px"
android:layout_margin="0px"
android:background="#BBFFFFFF"
android:cacheColorHint="#00000000"
android:layout_above="@+id/toolbarLayout"
android:fastScrollEnabled="true"
android:focusable="true">
</ListView>
<LinearLayout
android:id="@+id/loadingLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="invisible"
android:layout_centerInParent="true">
<ProgressBar
android:id="@+id/loading"
android:layout_width="31px"
android:layout_height="31px"
android:layout_gravity="center"
style="@style/progressStyle">
</ProgressBar>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在載入"
android:textSize="12px"
android:textColor="#9c9c9c"
android:layout_gravity="center"
android:layout_below="@+id/loading">
</TextView>
</LinearLayout>
<LinearLayout
android:id="@+id/toolbarLayout"
android:layout_width="fill_parent"
android:layout_height="44dip"
android:layout_alignParentBottom="true">
</LinearLayout>
</RelativeLayout>
</LinearLayout>
這個佈局首先是一個豎直的根LinearLayout,在這個根LinearLayout裏面分別是兩個RelativeLayout, 第一個RelativeLayout 用來顯示頁面的工具條,第二個RelativeLayout用來顯示列表以及底部的功能欄,特別主要在這第二個RelativeLayout中有一個id爲loadingLayout的LinearLayout是用來顯示數據載入中的動畫,它的android:visibility屬性爲invisible(也能夠設置成gone,區別:invisible這個View在ViewGroupt中仍保留它的位置,不從新layout
gone>不可見,但這個View在ViewGroupt中不保留位置,從新layout,那後面的view就會取代他的位置。 ),也就是一開始不顯示的意思,接下來看看
<ProgressBar
android:id="@+id/loading"
android:layout_width="31px"
android:layout_height="31px"
android:layout_gravity="center"
style="@style/progressStyle">
</ProgressBar>
這個ProgressBar控件就是用來顯示動畫用的,關鍵就是 style="@style/progressStyle",在res/values目錄下新建名爲loadingstyles.xml,內容以下:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<mce:style name="progressStyle" width="38" height="38" parent="@android:style/Widget.ProgressBar.Small"><!--
<item name="android:indeterminateDrawable">@anim/loading</item>
--></mce:style><style name="progressStyle" width="38" height="38" parent="@android:style/Widget.ProgressBar.Small" mce_bogus="1"><item name="android:indeterminateDrawable">@anim/loading</item></style>
</resources>
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<mce:style name="progressStyle" width="38" height="38" parent="@android:style/Widget.ProgressBar.Small"><!--
<item name="android:indeterminateDrawable">@anim/loading</item>
--></mce:style><style name="progressStyle" width="38" height="38" parent="@android:style/Widget.ProgressBar.Small" mce_bogus="1"><item name="android:indeterminateDrawable">@anim/loading</item></style>
</resources>
接着準備好r1.png - r8.png,
6 天前 上傳
下載附件 (998 Bytes)
6 天前 上傳
下載附件 (980 Bytes)
6 天前 上傳
下載附件 (1013 Bytes)
6 天前 上傳
下載附件 (1014 Bytes)
6 天前 上傳
下載附件 (986 Bytes)
6 天前 上傳
下載附件 (992 Bytes)
6 天前 上傳
下載附件 (1010 Bytes)
6 天前 上傳
下載附件 (1 KB) 八張不一樣的小圖片分別表明每旋轉45度圖片,八張恰好是360度。把這些圖片添加到res/drawable-mdpi目錄中。而後在res/anim目錄下新建名爲loading.xml動畫文件,內容以下:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="UTF-8"?>
<animation-list android:oneshot="false"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:duration="200" android:drawable="@drawable/r1" />
<item android:duration="200" android:drawable="@drawable/r2" />
<item android:duration="200" android:drawable="@drawable/r3" />
<item android:duration="200" android:drawable="@drawable/r4" />
<item android:duration="200" android:drawable="@drawable/r5" />
<item android:duration="200" android:drawable="@drawable/r6" />
<item android:duration="200" android:drawable="@drawable/r7" />
<item android:duration="200" android:drawable="@drawable/r8" />
</animation-list>
<?xml version="1.0" encoding="UTF-8"?>
<animation-list android:oneshot="false"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:duration="200" android:drawable="@drawable/r1" />
<item android:duration="200" android:drawable="@drawable/r2" />
<item android:duration="200" android:drawable="@drawable/r3" />
<item android:duration="200" android:drawable="@drawable/r4" />
<item android:duration="200" android:drawable="@drawable/r5" />
<item android:duration="200" android:drawable="@drawable/r6" />
<item android:duration="200" android:drawable="@drawable/r7" />
<item android:duration="200" android:drawable="@drawable/r8" />
</animation-list>
關於Android播放動畫實現我是參考http://www.eoeandroid.com/forum.php?mod=viewthread&tid=67311&extra=
本篇到這裏就結束了,下一篇繼續講用戶首頁的功能實現,請關注。
android開發個人新浪微博客戶端-用戶首頁面功能篇(5.2)
6 天前 上傳
下載附件 (101.43 KB)
上一篇完成用戶首頁的UI實現,本篇接下來說功能部分的實現,本頁面主要的功能就用戶關注的最新微博列表,從上一篇中知道本列表是用ID爲Msglist的ListView控件來實現,本篇的主要就講解若是獲取微博列表數據給這個ListView提供顯示數據。ListView每一條子數據分別由用戶頭像、用戶暱稱、發佈時間、是否包含照片、微博內容這五部分組成,根據這五部分定義一個名爲WeiBoInfo.java實體類,代碼以下:
view plaincopy to clipboardprint?
public class WeiBoInfo {
//文章id
private String id;
public String getId(){
return id;
}
public void setId(String id){
this.id=id;
}
//發佈人id
private String userId;
public String getUserId(){
return userId;
}
public void setUserId(String userId){
this.userId=userId;
}
//發佈人名字
private String userName;
public String getUserName(){
return userName;
}
public void setUserName(String userName){
this.userName=userName;
}
//發佈人頭像
private String userIcon;
public String getUserIcon(){
return userIcon;
}
public void setUserIcon(String userIcon){
this.userIcon=userIcon;
}
//發佈時間
private String time;
public String getTime(){
return time;
}
public void setTime(String time)
{
this.time=time;
}
//是否有圖片
private Boolean haveImage=false;
public Boolean getHaveImage(){
return haveImage;
}
public void setHaveImage(Boolean haveImage){
this.haveImage=haveImage;
}
//文章內容
private String text;
public String getText(){
return text;
}
public void setText(String text){
this.text=text;
}
}
public class WeiBoInfo {
//文章id
private String id;
public String getId(){
return id;
}
public void setId(String id){
this.id=id;
}
//發佈人id
private String userId;
public String getUserId(){
return userId;
}
public void setUserId(String userId){
this.userId=userId;
}
//發佈人名字
private String userName;
public String getUserName(){
return userName;
}
public void setUserName(String userName){
this.userName=userName;
}
//發佈人頭像
private String userIcon;
public String getUserIcon(){
return userIcon;
}
public void setUserIcon(String userIcon){
this.userIcon=userIcon;
}
//發佈時間
private String time;
public String getTime(){
return time;
}
public void setTime(String time)
{
this.time=time;
}
//是否有圖片
private Boolean haveImage=false;
public Boolean getHaveImage(){
return haveImage;
}
public void setHaveImage(Boolean haveImage){
this.haveImage=haveImage;
}
//文章內容
private String text;
public String getText(){
return text;
}
public void setText(String text){
this.text=text;
}
}
而後在res/layout目錄下新建名爲weibo.xml的Layout用來控制ListView子項的顯示部件,代碼很簡單很少解釋了,直接看下面代碼:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/wbicon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/usericon"
android:layout_margin="8px">
</ImageView>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="0px"
android:paddingRight="5px"
android:layout_marginTop="5px"
android:layout_marginBottom="5px">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/wbuser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15px"
android:textColor="#424952"
android:layout_alignParentLeft="true">
</TextView>
<ImageView
android:id="@+id/wbimage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3px"
android:layout_marginRight="5px"
android:layout_toLeftOf="@+id/wbtime">
</ImageView>
<TextView
android:id="@+id/wbtime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:textColor="#f7a200"
android:textSize="12px">
</TextView>
</RelativeLayout>
<TextView
android:id="@+id/wbtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#424952"
android:textSize="13px"
android:layout_marginTop="4px">
</TextView>
</LinearLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/wbicon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/usericon"
android:layout_margin="8px">
</ImageView>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="0px"
android:paddingRight="5px"
android:layout_marginTop="5px"
android:layout_marginBottom="5px">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/wbuser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15px"
android:textColor="#424952"
android:layout_alignParentLeft="true">
</TextView>
<ImageView
android:id="@+id/wbimage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3px"
android:layout_marginRight="5px"
android:layout_toLeftOf="@+id/wbtime">
</ImageView>
<TextView
android:id="@+id/wbtime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:textColor="#f7a200"
android:textSize="12px">
</TextView>
</RelativeLayout>
<TextView
android:id="@+id/wbtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#424952"
android:textSize="13px"
android:layout_marginTop="4px">
</TextView>
</LinearLayout>
</LinearLayout>
接下來爲列表控件定義一個數據Adapter,代碼以下:
view plaincopy to clipboardprint?
private List<WeiBoInfo> wbList;
//微博列表Adapater
public class WeiBoAdapater extends BaseAdapter{
private AsyncImageLoader asyncImageLoader;
@Override
public int getCount() {
return wbList.size();
}
@Override
public Object getItem(int position) {
return wbList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
asyncImageLoader = new AsyncImageLoader();
convertView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.weibo, null);
WeiBoHolder wh = new WeiBoHolder();
wh.wbicon = (ImageView) convertView.findViewById(R.id.wbicon);
wh.wbtext = (TextView) convertView.findViewById(R.id.wbtext);
wh.wbtime = (TextView) convertView.findViewById(R.id.wbtime);
wh.wbuser = (TextView) convertView.findViewById(R.id.wbuser);
wh.wbimage=(ImageView) convertView.findViewById(R.id.wbimage);
WeiBoInfo wb = wbList.get(position);
if(wb!=null){
convertView.setTag(wb.getId());
wh.wbuser.setText(wb.getUserName());
wh.wbtime.setText(wb.getTime());
wh.wbtext.setText(wb.getText(), TextView.BufferType.SPANNABLE);
textHighlight(wh.wbtext,new char[]{'#'},new char[]{'#'});
textHighlight(wh.wbtext,new char[]{'@'},new char[]{':',' '});
textHighlight2(wh.wbtext,"http://"," ");
if(wb.getHaveImage()){
wh.wbimage.setImageResource(R.drawable.images);
}
Drawable cachedImage = asyncImageLoader.loadDrawable(wb.getUserIcon(),wh.wbicon, new ImageCallback(){
@Override
public void imageLoaded(Drawable imageDrawable,ImageView imageView, String imageUrl) {
imageView.setImageDrawable(imageDrawable);
}
});
if (cachedImage == null) {
wh.wbicon.setImageResource(R.drawable.usericon);
}else{
wh.wbicon.setImageDrawable(cachedImage);
}
}
return convertView;
}
private List<WeiBoInfo> wbList;
//微博列表Adapater
public class WeiBoAdapater extends BaseAdapter{
private AsyncImageLoader asyncImageLoader;
@Override
public int getCount() {
return wbList.size();
}
@Override
public Object getItem(int position) {
return wbList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
asyncImageLoader = new AsyncImageLoader();
convertView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.weibo, null);
WeiBoHolder wh = new WeiBoHolder();
wh.wbicon = (ImageView) convertView.findViewById(R.id.wbicon);
wh.wbtext = (TextView) convertView.findViewById(R.id.wbtext);
wh.wbtime = (TextView) convertView.findViewById(R.id.wbtime);
wh.wbuser = (TextView) convertView.findViewById(R.id.wbuser);
wh.wbimage=(ImageView) convertView.findViewById(R.id.wbimage);
WeiBoInfo wb = wbList.get(position);
if(wb!=null){
convertView.setTag(wb.getId());
wh.wbuser.setText(wb.getUserName());
wh.wbtime.setText(wb.getTime());
wh.wbtext.setText(wb.getText(), TextView.BufferType.SPANNABLE);
textHighlight(wh.wbtext,new char[]{'#'},new char[]{'#'});
textHighlight(wh.wbtext,new char[]{'@'},new char[]{':',' '});
textHighlight2(wh.wbtext,"http://"," ");
if(wb.getHaveImage()){
wh.wbimage.setImageResource(R.drawable.images);
}
Drawable cachedImage = asyncImageLoader.loadDrawable(wb.getUserIcon(),wh.wbicon, new ImageCallback(){
@Override
public void imageLoaded(Drawable imageDrawable,ImageView imageView, String imageUrl) {
imageView.setImageDrawable(imageDrawable);
}
});
if (cachedImage == null) {
wh.wbicon.setImageResource(R.drawable.usericon);
}else{
wh.wbicon.setImageDrawable(cachedImage);
}
}
return convertView;
}
上面的這個Adapter實現沒有什麼特別的很普通,不過這個中使用了AsyncImageLoader的方法,這個是用來實現用戶頭像圖標的異步載入顯示,這樣能提升列表顯示的速度,提升用戶體驗,AsyncImageLoader的代碼以下:
view plaincopy to clipboardprint?
public class AsyncImageLoader {
//SoftReference是軟引用,是爲了更好的爲了系統回收變量
private HashMap<String, SoftReference<Drawable>> imageCache;
public AsyncImageLoader() {
imageCache = new HashMap<String, SoftReference<Drawable>>();
}
public Drawable loadDrawable(final String imageUrl,final ImageView imageView, final ImageCallback imageCallback){
if (imageCache.containsKey(imageUrl)) {
//從緩存中獲取
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
Drawable drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}
final Handler handler = new Handler() {
public void handleMessage(Message message) {
imageCallback.imageLoaded((Drawable) message.obj, imageView,imageUrl);
}
};
//創建新一個新的線程下載圖片
new Thread() {
@Override
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl);
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
Message message = handler.obtainMessage(0, drawable);
handler.sendMessage(message);
}
}.start();
return null;
}
public static Drawable loadImageFromUrl(String url){
URL m;
InputStream i = null;
try {
m = new URL(url);
i = (InputStream) m.getContent();
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Drawable d = Drawable.createFromStream(i, "src");
return d;
}
//回調接口
public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable,ImageView imageView, String imageUrl);
}
}
public class AsyncImageLoader {
//SoftReference是軟引用,是爲了更好的爲了系統回收變量
private HashMap<String, SoftReference<Drawable>> imageCache;
public AsyncImageLoader() {
imageCache = new HashMap<String, SoftReference<Drawable>>();
}
public Drawable loadDrawable(final String imageUrl,final ImageView imageView, final ImageCallback imageCallback){
if (imageCache.containsKey(imageUrl)) {
//從緩存中獲取
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
Drawable drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}
final Handler handler = new Handler() {
public void handleMessage(Message message) {
imageCallback.imageLoaded((Drawable) message.obj, imageView,imageUrl);
}
};
//創建新一個新的線程下載圖片
new Thread() {
@Override
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl);
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
Message message = handler.obtainMessage(0, drawable);
handler.sendMessage(message);
}
}.start();
return null;
}
public static Drawable loadImageFromUrl(String url){
URL m;
InputStream i = null;
try {
m = new URL(url);
i = (InputStream) m.getContent();
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Drawable d = Drawable.createFromStream(i, "src");
return d;
}
//回調接口
public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable,ImageView imageView, String imageUrl);
}
}
完成上述的工做後,接下來就是顯示微薄列表, 在HomeActivity的onCreate方法中調用loadList();代碼以下:
view plaincopy to clipboardprint?
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
。。。。。。
loadList();
}
private void loadList(){
if(ConfigHelper.nowUser==null)
{
}
else
{
user=ConfigHelper.nowUser;
//顯示當前用戶名稱
TextView showName=(TextView)findViewById(R.id.showName);
showName.setText(user.getUserName());
OAuth auth=new OAuth();
String url = "http://api.t.sina.com.cn/statuses/friends_timeline.json";
List params=new ArrayList();
params.add(new BasicNameValuePair("source", auth.consumerKey));
HttpResponse response =auth.SignRequest(user.getToken(), user.getTokenSecret(), url, params);
if (200 == response.getStatusLine().getStatusCode()){
try {
InputStream is = response.getEntity().getContent();
Reader reader = new BufferedReader(new InputStreamReader(is), 4000);
StringBuilder buffer = new StringBuilder((int) response.getEntity().getContentLength());
try {
char[] tmp = new char[1024];
int l;
while ((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
} finally {
reader.close();
}
String string = buffer.toString();
//Log.e("json", "rs:" + string);
response.getEntity().consumeContent();
JSONArray data=new JSONArray(string);
for(int i=0;i<data.length();i++)
{
JSONObject d=data.getJSONObject(i);
//Log.e("json", "rs:" + d.getString("created_at"));
if(d!=null){
JSONObject u=d.getJSONObject("user");
if(d.has("retweeted_status")){
JSONObject r=d.getJSONObject("retweeted_status");
}
//微博id
String id=d.getString("id");
String userId=u.getString("id");
String userName=u.getString("screen_name");
String userIcon=u.getString("profile_image_url");
Log.e("userIcon", userIcon);
String time=d.getString("created_at");
String text=d.getString("text");
Boolean haveImg=false;
if(d.has("thumbnail_pic")){
haveImg=true;
//String thumbnail_pic=d.getString("thumbnail_pic");
//Log.e("thumbnail_pic", thumbnail_pic);
}
Date date=new Date(time);
time=ConvertTime(date);
if(wbList==null){
wbList=new ArrayList<WeiBoInfo>();
}
WeiBoInfo w=new WeiBoInfo();
w.setId(id);
w.setUserId(userId);
w.setUserName(userName);
w.setTime(time);
w.setText(text);
w.setHaveImage(haveImg);
w.setUserIcon(userIcon);
wbList.add(w);
}
}
}catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
if(wbList!=null)
{
WeiBoAdapater adapater = new WeiBoAdapater();
ListView Msglist=(ListView)findViewById(R.id.Msglist);
Msglist.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View view,int arg2, long arg3) {
Object obj=view.getTag();
if(obj!=null){
String id=obj.toString();
Intent intent = new Intent(HomeActivity.this,ViewActivity.class);
Bundle b=new Bundle();
b.putString("key", id);
intent.putExtras(b);
startActivity(intent);
}
}
});
Msglist.setAdapter(adapater);
}
}
loadingLayout.setVisibility(View.GONE);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
。。。。。。
loadList();
}
private void loadList(){
if(ConfigHelper.nowUser==null)
{
}
else
{
user=ConfigHelper.nowUser;
//顯示當前用戶名稱
TextView showName=(TextView)findViewById(R.id.showName);
showName.setText(user.getUserName());
OAuth auth=new OAuth();
String url = "http://api.t.sina.com.cn/statuses/friends_timeline.json";
List params=new ArrayList();
params.add(new BasicNameValuePair("source", auth.consumerKey));
HttpResponse response =auth.SignRequest(user.getToken(), user.getTokenSecret(), url, params);
if (200 == response.getStatusLine().getStatusCode()){
try {
InputStream is = response.getEntity().getContent();
Reader reader = new BufferedReader(new InputStreamReader(is), 4000);
StringBuilder buffer = new StringBuilder((int) response.getEntity().getContentLength());
try {
char[] tmp = new char[1024];
int l;
while ((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
} finally {
reader.close();
}
String string = buffer.toString();
//Log.e("json", "rs:" + string);
response.getEntity().consumeContent();
JSONArray data=new JSONArray(string);
for(int i=0;i<data.length();i++)
{
JSONObject d=data.getJSONObject(i);
//Log.e("json", "rs:" + d.getString("created_at"));
if(d!=null){
JSONObject u=d.getJSONObject("user");
if(d.has("retweeted_status")){
JSONObject r=d.getJSONObject("retweeted_status");
}
//微博id
String id=d.getString("id");
String userId=u.getString("id");
String userName=u.getString("screen_name");
String userIcon=u.getString("profile_image_url");
Log.e("userIcon", userIcon);
String time=d.getString("created_at");
String text=d.getString("text");
Boolean haveImg=false;
if(d.has("thumbnail_pic")){
haveImg=true;
//String thumbnail_pic=d.getString("thumbnail_pic");
//Log.e("thumbnail_pic", thumbnail_pic);
}
Date date=new Date(time);
time=ConvertTime(date);
if(wbList==null){
wbList=new ArrayList<WeiBoInfo>();
}
WeiBoInfo w=new WeiBoInfo();
w.setId(id);
w.setUserId(userId);
w.setUserName(userName);
w.setTime(time);
w.setText(text);
w.setHaveImage(haveImg);
w.setUserIcon(userIcon);
wbList.add(w);
}
}
}catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
if(wbList!=null)
{
WeiBoAdapater adapater = new WeiBoAdapater();
ListView Msglist=(ListView)findViewById(R.id.Msglist);
Msglist.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View view,int arg2, long arg3) {
Object obj=view.getTag();
if(obj!=null){
String id=obj.toString();
Intent intent = new Intent(HomeActivity.this,ViewActivity.class);
Bundle b=new Bundle();
b.putString("key", id);
intent.putExtras(b);
startActivity(intent);
}
}
});
Msglist.setAdapter(adapater);
}
}
loadingLayout.setVisibility(View.GONE);
}
上面的loadList() 方法經過新浪Api接口http://api.t.sina.com.cn/statuses/friends_timeline.json獲取當前登陸用戶及其所關注用戶的最新微博消息,而後顯示到列表中。
這樣就完成了用戶首頁功能的開發。
android開發個人新浪微博客戶端-閱讀微博UI篇(6.1)
6 天前 上傳
下載附件 (154.98 KB) 上一篇完成了微博列表的功能,本篇接着作預讀微博的功能,本篇主要講講UI部分的實現,最終實現的效果如上圖所示。整個顯示頁面從上往下分爲四部分,第一部分頂部工具條、第二部分做者頭像和名稱、第三部分微博正文、第四部分功能按鈕區。新建名爲ViewActivity.java做爲閱讀微博的頁面,再res/layout目錄下新建名爲view.xml的Layout,代碼以下:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="3px">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo_ss">
</ImageView>
<TextView
android:id="@+id/showName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#343434"
android:text="閱讀微博"
android:textSize="16px">
</TextView>
<ImageButton
android:id="@+id/returnBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/homeBtn"
android:background="@drawable/bnt_return_selector">
</ImageButton>
<ImageButton
android:id="@+id/homeBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="12px"
android:background="@drawable/btn_home_selector">
</ImageButton>
</RelativeLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/hr">
</LinearLayout>
<RelativeLayout
android:id="@+id/user_bg"
android:layout_width="fill_parent"
android:layout_height="78px"
android:paddingTop="8px"
android:paddingLeft="15px"
android:background="@drawable/u_bg_v">
<ImageView
android:id="@+id/user_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:src="@drawable/usericon">
</ImageView>
<TextView
android:id="@+id/user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/user_icon"
android:layout_marginLeft="10px"
android:layout_marginTop="18px"
android:textColor="#000000">
</TextView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="5px"
android:layout_marginTop="10px"
android:src="@drawable/sjjt">
</ImageView>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="17px"
android:paddingRight="17px"
android:paddingBottom="5px"
android:layout_above="@+id/menu_layout">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="15px">
</TextView>
<ImageView
android:id="@+id/pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ImageView>
</LinearLayout>
</ScrollView>
<LinearLayout
android:id="@+id/loadingLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone"
android:layout_centerInParent="true">
<ProgressBar
android:id="@+id/loading"
android:layout_width="31px"
android:layout_height="31px"
android:layout_gravity="center"
style="@style/progressStyle">
</ProgressBar>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在載入"
android:textSize="12px"
android:textColor="#9c9c9c"
android:layout_gravity="center"
android:layout_below="@+id/loading">
</TextView>
</LinearLayout>
<TableLayout
android:id="@+id/menu_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_alignParentBottom="true"
android:layout_marginBottom="5px">
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<Button
android:id="@+id/btn_gz"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#3882b8"
android:textSize="15px"
android:text=" 關注(1231)"
android:background="@drawable/lt_selector">
</Button>
<Button
android:id="@+id/btn_pl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#3882b8"
android:textSize="15px"
android:text=" 評論(31)"
android:background="@drawable/rt_selector">
</Button>
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#3882b8"
android:textSize="15px"
android:layout_gravity="left"
android:text="刷新"
android:background="@drawable/lb_selector">
</Button>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#3882b8"
android:textSize="15px"
android:text="收藏"
android:background="@drawable/rb_selector">
</Button>
</TableRow>
</TableLayout>
</RelativeLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="3px">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/logo_ss">
</ImageView>
<TextView
android:id="@+id/showName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#343434"
android:text="閱讀微博"
android:textSize="16px">
</TextView>
<ImageButton
android:id="@+id/returnBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/homeBtn"
android:background="@drawable/bnt_return_selector">
</ImageButton>
<ImageButton
android:id="@+id/homeBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="12px"
android:background="@drawable/btn_home_selector">
</ImageButton>
</RelativeLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/hr">
</LinearLayout>
<RelativeLayout
android:id="@+id/user_bg"
android:layout_width="fill_parent"
android:layout_height="78px"
android:paddingTop="8px"
android:paddingLeft="15px"
android:background="@drawable/u_bg_v">
<ImageView
android:id="@+id/user_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:src="@drawable/usericon">
</ImageView>
<TextView
android:id="@+id/user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/user_icon"
android:layout_marginLeft="10px"
android:layout_marginTop="18px"
android:textColor="#000000">
</TextView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="5px"
android:layout_marginTop="10px"
android:src="@drawable/sjjt">
</ImageView>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="17px"
android:paddingRight="17px"
android:paddingBottom="5px"
android:layout_above="@+id/menu_layout">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="15px">
</TextView>
<ImageView
android:id="@+id/pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ImageView>
</LinearLayout>
</ScrollView>
<LinearLayout
android:id="@+id/loadingLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone"
android:layout_centerInParent="true">
<ProgressBar
android:id="@+id/loading"
android:layout_width="31px"
android:layout_height="31px"
android:layout_gravity="center"
style="@style/progressStyle">
</ProgressBar>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在載入"
android:textSize="12px"
android:textColor="#9c9c9c"
android:layout_gravity="center"
android:layout_below="@+id/loading">
</TextView>
</LinearLayout>
<TableLayout
android:id="@+id/menu_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_alignParentBottom="true"
android:layout_marginBottom="5px">
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<Button
android:id="@+id/btn_gz"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#3882b8"
android:textSize="15px"
android:text=" 關注(1231)"
android:background="@drawable/lt_selector">
</Button>
<Button
android:id="@+id/btn_pl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#3882b8"
android:textSize="15px"
android:text=" 評論(31)"
android:background="@drawable/rt_selector">
</Button>
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#3882b8"
android:textSize="15px"
android:layout_gravity="left"
android:text="刷新"
android:background="@drawable/lb_selector">
</Button>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#3882b8"
android:textSize="15px"
android:text="收藏"
android:background="@drawable/rb_selector">
</Button>
</TableRow>
</TableLayout>
</RelativeLayout>
</LinearLayout>
上面這個佈局實現起來並不複雜, 主要看看功能按鈕區的4個按鈕的點擊上去的切換背景的效果,以關注按鈕爲例子看這行設置,android:background="@drawable/lt_selector",在res/drawable-mdpi目錄下新建名爲lt_selector.xml用來實現點擊上去切換圖片的效果,具體代碼以下:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/tbtn_1" />
<item android:state_pressed="true" android:drawable="@drawable/tbtn_h_1" />
</selector>
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/tbtn_1" />
<item android:state_pressed="true" android:drawable="@drawable/tbtn_h_1" />
</selector>
本篇雖然看layout文件很是的長,其實仔細看看很是的簡單了沒有什麼難和複雜的了,就是按照前面的經驗控制好圖片以及控件的顯示位置和樣式便可,本篇中用了一個ScrollView控件這個是前面沒有用到過的,主要是用來當微博的內容超出顯示區域的時候出現滾動條用的這個很是容易使用,因此就簡單寫一下到此結束了,請繼續關注下一篇閱讀微博的功能篇。
android開發個人新浪微博客戶端-閱讀微博功能篇(6.2)
6 天前 上傳
下載附件 (154.98 KB) 注:最近因爲OAuth上傳圖片碰到了難題,一直在作這方面的研究致使博客好久沒有更新。
在上面一篇中已經實現了預讀微博的UI界面,效果如上圖,接下來完成功能部分的代碼,當用戶在上一個列表界面的列表中點擊某一條微博的時候顯示這個閱讀微博的界面,在這個界面中根據傳來的微博ID,而後根據這個ID經過api獲取微博的具體內容進行顯示。
在ViewActivity.class的onCreate方法中添加以下代碼:
view plaincopy to clipboardprint?
private UserInfo user;
private String key="";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view);
。。。。。
//獲取上一個頁面傳遞過來的key,key爲某一條微博的id
Intent i=this.getIntent();
if(!i.equals(null)){
Bundle b=i.getExtras();
if(b!=null){
if(b.containsKey("key")){
key = b.getString("key");
view(key);
}
}
}
}
private UserInfo user;
private String key="";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view);
。。。。。
//獲取上一個頁面傳遞過來的key,key爲某一條微博的id
Intent i=this.getIntent();
if(!i.equals(null)){
Bundle b=i.getExtras();
if(b!=null){
if(b.containsKey("key")){
key = b.getString("key");
view(key);
}
}
}
}
接下來就是view方法具體獲取微博內容的方法,在這個方法中若是獲取的本條微博若是包含圖片那麼就用前面AsyncImageLoader的方法異步載入圖片而且進行顯示,同時在這個方法中還要獲取本條微博被轉發的次數以及評論的次數,具體代碼以下:
view plaincopy to clipboardprint?
private void view(String id){
user=ConfigHelper.nowUser;
OAuth auth=new OAuth();
String url = "http://api.t.sina.com.cn/statuses/show/:id.json";
List params=new ArrayList();
params.add(new BasicNameValuePair("source", auth.consumerKey));
params.add(new BasicNameValuePair("id", id));
HttpResponse response =auth.SignRequest(user.getToken(), user.getTokenSecret(), url, params);
if (200 == response.getStatusLine().getStatusCode()){
try {
InputStream is = response.getEntity().getContent();
Reader reader = new BufferedReader(new InputStreamReader(is), 4000);
StringBuilder buffer = new StringBuilder((int) response.getEntity().getContentLength());
try {
char[] tmp = new char[1024];
int l;
while ((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
} finally {
reader.close();
}
String string = buffer.toString();
//Log.e("json", "rs:" + string);
response.getEntity().consumeContent();
JSONObject data=new JSONObject(string);
if(data!=null){
JSONObject u=data.getJSONObject("user");
String userName=u.getString("screen_name");
String userIcon=u.getString("profile_image_url");
Log.e("userIcon", userIcon);
String time=data.getString("created_at");
String text=data.getString("text");
TextView utv=(TextView)findViewById(R.id.user_name);
utv.setText(userName);
TextView ttv=(TextView)findViewById(R.id.text);
ttv.setText(text);
ImageView iv=(ImageView)findViewById(R.id.user_icon);
AsyncImageLoader asyncImageLoader = new AsyncImageLoader();
Drawable cachedImage = asyncImageLoader.loadDrawable(userIcon,iv, new ImageCallback(){
@Override
public void imageLoaded(Drawable imageDrawable,ImageView imageView, String imageUrl) {
imageView.setImageDrawable(imageDrawable);
}
});
if (cachedImage == null)
{
iv.setImageResource(R.drawable.usericon);
}
else
{
iv.setImageDrawable(cachedImage);
}
if(data.has("bmiddle_pic")){
String picurl=data.getString("bmiddle_pic");
String picurl2=data.getString("original_pic");
ImageView pic=(ImageView)findViewById(R.id.pic);
pic.setTag(picurl2);
pic.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Object obj=v.getTag();
Intent intent = new Intent(ViewActivity.this,ImageActivity.class);
Bundle b=new Bundle();
b.putString("url", obj.toString());
intent.putExtras(b);
startActivity(intent);
}
});
Drawable cachedImage2 = asyncImageLoader.loadDrawable(picurl,pic, new ImageCallback(){
@Override
public void imageLoaded(Drawable imageDrawable,ImageView imageView, String imageUrl) {
showImg(imageView,imageDrawable);
}
});
if (cachedImage2 == null)
{
//pic.setImageResource(R.drawable.usericon);
}
else
{
showImg(pic,cachedImage2);
}
}
}
}catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
url = "http://api.t.sina.com.cn/statuses/counts.json";
params=new ArrayList();
params.add(new BasicNameValuePair("source", auth.consumerKey));
params.add(new BasicNameValuePair("ids", id));
response =auth.SignRequest(user.getToken(), user.getTokenSecret(), url, params);
if (200 == response.getStatusLine().getStatusCode()){
try {
InputStream is = response.getEntity().getContent();
Reader reader = new BufferedReader(new InputStreamReader(is), 4000);
StringBuilder buffer = new StringBuilder((int) response.getEntity().getContentLength());
try {
char[] tmp = new char[1024];
int l;
while ((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
} finally {
reader.close();
}
String string = buffer.toString();
response.getEntity().consumeContent();
JSONArray data=new JSONArray(string);
if(data!=null){
if(data.length()>0){
JSONObject d=data.getJSONObject(0);
String comments=d.getString("comments");
String rt=d.getString("rt");
Button btn_gz=(Button)findViewById(R.id.btn_gz);
btn_gz.setText(" 轉發("+rt+")");
Button btn_pl=(Button)findViewById(R.id.btn_pl);
btn_pl.setText(" 評論("+comments+")");
}
}
}
catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
private void view(String id){
user=ConfigHelper.nowUser;
OAuth auth=new OAuth();
String url = "http://api.t.sina.com.cn/statuses/show/:id.json";
List params=new ArrayList();
params.add(new BasicNameValuePair("source", auth.consumerKey));
params.add(new BasicNameValuePair("id", id));
HttpResponse response =auth.SignRequest(user.getToken(), user.getTokenSecret(), url, params);
if (200 == response.getStatusLine().getStatusCode()){
try {
InputStream is = response.getEntity().getContent();
Reader reader = new BufferedReader(new InputStreamReader(is), 4000);
StringBuilder buffer = new StringBuilder((int) response.getEntity().getContentLength());
try {
char[] tmp = new char[1024];
int l;
while ((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
} finally {
reader.close();
}
String string = buffer.toString();
//Log.e("json", "rs:" + string);
response.getEntity().consumeContent();
JSONObject data=new JSONObject(string);
if(data!=null){
JSONObject u=data.getJSONObject("user");
String userName=u.getString("screen_name");
String userIcon=u.getString("profile_image_url");
Log.e("userIcon", userIcon);
String time=data.getString("created_at");
String text=data.getString("text");
TextView utv=(TextView)findViewById(R.id.user_name);
utv.setText(userName);
TextView ttv=(TextView)findViewById(R.id.text);
ttv.setText(text);
ImageView iv=(ImageView)findViewById(R.id.user_icon);
AsyncImageLoader asyncImageLoader = new AsyncImageLoader();
Drawable cachedImage = asyncImageLoader.loadDrawable(userIcon,iv, new ImageCallback(){
@Override
public void imageLoaded(Drawable imageDrawable,ImageView imageView, String imageUrl) {
imageView.setImageDrawable(imageDrawable);
}
});
if (cachedImage == null)
{
iv.setImageResource(R.drawable.usericon);
}
else
{
iv.setImageDrawable(cachedImage);
}
if(data.has("bmiddle_pic")){
String picurl=data.getString("bmiddle_pic");
String picurl2=data.getString("original_pic");
ImageView pic=(ImageView)findViewById(R.id.pic);
pic.setTag(picurl2);
pic.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Object obj=v.getTag();
Intent intent = new Intent(ViewActivity.this,ImageActivity.class);
Bundle b=new Bundle();
b.putString("url", obj.toString());
intent.putExtras(b);
startActivity(intent);
}
});
Drawable cachedImage2 = asyncImageLoader.loadDrawable(picurl,pic, new ImageCallback(){
@Override
public void imageLoaded(Drawable imageDrawable,ImageView imageView, String imageUrl) {
showImg(imageView,imageDrawable);
}
});
if (cachedImage2 == null)
{
//pic.setImageResource(R.drawable.usericon);
}
else
{
showImg(pic,cachedImage2);
}
}
}
}catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
url = "http://api.t.sina.com.cn/statuses/counts.json";
params=new ArrayList();
params.add(new BasicNameValuePair("source", auth.consumerKey));
params.add(new BasicNameValuePair("ids", id));
response =auth.SignRequest(user.getToken(), user.getTokenSecret(), url, params);
if (200 == response.getStatusLine().getStatusCode()){
try {
InputStream is = response.getEntity().getContent();
Reader reader = new BufferedReader(new InputStreamReader(is), 4000);
StringBuilder buffer = new StringBuilder((int) response.getEntity().getContentLength());
try {
char[] tmp = new char[1024];
int l;
while ((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
} finally {
reader.close();
}
String string = buffer.toString();
response.getEntity().consumeContent();
JSONArray data=new JSONArray(string);
if(data!=null){
if(data.length()>0){
JSONObject d=data.getJSONObject(0);
String comments=d.getString("comments");
String rt=d.getString("rt");
Button btn_gz=(Button)findViewById(R.id.btn_gz);
btn_gz.setText(" 轉發("+rt+")");
Button btn_pl=(Button)findViewById(R.id.btn_pl);
btn_pl.setText(" 評論("+comments+")");
}
}
}
catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
在上面的方法中對於微博中包含的圖片顯示尺寸進行了特別的處理,若是直接把獲取的圖片顯示在ImageView中,由於當圖片寬高超過手機屏幕的時候,系統會自動按照手機的屏幕按比例縮放圖片進行顯示,可是我發現一個現象圖片的高雖然是按照比例縮小了,可是圖片佔據的高仍舊是原來圖片的高度照成真實圖片和文字內容之間多了很高的一塊空白,這個現象很是的奇怪,因此我寫了以下方法進行處理:
view plaincopy to clipboardprint?
private void showImg(ImageView view,Drawable img){
int w=img.getIntrinsicWidth();
int h=img.getIntrinsicHeight();
Log.e("w", w+"/"+h);
if(w>300)
{
int hh=300*h/w;
Log.e("hh", hh+"");
LayoutParams para=view.getLayoutParams();
para.width=300;
para.height=hh;
view.setLayoutParams(para);
}
view.setImageDrawable(img);
}
private void showImg(ImageView view,Drawable img){
int w=img.getIntrinsicWidth();
int h=img.getIntrinsicHeight();
Log.e("w", w+"/"+h);
if(w>300)
{
int hh=300*h/w;
Log.e("hh", hh+"");
LayoutParams para=view.getLayoutParams();
para.width=300;
para.height=hh;
view.setLayoutParams(para);
}
view.setImageDrawable(img);
}
本篇到這裏就結束了,請繼續關注下一篇。
關於微博服務端API的OAuth認證明現
6 天前 上傳
下載附件 (18.96 KB)
新浪微博跟update相關的api已經掛了數日了一直沒有恢復正常,返回錯誤:40070 Error limited application access api!,新浪開放平臺的論壇裏n多的人都在等這個恢復,新浪官方也至關的噁心出問題了連個公告都沒有,既不說什麼緣由又不說何時能恢復。仍是有版主說是api正在升級禮拜1恢復正常今天都禮拜2了仍是不行。基於這個緣由個人android版的新浪微博客戶端已經停工好幾天了,恰好是跟update相關的一些功能。 客戶端開發不成了,就本身作作服務端程序,提供相似新浪微博rest api服務, api其實說簡單也很簡單了,沒法是經過連接對外提供json或者xml格式的數據和接收外部提供的數據進去相應的存儲、刪除、更新等操做。過程當中碰到的最麻煩的問題就是OAuth認證功能了,在作android版的新浪微博客戶端時候也花了蠻長的時間對OAuth認證進行研究,在客戶端原先是採用了oauth-signpost開源項目,後來因爲某些緣由就放棄了這個開源類庫,本身從新寫了OAuth認證部分的實現, 如今作服務端的OAuth認證,其實有過作客戶端的經驗作服務端也差很少,簡單的說無非是客戶端對參數字符串進行簽名而後把簽名值傳輸到服務端,服務端也對一樣對參數字符串進行簽名,把從客戶端傳過來的簽名值進去比較,簡單的說就這麼個過程,具體實現確定比這個要複雜多了,不明真相的同窗能夠google一下OAuth進行深刻的學習研究了。 服務端程序用asp.net和C#編寫了而非java,理由很簡單本人對.net更加熟悉。因爲想快速的實現效果採用了oauth-dot-net開源項目並無所有本身寫。
1、首先新建名爲Rest Api的ASP.NET Web應用程序,而後添加 oauth-dot-net開源項目相關的幾個dll(Castle.Core.dll、Castle.MicroKernel.dll、Castle.Windsor.dll、CommonServiceLocator.WindsorAdapter.dll、Microsoft.Practices.ServiceLocation.dll、OAuth.Net.Common.dll、OAuth.Net.Components.dll、OAuth.Net.ServiceProvider.dll)。
2、在Web.config文件裏添加相應的配置,具體能夠參考OAuth.Net.Examples.EchoServiceProvider項目,而後在Global.asax.cs添加以下代碼:
view plaincopy to clipboardprint?
public override void Init()
{
IServiceLocator injector =
new WindsorServiceLocator(
new WindsorContainer(
new XmlInterpreter(
new ConfigResource("oauth.net.components"))));
ServiceLocator.SetLocatorProvider(() => injector);
}
public override void Init()
{
IServiceLocator injector =
new WindsorServiceLocator(
new WindsorContainer(
new XmlInterpreter(
new ConfigResource("oauth.net.components"))));
ServiceLocator.SetLocatorProvider(() => injector);
}
接下來是比較重要,就是request_token、authorize、access_token的實現,OAuth認證明現的幾個過程,不理解能夠看android開發個人新浪微博客戶端-OAuth篇(2.1) ,具體代碼實現不少是參考OAuth.Net.Examples.EchoServiceProvider示例項目。
3、 首先新建ConsumerStore.cs類,用來存儲Consumer信息,因爲測試項目因此存儲在內存中並無考慮保存到數據庫,真實項目的時候請把相應的Consumer信息保存到數據庫中。Consumer信息對應新浪微博其實就是應用的App Key和App Secret,當開發者在新浪微博建一個新的應用獲取App Key和App Secret,因此完整的應該還須要一個開發一個提供給第三方開發者申請獲取App Key和App Secret的功能頁面,這裏就不具體實現,直接在代碼裏寫死了一個名爲測試應用的Consumer,App Key:2433927322,App Secret:87f042c9e8183cbde0f005a00db1529f,這個提供給客戶端測試用。 具體代碼以下:
view plaincopy to clipboardprint?
public sealed class ConsumerStore : InMemoryConsumerStore, IConsumerStore
{
internal static readonly IConsumer FixedConsumer = new OAuthConsumer("2433927322", "87f042c9e8183cbde0f005a00db1529f", "測試應用", ConsumerStatus.Valid);
public ConsumerStore()
{
this.ConsumerDictionary.Add(
ConsumerStore.FixedConsumer.Key,
ConsumerStore.FixedConsumer);
}
public override bool Add(IConsumer consumer)
{
throw new NotSupportedException("Consumers cannot be added to this store--it is fixed.");
}
public override bool Contains(string consumerKey)
{
return ConsumerStore.FixedConsumer.Key.Equals(consumerKey);
}
public override bool Update(IConsumer consumer)
{
throw new NotSupportedException("Consumers cannot be updated in this store--it is fixed.");
}
public override bool Remove(IConsumer consumer)
{
throw new NotSupportedException("Consumers cannot be removed from this store--it is fixed.");
}
}
public sealed class ConsumerStore : InMemoryConsumerStore, IConsumerStore
{
internal static readonly IConsumer FixedConsumer = new OAuthConsumer("2433927322", "87f042c9e8183cbde0f005a00db1529f", "測試應用", ConsumerStatus.Valid);
public ConsumerStore()
{
this.ConsumerDictionary.Add(
ConsumerStore.FixedConsumer.Key,
ConsumerStore.FixedConsumer);
}
public override bool Add(IConsumer consumer)
{
throw new NotSupportedException("Consumers cannot be added to this store--it is fixed.");
}
public override bool Contains(string consumerKey)
{
return ConsumerStore.FixedConsumer.Key.Equals(consumerKey);
}
public override bool Update(IConsumer consumer)
{
throw new NotSupportedException("Consumers cannot be updated in this store--it is fixed.");
}
public override bool Remove(IConsumer consumer)
{
throw new NotSupportedException("Consumers cannot be removed from this store--it is fixed.");
}
}
4、接下來就是request_token功能,新建RequestTokenHandler.cs ,這個是OAuth.Net.ServiceProvider.RequestTokenHandler子類,而且是httpHandlers因此須要在Web.config中添加httpHandlers配置,這個用來接收客戶端程序的請求,返回給客戶端程序Request Token和Request Secret用,具體代碼以下:
view plaincopy to clipboardprint?
public sealed class RequestTokenHandler : OAuth.Net.ServiceProvider.RequestTokenHandler
{
protected override void IssueRequestToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
//產生RequestToken
IRequestToken token = this.GenerateRequestToken(httpContext, requestContext);
requestContext.RequestToken = token;
Uri callbackUri;
if (Uri.TryCreate(requestContext.Parameters.Callback, UriKind.Absolute, out callbackUri))
{
if (!ServiceProviderContext.CallbackStore.ContainsCallback(token))
{
//保存Callback地址了
ServiceProviderContext.CallbackStore.AddCallback(token, callbackUri);
}
}
else
OAuthRequestException.ThrowParametersRejected(new string[] { Constants.CallbackParameter }, "Not a valid Uri.");
//把token.Token和token.Secret輸出到客戶端,
requestContext.ResponseParameters[Constants.TokenParameter] = token.Token;
requestContext.ResponseParameters[Constants.TokenSecretParameter] = token.Secret;
}
protected override IRequestToken GenerateRequestToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
return ServiceProviderContext.TokenGenerator.CreateRequestToken(requestContext.Consumer, requestContext.Parameters);
}
}
public sealed class RequestTokenHandler : OAuth.Net.ServiceProvider.RequestTokenHandler
{
protected override void IssueRequestToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
//產生RequestToken
IRequestToken token = this.GenerateRequestToken(httpContext, requestContext);
requestContext.RequestToken = token;
Uri callbackUri;
if (Uri.TryCreate(requestContext.Parameters.Callback, UriKind.Absolute, out callbackUri))
{
if (!ServiceProviderContext.CallbackStore.ContainsCallback(token))
{
//保存Callback地址了
ServiceProviderContext.CallbackStore.AddCallback(token, callbackUri);
}
}
else
OAuthRequestException.ThrowParametersRejected(new string[] { Constants.CallbackParameter }, "Not a valid Uri.");
//把token.Token和token.Secret輸出到客戶端,
requestContext.ResponseParameters[Constants.TokenParameter] = token.Token;
requestContext.ResponseParameters[Constants.TokenSecretParameter] = token.Secret;
}
protected override IRequestToken GenerateRequestToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
return ServiceProviderContext.TokenGenerator.CreateRequestToken(requestContext.Consumer, requestContext.Parameters);
}
}
5、 接着是authorize功能,新建名爲authorize.aspx的頁面,用來給用戶輸入帳號和密碼進行受權的頁面,這個頁面很簡單具體以下圖,在這個頁面中獲取用戶輸入的帳戶和密碼跟數據庫中存儲的用戶帳號和密碼進行驗證,若是驗證經過返回以前客戶端提供的callback地址,而且給這個地址添加一個校驗碼,具體代碼以下:
view plaincopy to clipboardprint?
public partial class authorize : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
if (loginName.Text == "test" && password.Text == "123")
{
string toke = Request.Params["oauth_token"];
IRequestToken tk = ServiceProviderContext.TokenStore.GetRequestToken(toke);
Uri callback = ServiceProviderContext.CallbackStore.GetCalback(tk);
string oauth_verifier = ServiceProviderContext.VerificationProvider.Generate(tk);
Response.Redirect(callback.ToString() + "?oauth_verifier=" + oauth_verifier);
}
}
}
public partial class authorize : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
if (loginName.Text == "test" && password.Text == "123")
{
string toke = Request.Params["oauth_token"];
IRequestToken tk = ServiceProviderContext.TokenStore.GetRequestToken(toke);
Uri callback = ServiceProviderContext.CallbackStore.GetCalback(tk);
string oauth_verifier = ServiceProviderContext.VerificationProvider.Generate(tk);
Response.Redirect(callback.ToString() + "?oauth_verifier=" + oauth_verifier);
}
}
}
6、接下來就是access_token功能,新建AccessTokenHandler.cs , 這個是OAuth.Net.ServiceProvider.AccessTokenHandler子類,而且是httpHandlers因此須要在Web.config中添加httpHandlers配置,這個用來接收客戶端程序的請求,返回給客戶端程序Access Token和Access Secret用,具體代碼以下:
view plaincopy to clipboardprint?
public sealed class AccessTokenHandler : OAuth.Net.ServiceProvider.AccessTokenHandler
{
protected override void IssueAccessToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
//產生access token
IAccessToken accessToken = this.GenerateAccessToken(httpContext, requestContext);
accessToken.Status = TokenStatus.Authorized;
// 把accessToken和accessSecret輸出到客戶端,
requestContext.ResponseParameters[Constants.TokenParameter] = accessToken.Token;
requestContext.ResponseParameters[Constants.TokenSecretParameter] = accessToken.Secret;
}
protected override IAccessToken GenerateAccessToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
return ServiceProviderContext.TokenGenerator.CreateAccessToken(requestContext.Consumer, requestContext.RequestToken);
}
}
public class TokenGenerator : ITokenGenerator
{
internal static readonly IRequestToken FixedRequestToken = new OAuthRequestToken("requestkey",
"requestsecret",
ConsumerStore.FixedConsumer,
TokenStatus.Authorized,
null,
ServiceProviderContext.DummyIdentity,
new string[] { });
internal static readonly IAccessToken FixedAccessToken = new OAuthAccessToken(
"accesskey",
"accesssecret",
ConsumerStore.FixedConsumer,
TokenStatus.Authorized,
TokenGenerator.FixedRequestToken);
public IRequestToken CreateRequestToken(IConsumer consumer, OAuthParameters parameters)
{
return TokenGenerator.FixedRequestToken;
}
public IAccessToken CreateAccessToken(IConsumer consumer, IRequestToken requestToken)
{
return TokenGenerator.FixedAccessToken;
}
}
public class TokenStore : InMemoryTokenStore, ITokenStore
{
public TokenStore()
{
this.RequestTokenDictionary.Add(
TokenGenerator.FixedRequestToken.Token,
TokenGenerator.FixedRequestToken);
this.AccessTokenDictionary.Add(
TokenGenerator.FixedAccessToken.Token,
TokenGenerator.FixedAccessToken);
}
public override bool Add(IRequestToken token)
{
throw new NotSupportedException("Tokens cannot be added to the token store--it is fixed.");
}
public override bool Add(IAccessToken token)
{
throw new NotSupportedException("Tokens cannot be added to the token store--it is fixed.");
}
public override bool Update(IRequestToken token)
{
throw new NotSupportedException("Tokens cannot be updated in the token store--it is fixed.");
}
public override bool Update(IAccessToken token)
{
throw new NotSupportedException("Tokens cannot be updated in the token store--it is fixed.");
}
public override bool Remove(IRequestToken token)
{
throw new NotSupportedException("Tokens cannot be removed from the token store--it is fixed.");
}
public override bool Remove(IAccessToken token)
{
throw new NotSupportedException("Tokens cannot be removed from the token store--it is fixed.");
}
}
public sealed class AccessTokenHandler : OAuth.Net.ServiceProvider.AccessTokenHandler
{
protected override void IssueAccessToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
//產生access token
IAccessToken accessToken = this.GenerateAccessToken(httpContext, requestContext);
accessToken.Status = TokenStatus.Authorized;
// 把accessToken和accessSecret輸出到客戶端,
requestContext.ResponseParameters[Constants.TokenParameter] = accessToken.Token;
requestContext.ResponseParameters[Constants.TokenSecretParameter] = accessToken.Secret;
}
protected override IAccessToken GenerateAccessToken(HttpContext httpContext, OAuthRequestContext requestContext)
{
return ServiceProviderContext.TokenGenerator.CreateAccessToken(requestContext.Consumer, requestContext.RequestToken);
}
}
public class TokenGenerator : ITokenGenerator
{
internal static readonly IRequestToken FixedRequestToken = new OAuthRequestToken("requestkey",
"requestsecret",
ConsumerStore.FixedConsumer,
TokenStatus.Authorized,
null,
ServiceProviderContext.DummyIdentity,
new string[] { });
internal static readonly IAccessToken FixedAccessToken = new OAuthAccessToken(
"accesskey",
"accesssecret",
ConsumerStore.FixedConsumer,
TokenStatus.Authorized,
TokenGenerator.FixedRequestToken);
public IRequestToken CreateRequestToken(IConsumer consumer, OAuthParameters parameters)
{
return TokenGenerator.FixedRequestToken;
}
public IAccessToken CreateAccessToken(IConsumer consumer, IRequestToken requestToken)
{
return TokenGenerator.FixedAccessToken;
}
}
public class TokenStore : InMemoryTokenStore, ITokenStore
{
public TokenStore()
{
this.RequestTokenDictionary.Add(
TokenGenerator.FixedRequestToken.Token,
TokenGenerator.FixedRequestToken);
this.AccessTokenDictionary.Add(
TokenGenerator.FixedAccessToken.Token,
TokenGenerator.FixedAccessToken);
}
public override bool Add(IRequestToken token)
{
throw new NotSupportedException("Tokens cannot be added to the token store--it is fixed.");
}
public override bool Add(IAccessToken token)
{
throw new NotSupportedException("Tokens cannot be added to the token store--it is fixed.");
}
public override bool Update(IRequestToken token)
{
throw new NotSupportedException("Tokens cannot be updated in the token store--it is fixed.");
}
public override bool Update(IAccessToken token)
{
throw new NotSupportedException("Tokens cannot be updated in the token store--it is fixed.");
}
public override bool Remove(IRequestToken token)
{
throw new NotSupportedException("Tokens cannot be removed from the token store--it is fixed.");
}
public override bool Remove(IAccessToken token)
{
throw new NotSupportedException("Tokens cannot be removed from the token store--it is fixed.");
}
}
這樣就完成了一個最最簡單小型的服務端OAuth認證,而後用android客戶端進行測試ok經過。 注意點: 1、android模擬器訪問本地服務地址爲10.0.2.2,好比http://localhost:3423/authorize.aspx在模擬器中用http://10.0.2.2:3423/authorize.aspx。 2、OAuth.Net類庫的OAuth.Net.Common項目中的interface ICallbackStore 添加了一個Uri GetCalback(IRequestToken token);而且在具體的實現類InMemoryCallbackStore添加了實習代碼: public Uri GetCalback(IRequestToken token) {
lock (this.callbackStore)
{
if (this.callbackStore.ContainsKey(token))
{
return this.callbackStore[token];
}
else
{
return null;
}
}
}
3、爲了能用我前面作的給新浪用的android客戶端,對於類庫源代碼AccessTokenHandler的ParseParameters方法作了以下修改,由於新浪請求api的時候都會加一個source的參數: protected virtual void ParseParameters(HttpContext httpContext, OAuthRequestContext requestContext) {
.......
parameters.AllowOnly(
Constants.ConsumerKeyParameter,
Constants.TokenParameter,
Constants.SignatureMethodParameter,
Constants.SignatureParameter,
Constants.TimestampParameter,
Constants.NonceParameter,
Constants.VerifierParameter,
Constants.VersionParameter, // (optional)
Constants.RealmParameter, // (optional)
"source");
......
}
android開發個人新浪微博客戶端-大圖瀏覽以及保存篇(7)
6 天前 上傳
下載附件 (129.72 KB)
6 天前 上傳
下載附件 (73.8 KB) 在閱讀微博的功能篇中,若是微博包含了圖片就會在微博正文下面顯示該張圖片,可是這個圖片只是張縮略圖,這樣就須要提供一個能放大縮小查看這張圖片的功能,當點擊正文中的縮略圖的時候顯示一個簡單的圖片瀏覽器功能,提供圖片的放大、縮小、拖拽操做方便用戶查看圖片,同時也提供保存圖片到手機的功能。本功能的UI比較簡單就不單獨分篇講了,具體的實現效果如上圖。
新建ImageActivity.java做爲圖片瀏覽Activity,在res/layout下新建image.xml的Layout做爲圖片瀏覽的佈局文件,image.xml佈局代碼很簡單了就不詳細解釋了直接貼代碼:
view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="41px"
android:background="@drawable/imagebar_bg">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="2">
<Button
android:id="@+id/returnBtn"
android:layout_width="63px"
android:layout_height="29px"
android:layout_centerInParent="true"
android:text="返回"
android:textColor="#ffffff"
android:background="@drawable/btn1_bg">
</Button>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="瀏覽圖片"
android:textColor="#ffffff">
</TextView>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="2">
<Button
android:id="@+id/downBtn"
android:layout_width="60px"
android:layout_height="29px"
android:layout_centerInParent="true"
android:text="下載"
android:textColor="#ffffff"
android:background="@drawable/btn2_bg">
</Button>
</RelativeLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<MySinaWeiBo.ui.ImageZoomView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pic"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</MySinaWeiBo.ui.ImageZoomView>
<ZoomControls
android:id="@+id/zoomCtrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true">
</ZoomControls>
</RelativeLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="41px"
android:background="@drawable/imagebar_bg">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="2">
<Button
android:id="@+id/returnBtn"
android:layout_width="63px"
android:layout_height="29px"
android:layout_centerInParent="true"
android:text="返回"
android:textColor="#ffffff"
android:background="@drawable/btn1_bg">
</Button>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="瀏覽圖片"
android:textColor="#ffffff">
</TextView>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="2">
<Button
android:id="@+id/downBtn"
android:layout_width="60px"
android:layout_height="29px"
android:layout_centerInParent="true"
android:text="下載"
android:textColor="#ffffff"
android:background="@drawable/btn2_bg">
</Button>
</RelativeLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<MySinaWeiBo.ui.ImageZoomView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pic"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</MySinaWeiBo.ui.ImageZoomView>
<ZoomControls
android:id="@+id/zoomCtrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true">
</ZoomControls>
</RelativeLayout>
</LinearLayout>
上面的代碼中用到了一個自定義控件MySinaWeiBo.ui.ImageZoomView,這個就是整個功能的核心部分,用來實現圖片的放大、縮小、拖拽的一個圖片顯示控件,這個控件非我原創,是參考了Android one finger zoom tutorial 這篇博客寫出來的,因此我在這裏也不貼實現代碼了,有興趣的你們能夠直接看看這個文章。 接下要作的就是用這個ImageZoomView來顯示圖片,在閱讀微博內容的頁面中當點擊內容中的縮略圖片的時候會把這個縮略圖對應的原圖的url傳給當前的這個ImageActivity,那麼在ImageActivity的onCreate方法中根據這個url獲取圖片而且設置給ImageZoomView。在onCreate方法中代碼以下:
view plaincopy to clipboardprint?
@Override
public void onCreate(Bundle savedInstanceState) {
。。。。。
Intent i=this.getIntent();
if(i!=null){
Bundle b=i.getExtras();
if(b!=null){
if(b.containsKey("url")){
String url = b.getString("url");
mZoomView=(ImageZoomView)findViewById(R.id.pic);
Drawable img= AsyncImageLoader.loadImageFromUrl(url);
image=drawableToBitmap(img);
mZoomView.setImage(image);
mZoomState = new ZoomState();
mZoomView.setZoomState(mZoomState);
mZoomListener = new SimpleZoomListener();
mZoomListener.setZoomState(mZoomState);
mZoomView.setOnTouchListener(mZoomListener);
resetZoomState();
}
}
}
。。。。。。
}
@Override
public void onCreate(Bundle savedInstanceState) {
。。。。。
Intent i=this.getIntent();
if(i!=null){
Bundle b=i.getExtras();
if(b!=null){
if(b.containsKey("url")){
String url = b.getString("url");
mZoomView=(ImageZoomView)findViewById(R.id.pic);
Drawable img= AsyncImageLoader.loadImageFromUrl(url);
image=drawableToBitmap(img);
mZoomView.setImage(image);
mZoomState = new ZoomState();
mZoomView.setZoomState(mZoomState);
mZoomListener = new SimpleZoomListener();
mZoomListener.setZoomState(mZoomState);
mZoomView.setOnTouchListener(mZoomListener);
resetZoomState();
}
}
}
。。。。。。
}
view plaincopy to clipboardprint?
private void resetZoomState() {
mZoomState.setPanX(0.5f);
mZoomState.setPanY(0.5f);
final int mWidth = image.getWidth();
final int vWidth= mZoomView.getWidth();
Log.e("iw:",vWidth+"");
mZoomState.setZoom(1f);
mZoomState.notifyObservers();
}
public Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = ((BitmapDrawable)drawable).getBitmap();
return bitmap;
}
private void resetZoomState() {
mZoomState.setPanX(0.5f);
mZoomState.setPanY(0.5f);
final int mWidth = image.getWidth();
final int vWidth= mZoomView.getWidth();
Log.e("iw:",vWidth+"");
mZoomState.setZoom(1f);
mZoomState.notifyObservers();
}
public Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = ((BitmapDrawable)drawable).getBitmap();
return bitmap;
}
view plaincopy to clipboardprint?
ZoomControls zoomCtrl = (ZoomControls) findViewById(R.id.zoomCtrl);
zoomCtrl.setOnZoomInClickListener(new OnClickListener(){
@Override
public void onClick(View view) {
float z= mZoomState.getZoom()+0.25f;
mZoomState.setZoom(z);
mZoomState.notifyObservers();
}
});
zoomCtrl.setOnZoomOutClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
float z= mZoomState.getZoom()-0.25f;
mZoomState.setZoom(z);
mZoomState.notifyObservers();
}
});
ZoomControls zoomCtrl = (ZoomControls) findViewById(R.id.zoomCtrl);
zoomCtrl.setOnZoomInClickListener(new OnClickListener(){
@Override
public void onClick(View view) {
float z= mZoomState.getZoom()+0.25f;
mZoomState.setZoom(z);
mZoomState.notifyObservers();
}
});
zoomCtrl.setOnZoomOutClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
float z= mZoomState.getZoom()-0.25f;
mZoomState.setZoom(z);
mZoomState.notifyObservers();
}
});
這樣一個簡單的圖片瀏覽器功能就完成了,支持放大縮小而且還能拖拽,基本上達到應用需求。