android开发新浪微博客户端 完整攻略 [新手必读][转]
开发第一件事情,那就是开发工具以及环境,我的配置是Eclipse Helios (3.6.1) + Adroid2.2,具体的环境搭建我就不罗嗦了,google一下一大堆,光博客园里都能搜到很多篇了。 开发第二件事情,既然是开发新浪的微博客户端,那就先去新浪申请微博账号然后登陆后到新浪的开放平台,新浪的开放平台提供的新浪微博对外的api接口,在我的应用中创建一个新的应用获取App Key和App Secret,这2个值后面会有用到先记录下来。在新浪的开放平台中提供了开发文档、SDK、接口测试工具等,本人决定直接通过新浪的Rest Api进行开发并不打算使用新浪提供的SDK,据说新浪提供的java版的SDK并不能直接用来进行android的开发需要进行一定的修改才能使用,只是听说我没有试过不一定准确。 最后在说一下,我准备分为UI和功能两部分分别进行说明讲解,据我自己的情况大部分的时间都花在的UI的设计和实现上了,编码倒反而工作量小多了,所以特别把UI部分分出来讲。
最后还要在说一下,很抱歉上面内容基本上属于废话没有什么实质内容了但是既然是第一篇还是得象征性的交代一下,从下篇开始讲具体的内容。
本软件设定用户第一个接触到的功能就是页面载入等待功能,这个功能对使用者来说就是一个持续1、2秒钟的等待页面,在用户等待的同时程序做一些必要的检查以及数据准备工作,载入页面分为UI篇和功能篇,从表及里首先是UI的实现,一个软件除功能之外还得有一个光鲜的外表也是非常重要的,尽管本人设计水平一般但是还是亲自操刀用ps先做了一下设计效果图如下:
一、接下来的任务就是在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系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的图片,在开发程序时为了兼容不同平台不同屏幕,建议各自文件夹根据需求均存放不同版本图片,我这里就不进行这么多的考虑了。
二、完成图片资源的准备后接下就是layout文件的编写, 在res/layout文件夹下新建main.xml文件,这个layout采用LinearLayout控件作为顶层控件,然后用ImageView控件分别实现版本号图片顶部靠左对齐显示、软件名称和图标图片居中对齐、作者名称和blog图片底部靠右对齐。注意在版本号图片显示ImageView控件下面添加一个RelativeLayout控件作为软件名称和图标图片ImageVIew和作者名称和blog图片ImageView的父控件用来控制居中对齐已经底部对齐的实现,具体代码如下:代码
- <?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>
复制代码
三、在ec打开名为MainActivity的Activity源代码文件进行编辑,onCreate部分代码如下:
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- }
复制代码
然后运行项目可以在模拟器中显示,上面的几个图片都按照设计的位置和效果进行显示只是整个页面的背景还是黑色的,接下来就是背景部分的显示实现,由于为了实现横竖屏切换显示,背景图的显示采用代码进行控制显示,首先用如下方法获取当前手机是横屏还是竖屏:
- //获取屏幕方向
- 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的公共方法用来实现屏幕背景的自动切换,后面的几乎每一个功能页面都需要用到这个方法
- 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方法进行屏幕自动切换:
- LinearLayout layout=(LinearLayout)findViewById(R.id.layout);
- //背景自动适应
- AndroidHelper.AutoBackground(this, layout, R.drawable.bg_v, R.drawable.bg_h);
复制代码
到此完成了载入页面的UI部分的实现,测试运行模拟器中查看效果,基本上跟最上面的设计效果图相符,测试效果图如下:
通过上一篇文章(android开发我的新浪微博客户端-载入页面UI篇(1.1))已经完成了载入页面的UI部分的实现,效果如上图,接下来在上面的基础上完成载入页面的功能代码。
首先说明一下新浪微博提供了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数据表的创建、更新等,代码如下:
- 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类文件实现用户记录的创建、更新、删除等,代码如下:
- 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方法添加代码:
- 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){
- ......
- }
- }
复制代码
关于载入页面的sqlite就说到这里了,下一篇说说OAuth认证实现。
android开发我的新浪微博客户端-OAuth篇(2.1)
本篇说说关于OAuth授权认证的事情,新浪开放api都必须在这个基础上才能调用,所以有必要专门来讲讲,前面的文章中已经提到过关于新浪微博提供了OAuth和Base OAuth两种认证方式,并且本项目采用OAuth认证方式,至于为什么采用这个OAuth认证而不采用Base OAuth认证原因很简单,自从Twitter只支持OAuth认证方式以来,各大应用都纷纷转向OAuth认证方式,而新浪微博的开放平台也将在近日停止Base OAuth的认证方式。 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开源项目简单了很多。具体代码如下:
复制代码 这样就完成了OAuth功能类的开发,后面都会用到这个类相关的方法。本篇到这里就算是完结请继续关注后面的文章。 |
android开发我的新浪微博客户端-用户授权页面UI篇(3.1)
上一篇讲了讲OAuth授权认证的事情,大概的介绍了OAuth的原理,并且完成了一个OAuth.java的类库,提供了几个OAuth认证必要的方法,本篇开始具体讲本项目的用户授权功能,用户授权页面是当用户第一次使用本软件的时候自动从载入页面跳转过来的显示的页面,涉及OAuth认证相关都是在上一篇的OAuth.java的类基础上开发。用户授权页面分为UI篇和功能篇两篇,本篇先来讲讲UI的实现,这次就不贴PS的效果图了直接贴实现后的功能截图如下: 看上面的图,其实这个页面的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:
复制代码 接下来是本文的重点部分,半透明弹窗用Dialog控件进行实现,首先为这个半透明弹窗新建一个名为dialog.xml的Layout,这个Layout主要是对4个元素进行布局,如图所示分别为i小图标、信息提示、中间文字、开始按钮,首先用LinearLayout对i小图标和信息提示进行水平布局,中间文字以一个TextView跟在下面,对于开始按钮是用RelativeLayout进行底部对齐显示。具体代码如下:
复制代码 完成了半透明弹窗的Layout定义接下来我们要做的就是为它写一个自定义样式来实现我们想要的显示效果,首先我们需准备一个圆角的半透明png图片名为dia_bg.png并且添加到drawable中,接下来再res/values文件夹新建名为 dialogStyle.xml的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方法添加如下代码:
复制代码 最后运行查看效果,到这里我们的任务已经完成了。请关注下一篇功能篇。 |
android开发我的新浪微博客户端-用户授权页面功能篇(3.2)
复制代码 上面的代码中重点来说明一下 RequestAccessToken方法的第二参数CallBackUrl,这个参数是用户在新浪的页面中输入账户密码后完成认证后返回的地址,我这里是这样设置的CallBackUrl = "myapp://AuthorizeActivity",在AndroidManifest.xml中配置给AuthorizeActivity添加如下配置把myapp://AuthorizeActivity指向到AuthorizeActivity,这样当页面返回到AuthorizeActivity中就可以获取到传过来的oauth_verifier参数。
复制代码 再AuthorizeActivity如果来接收返回的oauth_verifier参数呢?接下来在AuthorizeActivity添加如下方法:
复制代码 关于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添加如下代码:
复制代码 通过上面的代码完成了User_id、Access Token和Access Secret 获取并且保存到了sqlite库中,这样就完成了用户的OAuth认证,当需要调用新浪的api时只需要去sqlite库中找该用户的User_id、Access Token和Access Secret 即可。到这里本篇就结束了,请关注下一篇。 |
首先回顾一下功能流程当用户开启软件显示载入页面时程序首先去sqlite库查询是否已经保存有用户的新浪微博的UserID号、Access Token、Access Secret的记录如果没有一条记录那么跳转到用户授权功能页面,这个已经由上面两篇文章实现了,如果有记录那么页面跳转到用户登录页面,也就是本篇以及下篇要实现的功能,本篇讲UI的实现,本项目支持多微博账号了,也就是用户可以设置多个微博账号,登录的时候选择其中的一个登录,具体效果如上图,新建名LoginActivity.java的Activity并且在AndroidManifest.xml中进行相应配置,这个页面就是我们要实现的用户登录页面。
看上面的效果,首先页面分3部分实现,背景部分、底部菜单部分、用户选择以及头像显示部分,首先在res/layout的目录下新建名为login.xml的layout,然后根据页面显示要求编写如下的布局控制:
- <?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的样式,具体解释可以参考前面的户授权验证页面功能,内容如下:
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <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>
- </style>
- </resources>
复制代码
接下来还需要定义选择列表的layout,新建名为dialog2.xml的layout文件,内容如下:
- <?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方法中添加如下代码:
- 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控件来显示账号列表,首先是从数据库中获取所有的账户记录然后设置默认选中的用户账号代码如下:
复制代码 这个initUser() 初始账号的方法在LoginActivity的onCreate中调用,主要完成两件事情,第一件获取通过userList = dbHelper.GetUserList(false);获取所有的账户记录,关于DataHelper前面已经有说过了,如果获取的用户记录为空那么就跳转到用户授权功能页面让用户添加账号,如果不为空那么通过SharedPreferences去读取用户上一次选择的账号名称,如果没有或者数据库里账号记录不包括这个账户名称那么默认显示记录的第一个账号和头像,如果有那么显示这个账户的名称和头像。关于SharedPreferences,是android提供给开发者用来存储一些简单的数据用的,非常方便类似于网站的Cookie,在这里我就是用这个来保存上一次用户选择的是哪个账号,非常实用。
复制代码 接下就是为这个ListView设定数据源Adapter,在账号选择窗口显示的时候进行设置,添加到id为iconSelectBtn的ImageButton的OnClickListener中代码如下:
复制代码 通过上面代码完成了账号选择的功能,接下来给id为login的ImageButton添加OnClickListener,使得点击后以当前选择账号进入微博首页,代码如下:
复制代码 在上面的GoHome方法中ConfigHelper.nowUser是类型为UserInfo的static类型用来保存当前登录账号的信息,替代web中session使用。
复制代码 至此登录页面功能篇结束,请继续关注下一篇。 |
android开发我的新浪微博客户端-用户首页面UI篇(5.1)
在前篇完成了用户登录功能后开始用户首页的开发,用户的首页主要的内容是当前登录用户关注的微博列表,本篇先来讲讲UI的实现,效果如上图,整个页面分为上、中、下三部分,上面部分是工具条,显示当前登录用户的昵称以及写微博、刷新两个功能按钮;中间部分是当前用户关注的最新微博列表,下面部分是功能切换栏,用来进行各个功能之间的切换。 首先新建名为HomeActivity.java的Activity作为用户首页,然后在res/layout目录下新建名为home.xml的Layout,具体代码如下:
复制代码 这个布局首先是一个竖直的根LinearLayout,在这个根LinearLayout里面分别是两个RelativeLayout, 第一个RelativeLayout 用来显示页面的工具条,第二个RelativeLayout用来显示列表以及底部的功能栏,特别主要在这第二个RelativeLayout中有一个id为loadingLayout的LinearLayout是用来显示数据载入中的动画,它的android:visibility属性为invisible(也可以设置成gone,区别:invisible这个View在ViewGroupt中仍保留它的位置,不重新layout android:id="@+id/loading" android:layout_gravity="center" style="@style/progressStyle">
复制代码 接着准备好r1.png - r8.png, 八张不同的小图片分别代表每旋转45度图片,八张刚好是360度。把这些图片添加到res/drawable-mdpi目录中。然后在res/anim目录下新建名为loading.xml动画文件,内容如下:
复制代码 关于Android播放动画实现我是参考http://www.eoeandroid.com/forum.php?mod=viewthread&tid=67311&extra= |
上一篇完成用户首页的UI实现,本篇接下来讲功能部分的实现,本页面主要的功能就用户关注的最新微博列表,从上一篇中知道本列表是用ID为Msglist的ListView控件来实现,本篇的主要就讲解如果获取微博列表数据给这个ListView提供显示数据。ListView每一条子数据分别由用户头像、用户昵称、发布时间、是否包含照片、微博内容这五部分组成,根据这五部分定义一个名为WeiBoInfo.java实体类,代码如下:
- 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子项的显示部件,代码很简单不多解释了,直接看下面代码:
- <?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,代码如下:
- 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的代码如下:
- 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();代码如下:
- @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)
上一篇完成了微博列表的功能,本篇接着做预读微博的功能,本篇主要讲讲UI部分的实现,最终实现的效果如上图所示。整个显示页面从上往下分为四部分,第一部分顶部工具条、第二部分作者头像和名称、第三部分微博正文、第四部分功能按钮区。新建名为ViewActivity.java作为阅读微博的页面,再res/layout目录下新建名为view.xml的Layout,代码如下:
复制代码 上面这个布局实现起来并不复杂, 主要看看功能按钮区的4个按钮的点击上去的切换背景的效果,以关注按钮为例子看这行设置,android:background="@drawable/lt_selector",在res/drawable-mdpi目录下新建名为lt_selector.xml用来实现点击上去切换图片的效果,具体代码如下:
复制代码 本篇虽然看layout文件非常的长,其实仔细看看非常的简单了没有什么难和复杂的了,就是按照前面的经验控制好图片以及控件的显示位置和样式即可,本篇中用了一个ScrollView控件这个是前面没有用到过的,主要是用来当微博的内容超出显示区域的时候出现滚动条用的这个非常容易使用,所以就简单写一下到此结束了,请继续关注下一篇阅读微博的功能篇。
关于微博服务端API的OAuth认证实现 新浪微博跟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开源项目并没有全部自己写。 一、首先新建名为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)。 二、在Web.config文件里添加相应的配置,具体可以参考OAuth.Net.Examples.EchoServiceProvider项目,然后在Global.asax.cs添加如下代码:
复制代码 接下来是比较重要,就是request_token、authorize、access_token的实现,OAuth认证实现的几个过程,不理解可以看android开发我的新浪微博客户端-OAuth篇(2.1) ,具体代码实现很多是参考OAuth.Net.Examples.EchoServiceProvider示例项目。
复制代码 四、接下来就是request_token功能,新建RequestTokenHandler.cs ,这个是OAuth.Net.ServiceProvider.RequestTokenHandler子类,并且是httpHandlers所以需要在Web.config中添加httpHandlers配置,这个用来接收客户端程序的请求,返回给客户端程序Request Token和Request Secret用,具体代码如下:
复制代码 五、 接着是authorize功能,新建名为authorize.aspx的页面,用来给用户输入账号和密码进行授权的页面,这个页面很简单具体如下图,在这个页面中获取用户输入的账户和密码跟数据库中存储的用户账号和密码进行验证,如果验证通过返回之前客户端提供的callback地址,并且给这个地址添加一个校验码,具体代码如下:
复制代码 六、接下来就是access_token功能,新建AccessTokenHandler.cs , 这个是OAuth.Net.ServiceProvider.AccessTokenHandler子类,并且是httpHandlers所以需要在Web.config中添加httpHandlers配置,这个用来接收客户端程序的请求,返回给客户端程序Access Token和Access Secret用,具体代码如下:
复制代码 这样就完成了一个最最简单小型的服务端OAuth认证,然后用android客户端进行测试ok通过。 注意点: 一、android模拟器访问本地服务地址为10.0.2.2,比如http://localhost:3423/authorize.aspx在模拟器中用http://10.0.2.2:3423/authorize.aspx。 二、OAuth.Net类库的OAuth.Net.Common项目中的interface ICallbackStore 添加了一个Uri GetCalback(IRequestToken token);并且在具体的实现类InMemoryCallbackStore添加了实习代码: public Uri GetCalback(IRequestToken token) { 三、为了能用我前面做的给新浪用的android客户端,对于类库源代码AccessTokenHandler的ParseParameters方法做了如下修改,因为新浪请求api的时候都会加一个source的参数: protected virtual void ParseParameters(HttpContext httpContext, OAuthRequestContext requestContext) { ......
|
android开发新浪微博客户端 完整攻略 [新手必读][转]相关推荐
- android开发新浪微博客户端 完整攻略 [新手必读]
android开发新浪微博客户端 完整攻略 [新手必读][转]2011-04-06 10:49:19 http://www.eoeandroid.com/forum-viewthread-tid-6 ...
- android开发新浪微博客户端 完整攻略
http://www.eoeandroid.com/forum-viewthread-tid-67298-fromuid-106432.html 开始接触学习android已经有3个礼拜了,一直都是对 ...
- 【转载】android开发新浪微博客户端 完整攻略
开始接触学习android已经有3个礼拜了,一直都是对着android的sdk文档写Tutorials从Hello World到Notepad Tutorial算是初步入门了吧,刚好最近对微博感兴趣就 ...
- android开发新浪微博客户端
android开发新浪微博客户端 完整攻略 [新手必读][转]2011-04-06 10:49:19 http://www.eoeandroid.com/forum-viewthread-tid-6 ...
- 时空之轮Android手柄,时空之轮图文完整攻略(超时空之轮(ChronoTrigger)最详细攻略图文详解)...
时空之轮图文完整攻略(超时空之轮(ChronoTrigger)最详细攻略图文详解),哪吒游戏网给大家带来详细的时空之轮图文完整攻略(超时空之轮(ChronoTrigger)最详细攻略图文详解)介绍,大 ...
- Android开发屏幕适配全攻略
Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因.重要概念.解决方案及最佳实践,我相信如果你能认真的学习 ...
- android 启动新浪客户端,android开发新浪微博客户端
[实例简介] [实例截图] [核心代码] package weibo4andriod.examples; import java.io.*; import java.net.*; import wei ...
- 美服行星边际2服务器维护时间,行星边际2美服证书 快速起步攻略新手必读
这几天我自己体验了下美服,总感觉6天1000点还是比较慢!我们接下来先看看如何快速起步! 1.利用好每隔8小时不同载具武器及步兵武器的体验功能! 正如上面所描述的,我们要利用好这个功能,把枪用在刀刃上 ...
- android4.2.2系统投屏,一学就会!手机投屏电视完整攻略
原标题:一学就会!手机投屏电视完整攻略 想在电视上玩<王者荣耀>?想弄明白怎样投屏?看完这篇文章,你就会了~ 目前主流的投屏技术有以下三种:DLNA,airplay,miracast技术, ...
最新文章
- Spring AOP无法拦截内部方法调用-- expose-proxy=true用法
- c++,当const char*为0时,不能将其直接赋给string
- Spring MVC控制器的单元测试:配置
- [js] 你有使用过pjax吗?它的原理是什么?
- oracle中错位函数,Oracle中的一些函数
- 用Canvas创造一个太阳系
- [论文阅读] Cost-Effective REgion-based Active Learning for Semantic Segmentation
- JVM初识之常用参数配置
- 使用polar si9000计算差分阻抗
- python爬虫:批量下载qq空间里的照片(二)
- 百度——测试开发实习生面试记录
- 学术捜索新添找寻新近文章功能
- Cesium资料大集合
- python画国旗和八卦图
- 可鸡的三大充要条件来了!!
- 怎么读取照片内的文字
- c语言 int类型转换为string类型
- MATLAB:三阶矩阵约当阵,能控,能观标准型转化
- FMX探索之IMAGE控件上输出
- 俺的作品也开始有盗版了... hiahia... 奇怪, 为什么我反而很得意涅...