浏览 8078 次
锁定老帖子 主题:人人网官方android客户端源码分析
精华帖 (0) :: 良好帖 (3) :: 新手帖 (6) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-10-29
最后修改:2011-10-31
ContentProvider是不同应用程序之间进行数据交换的标准API,ContentProvider以某种Uri的形式对外提供数据,允许其他应用访问或修改数据;其他应用程序使用ContentResolver根据Uri去访问操作指定数据。 人人网android客户端也是使用ContentProvider对需要保存于Android客户端的数据进行管理。 1. renren.db SQLLiteOpenHelper是Android提供的一个管理数据库的工具类,可用于管理数据库的创建和版本更新。一般的用法是创建SQLiteOpenHelper的子类,并扩展它的onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion)方法。 人人网Android客户端使用该方法创建及修改用户手机中的人人网数据库(renren.db)。 下面是RenRenProvider$DatabaseHelper的代码: public class RenRenProvider$DatabaseHelper extends SQLiteOpenHelper { public RenRenProvider$DatabaseHelper(Context context) { super(context, "renren.db", null, 71); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE pic (_id INTEGER PRIMARY KEY,url TEXT UNIQUE ON CONFLICT REPLACE,_data TEXT,size INTEGER);"); db.execSQL("CREATE TABLE account (_id INTEGER PRIMARY KEY,uid INTEGET,account TEXT UNIQUE ON CONFLICT REPLACE,pwd TEXT,proxy INTEGER,sessionkey TEXT,srt_key TEXT,ticket TEXT,name TEXT,headphoto BLOB,isdefault INTEGER,last_login INTEGER,friend_count INTEGER);"); db.execSQL("CREATE TABLE home (_id INTEGER PRIMARY KEY,item_id INTEGER UNIQUE ON CONFLICT REPLACE,data BLOB);"); db.execSQL("CREATE TABLE profile (_id INTEGER PRIMARY KEY,type INTEGER UNIQUE ON CONFLICT REPLACE,data BLOB);"); db.execSQL("CREATE TABLE friends (_id INTEGER PRIMARY KEY,uid INTEGER UNIQUE ON CONFLICT REPLACE,username TEXT,headurl TEXT,doing TEXT,nameindex TEXT,namepinyin TEXT,friendgroup TEXT,network TEXT,gender TEXT,isfriend INTEGER,suggest_text_1 TEXT,suggest_intent_query TEXT);"); db.execSQL("CREATE TABLE messages (_id INTEGER PRIMARY KEY,messageid INTEGER UNIQUE ON CONFLICT REPLACE,message BLOB);"); db.execSQL("CREATE TABLE favorites (_id INTEGER PRIMARY KEY,favoriteid BIGINT UNIQUE ON CONFLICT REPLACE,favoriteowner INTEGER,type INTEGER,favorite BLOB);"); db.execSQL("CREATE TABLE emonticons (_id INTEGER PRIMARY KEY,url TEXT,emotion TEXT UNIQUE ON CONFLICT REPLACE,img BLOB,size INTEGER,_data TEXT);"); db.execSQL("CREATE TABLE favoritefriends (_id INTEGER PRIMARY KEY,owner INTEGER,uid INTEGER,name TEXT);"); db.execSQL("CREATE TABLE chathistory (_id INTEGER PRIMARY KEY,uid INTEGER,tochatid INTEGER,chatmessage TEXT,comefrom INTEGER,chatname TEXT,chattime LONG);"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS pic"); db.execSQL("DROP TABLE IF EXISTS account"); db.execSQL("DROP TABLE IF EXISTS home"); db.execSQL("DROP TABLE IF EXISTS profile"); db.execSQL("DROP TABLE IF EXISTS friends"); db.execSQL("DROP TABLE IF EXISTS messages"); db.execSQL("DROP TABLE IF EXISTS favorites"); db.execSQL("DROP TABLE IF EXISTS emonticons"); db.execSQL("DROP TABLE IF EXISTS favoritefriends"); db.execSQL("DROP TABLE IF EXISTS favoritefriends"); db.execSQL("DROP TABLE IF EXISTS chathistory"); onCreate(db); } } 从代码中我们可以看到人人网android客户端在用户手机上创建了renren.db数据库,数据库中共有10张表,分别为pic、account、home、profile、friends、messages、favorites、emonticons、favoritefriends、chathistory。 2. RenRenProvider 前面我们已经提到过ContentProvider,下面我们来看看人人网android客户端是如何开发ContentProvider的。开发ContentProvider的两步:1)开发一个ContentProvider的子类,该子类需要实现增、删、改、查等方法。2)在AndroidManifest.xml文件中注册该ContentProvider。 下面是RenRenProvider核心代码: public class RenRenProvider extends ContentProvider { public static final String AUTHORITY = "com.renren.mobile.provider"; public static final class Account implements BaseColumns { public static final Uri ACCOUNT_CONTENT_URI = Uri .parse("content://com.renren.mobile.provider/account"); } public static final class ChatHistory implements BaseColumns { public static final Uri CHAT_HISTORY_CONTENT_URI = Uri .parse("content://com.renren.mobile.provider/chathistory"); } public static final class Emonticons implements BaseColumns { public static final Uri EMONTICONS_CONTENT_URI = Uri .parse("content://com.renren.mobile.provider/emonticons"); } public static final class Favorite implements BaseColumns { public static final Uri FAVORITE_CONTENTURI = Uri .parse("content://com.renren.mobile.provider/favorites"); } public static final class FavoriteFriends implements BaseColumns { public static final Uri FAVORITE_FRIENDS_CONTENT_URI = Uri .parse("content://com.renren.mobile.provider/favoritefriends"); } public static final class Friends implements BaseColumns { public static final Uri FRIENDS_CONTENT_URI = Uri .parse("content://com.renren.mobile.provider/friends"); } public static final class Home implements BaseColumns { public static final Uri HOME_CONTENT_URI = Uri .parse("content://com.renren.mobile.provider/home"); } public static final class Messages implements BaseColumns { public static final Uri MESSAGES_CONTENT_URI = Uri .parse("content://com.renren.mobile.provider/messages"); } public static final class Pic implements BaseColumns { public static final Uri PIC_CONTENT_URI = Uri .parse("content://com.renren.mobile.provider/pic"); } public static final class Profile implements BaseColumns { public static final Uri PROFILE_CONTENT_URI = Uri .parse("content://com.renren.mobile.provider/profile"); } private static final UriMatcher URI_MATCHER; private RenRenProvider.DatabaseHelper renrenDatabaseHelper; static { URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); URI_MATCHER.addURI(AUTHORITY, "pic", 3); URI_MATCHER.addURI(AUTHORITY, "pic/#", 4); URI_MATCHER.addURI(AUTHORITY, "account", 5); URI_MATCHER.addURI(AUTHORITY, "account/#", 6); URI_MATCHER.addURI(AUTHORITY, "home", 7); URI_MATCHER.addURI(AUTHORITY, "home/#", 8); URI_MATCHER.addURI(AUTHORITY, "profile", 9); URI_MATCHER.addURI(AUTHORITY, "profile/#", 10); URI_MATCHER.addURI(AUTHORITY, "friends", 11); URI_MATCHER.addURI(AUTHORITY, "friends/#", 12); URI_MATCHER.addURI(AUTHORITY, "search_suggest_query/*", 1); URI_MATCHER.addURI(AUTHORITY, "search_suggest_query", 2); URI_MATCHER.addURI(AUTHORITY, "messages", 13); URI_MATCHER.addURI(AUTHORITY, "messages/#", 14); URI_MATCHER.addURI(AUTHORITY, "favorites", 15); URI_MATCHER.addURI(AUTHORITY, "favorites/#", 16); URI_MATCHER.addURI(AUTHORITY, "emonticons", 17); URI_MATCHER.addURI(AUTHORITY, "emonticons/#", 18); URI_MATCHER.addURI(AUTHORITY, "favoritefriends", 19); URI_MATCHER.addURI(AUTHORITY, "favortiefriends/#", 20); URI_MATCHER.addURI(AUTHORITY, "chathistory", 21); URI_MATCHER.addURI(AUTHORITY, "chathistory/#", 22); URI_MATCHER.addURI(AUTHORITY, "chathistory/*/*", 23); } public boolean onCreate() { renrenDatabaseHelper = new RenRenProvider.DatabaseHelper(this.getContext()); return true; } //其它代码省略... } 下面是人人网android客户端在AndroidMantifest.xml中对该ContentProvider的注册。 <providerandroid:name=".contentprovider.RenRenProvider" android:permission="com.renren.mobile.android.permission.PERMISSION_ADD_ACCOUNT" android:authorities="com.renren.mobile.provider" /> 从上面的分析我们了解到只要得到com.renren.mobile.android.permission.PERMISSION_ADD_ACCOUNT权限我们就可以通过特定Uri访问人人网android客户端在用户手机上创建的renren.db中特定表了。 3. 开发android应用访问renren.db中的数据 从上面分析中我们已经知道renren.db中表结构,及访问特定表对应的Uri,如我们可以通过content://com.renren.mobile.provider/account访问renren.db中的account表等等。下面我们写个很简单的例子来访问account表中的account和ticket字段。 main.xml根节点下简单添加2个TextView,如下: <TextView android:id="@+id/textView1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="TextView" /> <TextView android:id="@+id/textView2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="TextView" /> 将account和ticket信息显示到TextView中,类代码如下 public class RenRenExtActivity extends Activity { private static final Uri ACCOUNT_CONTENT_URI = Uri .parse("content://com.renren.mobile.provider/account"); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView textView1 = (TextView) findViewById(R.id.textView1); textView1.setText("Sorry."); TextView textView2 = (TextView) findViewById(R.id.textView2); textView2.setText("Sorry2."); Cursor cursor = getContentResolver().query(ACCOUNT_CONTENT_URI, null, null, null, null); List<Map<String, String>> resultList = converCursorToList(cursor); if (!resultList.isEmpty()) { Map<String, String> map = resultList.get(0); textView1.setText(map.get("account")); textView2.setText(map.get("ticket")); } } private List<Map<String, String>> converCursorToList(Cursor cursor) { List<Map<String, String>> result = new ArrayList<Map<String, String>>(); if (cursor == null) { return Collections.emptyList(); } // 遍历Cursor结果集 while (cursor.moveToNext()) { // 将结果集中的数据存入ArrayList中 Map<String, String> map = new HashMap<String, String>(); map.put("account", cursor.getString(cursor.getColumnIndex("account"))); map.put("ticket", cursor.getString(cursor.getColumnIndex("ticket"))); result.add(map); } return result; } } 需要指出的是,上面的应用程序需要操作人人网android客户端中的数据库,因此要记得在AndroidMantifest.xml文件中为该应用程序授权。也就是在该文件的根元素中添加如下元素: <uses-permission android:name="com.renren.mobile.android.permission.PERMISSION_ADD_ACCOUNT" /> 如果你android手机中安装有人人网android客户端且曾经使用过,那么renren.db中应该有数据存在,把上面应用打包为apk文件安装到你android手机中,运行它,应该能看到屏幕中将显示你的人人网账号及一串ticket,该ticket是人人网andriod客户端部分功能与人人网服务器通信的sid。 同理,也可以使用其它特定Uri访问手机中renre.db中特定的表,如friends表等等,所有Uri详见RenRenProvider代码。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-10-30
分析的不错,写的也很详细,主要就是ContentProvider,不管数据是那种形式存储,(sqlite数据库,xml等)只要提供了数据的操作方法,那么别的程序就可以调用,这作为跨程序访问来说非常方便。特别是开发一些列独立程序并要互操作数据,这种方式就特别有用了。
android还提供了很多便捷的方法和功能,作为开发者,一定要整体看下api,看都提供哪些东西再设计开发,不要重复发明轮子。 |
|
返回顶楼 | |
发表时间:2011-10-30
List<Map<String, String>> result = new ArrayList<Map<String, String>>();
if (cursor == null) { return Collections.emptyList(); } ......... |
|
返回顶楼 | |
发表时间:2011-10-30
不知道楼主有没有兴趣和我一起分析源码?
|
|
返回顶楼 | |
发表时间:2011-10-31
很实用,谢谢
|
|
返回顶楼 | |
发表时间:2011-10-31
最后修改:2011-10-31
在朋友写的.dex分析工具基础上,作了些完善,主要是对intermediate representation部分做了些加强
反编译人人网android客户端算是对这个工具的试验,发现效果还可以 有人投新手帖了,情何以堪 ![]() 不会是人人网的员工吧 ![]() 不过,的确只对字节码有些兴趣,真正android编程才一个星期 ![]() |
|
返回顶楼 | |
发表时间:2011-11-01
我给你良好!
投新手的有多手点那一下的时间你也发一条,现在的eye啊真是没救了,喷子的帖子可以推主页,标题党的东西也可以推主页,只要是白开水都能放到主页! 这贴虽说含糖量不高。但为啥投新手的那些人你们就看不下去?难道你们都是糖尿~~ |
|
返回顶楼 | |
发表时间:2011-11-01
happysoul 写道 我给你良好!
投新手的有多手点那一下的时间你也发一条,现在的eye啊真是没救了,喷子的帖子可以推主页,标题党的东西也可以推主页,只要是白开水都能放到主页! 这贴虽说含糖量不高。但为啥投新手的那些人你们就看不下去?难道你们都是糖尿~~ 同投良好,对lz的分享精神赞一个 |
|
返回顶楼 | |
发表时间:2011-11-04
自己看看就行了,还拿到网上分析,道德吗?
|
|
返回顶楼 | |
发表时间:2011-11-04
冰冷缠绵 写道 List<Map<String, String>> result = new ArrayList<Map<String, String>>();
if (cursor == null) { return Collections.emptyList(); } ......... 这个有什么问题?莫非你看走眼了? |
|
返回顶楼 | |