Android高效率编码-第三方SDK详解系列(二)——Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能

我的本意是第二篇写Mob的shareSDK分享组件的,奈何需要去注册各平台的账号,还要审核,有些审核还挺久,就没办法,改为写这个Bmob了,相信大家对Bmob都是挺期待的吧,因为他作为Android后端的实现很好的支持,国内很多软件都在使用它,他的功能也是特别神奇,这里就不一一细说了,我们用实际的例子来见证他的神奇

官网:http://www.bmob.cn/

注意本教程是根据Bmob官方教程改写

这里我简单的介绍一下Bmob吧,Bmob平台为您的移动应用提供了一个完整的后端解决方案,他们提供轻量级的SDK开发包,让开发者以最小的配置和最简单的方式使用Bmob平台提供的服务,进而完全消除开发者编写服务器代码以及维护服务器的操作。

开发文档:http://docs.bmob.cn/android/developdoc/index.html?menukey=develop_doc&key=develop_android

目录:


我们当然不可能按部就班的找些上面写,不过入门都是一样的,我们这些流程还是得走一遍,这样才更有利于你对Bmob的认知和了解
我们首先新建一个工程,以Eclipse为例哈,也是为了编写小Demo方便

然后我们打开Bmob的官网去创建我们的项目

控制面板

创建项目

项目列表

相关的一些key

好了,我们得到了我们想要的key了,我们就可以开始编写了

一.Hello Bmob

1.下载SDK,添加进工程

这个相信都不用多说了

Android Studio

鉴于目前Google官方推荐使用 Android Studio 进行Android项目开发,自 V3.4.2 开始,Bmob Android SDK 可以使用Gradle来进行包依赖管理,如果你使用Android Studio来进行基于BmobSDK的项目开发

1.在Project的build.gradle文件中添加如下配置(注意文字说明部分)

buildscript {    repositories {        jcenter()    }    dependencies {        classpath 'com.android.tools.build:gradle:1.2.3'    }}allprojects {    repositories {        jcenter()        //Bmob的maven仓库地址,必须填写        maven { url "https://raw.github.com/bmob/bmob-android-sdk/master" }    }}

2、在app的build.gradle文件中添加如下配置(注意文字说明部分):

apply plugin: 'com.android.application'android {    compileSdkVersion 22    buildToolsVersion '22.0.1'    defaultConfig {        applicationId "cn.bmob.android"        minSdkVersion 14        targetSdkVersion 22        versionCode 1        versionName "1.0"    }    buildTypes {        release {            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }    lintOptions{        abortOnError false    }}dependencies {    compile fileTree(dir: 'libs', include: ['*.jar'])    compile 'com.android.support:appcompat-v7:22.2.0'    //以下SDK开发者请根据需要自行选择    //bmob-sdk :Bmob的android sdk包    compile 'cn.bmob.android:bmob-sdk:3.4.5'    //bmob-push:Bmob的推送包    compile 'cn.bmob.android:bmob-push:0.6'    //bmob-im:bmob的im包,以下两个配置是im功能所需    compile 'cn.bmob.android:bmob-im:1.1.9'    compile 'cn.bmob.android:bmob-sdk:3.4.3'    //okhttp(选填):为解决弱网情况下SDK请求失败及响应慢的问题,自`V3.4.3版本`开始使用`okhttp`优化SDK的网络框架。    compile 'com.squareup.okhttp:okhttp:2.4.0'    compile 'com.squareup.okio:okio:1.4.0'    //bmob-sms :Bmob单独为短信服务提供的包    compile 'cn.bmob.android:bmob-sms:1.0.1'}

注:

1、如果你只需要Bmob提供的短信功能,那么你只需单独配置bmob-sms,如果你既需要bmob的数据服务,也需要短信服务,那么你只需要配置bmob-sdk即可。2、每个版本的im都对应特定版本的bmob-sdk,如果你使用的是1.1.8版本的im,那么配套的bmob-sdk的版本为3.3.5。使用的是1.1.9配套的bmob-sdk的版本为3.4.3.3、与okhttp有关的配置依赖不是必填项,开发者可以不添加该依赖。

Eclipse

直接拷贝到lib目录下

下面的例子均在Eclipse环境下完成

2.添加权限

<uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permission android:name="android.permission.READ_PHONE_STATE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_LOGS"/>

3.初始化BmobSDK

public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {         // TODO Auto-generated method stub        super.onCreate(savedInstanceState);         // 初始化 Bmob SDK        // 使用时请将第二个参数Application ID替换成你在Bmob服务器端创建的Application ID        Bmob.initialize(this, "Your Application ID");    }}

二.数据操作

首先我们把布局添加一下


layout_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <Button        android:id="@+id/btn_add"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="添加数据" />    <Button        android:id="@+id/btn_update"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="更新数据" />    <Button        android:id="@+id/btn_delete"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="删除数据" />    <Button        android:id="@+id/btn_query"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="查询数据" /></LinearLayout>
然后实例化这四个Button
    private Button btn_add, btn_update, btn_delete, btn_query;
    btn_add = (Button) findViewById(R.id.btn_add);    btn_add.setOnClickListener(this);    btn_update = (Button) findViewById(R.id.btn_update);    btn_update.setOnClickListener(this);    btn_delete = (Button) findViewById(R.id.btn_delete);    btn_delete.setOnClickListener(this);    btn_query = (Button) findViewById(R.id.btn_query);    btn_query.setOnClickListener(this);
因为考虑到有四个点击事件,我们直接implements OnClickListener这样也许更直观一点,所以onClick()方法就是这个样子了
        @Override    public void onClick(View v) {        switch (v.getId()) {        //添加数据        case R.id.btn_add:            break;        //更新数据        case R.id.btn_update:            break;        //删除数据        case R.id.btn_delete:            break;        //查询数据        case R.id.btn_query:            break;        }    }
准备工作差不多都做完了?No,还有一件非常重要的事情要做

1.创建JavaBean

我们新建一个类继承BmobObject,具体操作看注释
package com.lgl.bmobdemo;import cn.bmob.v3.BmobObject;/** * javabean * * @author lgl * */public class Bean extends BmobObject {    /** * 这个javabean必须视情况而定,也就是你需要你的表上有什么信息你就加什么,当然,前提是,你的表单上有 * 添加表单可以在Bmob应用控制-数据浏览页面操作,后续会讲到 这里,我们假设有三个信息数据,分别是姓名,年龄,分数 */    private String name;    private int age;    private int score;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public int getScore() {        return score;    }    public void setScore(int score) {        this.score = score;    }}

2.添加数据

其实就是调用了Bean的get,set方法
case R.id.btn_add:            // new出这个bean            Bean bean = new Bean();            // 分别设置相应的信息            bean.setName("刘桂林");            bean.setAge(20);            bean.setScore(100);            bean.save(this, new SaveListener() {                @Override                public void onSuccess() {                    // 成功                    Toast.makeText(MainActivity.this, "保存成功", 1)                            .show();                }                @Override                public void onFailure(int arg0, String arg1) {                    // 失败                    Toast.makeText(MainActivity.this, "保存失败", Toast.LENGTH_LONG)                            .show();                }            });    break;
我们运行程序,然后点击添加数据,当弹出Toast说明保存成功后,我们回到Bmob官网,找到我们的项目,点击数据浏览,就会看到已经保存的信息,这个就是我们的后台了

3.更新数据

更新数据,就是更新一条数据的记录,就像你修改个人信息,本来是男,现在要修改成女一样,但是,我们必须知道一点,就是如下图所示的objectid


假设我先现在知道这个id,那我们的操作就可以这样

case R.id.btn_update:            bean = new Bean();            bean.setObjectId("edec38a77d");            bean.setName("修改刘桂林");            bean.setScore(30);            bean.update(this, new UpdateListener() {                @Override                public void onSuccess() {                    // 成功                    Toast.makeText(MainActivity.this, "更新成功", 1).show();                }                @Override                public void onFailure(int arg0, String arg1) {                    // 失败                    Toast.makeText(MainActivity.this, "更新失败", 1).show();                }            });    break;
然后我们来运行程序,点击更新数据,然后我们回到后台去查看

4.删除数据

同样的,你要删除一条数据,你还得知道人家的objectid
case R.id.btn_delete:            bean = new Bean();            bean.setObjectId("edec38a77d");            bean.delete(this, new DeleteListener() {                @Override                public void onSuccess() {                    //成功                    Toast.makeText(MainActivity.this, "删除成功", 1).show();                }                @Override                public void onFailure(int arg0, String arg1) {                    //失败                    Toast.makeText(MainActivity.this, "删除失败", 1).show();                }            });    break;
然后我们运行程序,点击删除数据后回到后台

可以看到,表明bean还在,但是数据已经被删除了

5.查询数据

这几个数据操作,唯一不同的就是查询了,他必须使用到一个查询的类BmobQuery
        case R.id.btn_query:            // BmobQuery<要查询的数据表> 项目一般不会只有一张表的            BmobQuery<Bean> query = new BmobQuery<Bean>();            query.findObjects(this, new FindListener<Bean>() {                @Override                public void onSuccess(List<Bean> arg0) {                    // 成功                    Toast.makeText(MainActivity.this, "查询成功"+arg0.size(), 1).show();                }                @Override                public void onError(int arg0, String arg1) {                    // 失败                    Toast.makeText(MainActivity.this, "查询失败", 1).show();                }            });    break;
然后我们点击查询之后,他返回的是一个List,这里我们就不详细看List里面有什么了,表里只有一条数据,我们直接Toast他的size

5.1条件查询

跟数据库操作是一样的,你可以根据条件来查询,看代码
case R.id.btn_query:            // BmobQuery<要查询的数据表> 项目一般不会只有一张表的            BmobQuery<Bean> query = new BmobQuery<Bean>();            //条件查询 我们查询名称是刘桂林的数据            query.addWhereEqualTo("name", "刘桂林");            query.findObjects(this, new FindListener<Bean>() {                @Override                public void onSuccess(List<Bean> arg0) {                    // 成功// Toast.makeText(MainActivity.this, "查询成功"+arg0.size(), 1).show();                    for (Bean bean : arg0) {                        Toast.makeText(MainActivity.this, "查询成功"+bean.getName()+"---"+bean.getAge(), 1).show();                    }                }                @Override                public void onError(int arg0, String arg1) {                    // 失败                    Toast.makeText(MainActivity.this, "查询失败", 1).show();                }            });     break;
运行的结果

5.2单条查询

case R.id.btn_query:            // BmobQuery<要查询的数据表> 项目一般不会只有一张表的            BmobQuery<Bean> query = new BmobQuery<Bean>();            // 查询单条数据            query.getObject(this, "9fe91ce9a6", new GetListener<Bean>() {                @Override                public void onFailure(int arg0, String arg1) {                    // 失败                    Toast.makeText(MainActivity.this, "查询失败", 1).show();                }                @Override                public void onSuccess(Bean bean) {                    // 成功                    Toast.makeText(MainActivity.this, bean.getName()+","+bean.getAge(), 1).show();                }            });            break;
这里你要单条数据查询的话,你就必须只带objectid才行,这里就不演示了

Demo下载地址:http://download.csdn.net/detail/qq_26787115/9379591

三.登录,注册,更新资料,修改密码,邮箱验证

前面废话啰嗦了也有一大堆了,现在来聊聊实际点的东西,Bmob他毕竟是一个后台数据管理的平台,所以前面才说了一堆的数据操作,我们接下来要实现的功能就是用户的注册和登录。

1.注册

Bmob实现登录注册,还有邮箱验证的功能,其实就是利用上面的数据操作,也就是增删查改我们进入后台会看到用户表单里面有一些字段

这可不是固定的,而是根据我们的需求可以增加或者删除的,默认的是最基本的我们为了方便,新建一个工程BmobTest,然后把架包放在lib目录下,添加相应的权限以及在onCreate()方法里初始化Bmob,准备工作做完了之后,我们开始写代码:

我们还是用回上面的哪个Bean,因为用户名和密码是不需要复写的,不过这里特别需要注意的是,这次我们不是继承BmobObject,而是继承BmobUser;

**
我们要先搭建一个工程

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >    <EditText  android:id="@+id/et_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入用户名" />    <EditText  android:id="@+id/et_pass" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入密码" />    <Button  android:id="@+id/btn_login" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="登录" />    <LinearLayout  android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="15dp" android:orientation="horizontal" >        <TextView  android:id="@+id/tv_etpass" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="修改密码" />        <TextView  android:id="@+id/tv_register" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="注册用户" />    </LinearLayout></LinearLayout>

activity_register.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >    <EditText  android:id="@+id/et_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入用户名" />    <EditText  android:id="@+id/et_pass" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入密码" />    <Button  android:id="@+id/btn_register" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="注册" /></LinearLayout>
布局就是这样,想必跳转的逻辑也不用说了吧,很简单的一个例子,那我们先来注册:

RegisterActivity

package com.lgl.bmobtest;import cn.bmob.v3.listener.SaveListener;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;public class RegisterActivity extends Activity {    private Button btn_register;    private EditText et_name, et_pass;    @Override    protected void onCreate(Bundle savedInstanceState) {        // TODO Auto-generated method stub        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_register);        btn_register = (Button) findViewById(R.id.btn_register);        et_name = (EditText) findViewById(R.id.et_name);        et_pass = (EditText) findViewById(R.id.et_pass);        btn_register.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                Bean bean = new Bean();                // 设置的内容可以不需要,这里为了简便直接写死了                bean.setName("刘桂林");                bean.setAge(20);                bean.setScore(100);                bean.setUsername(et_name.getText().toString());                bean.setPassword(et_pass.getText().toString());                bean.signUp(RegisterActivity.this, new SaveListener() {                    @Override                    public void onSuccess() {                        // 如果注册成功,就finish()掉,也就是退回主界面                        finish();                    }                    @Override                    public void onFailure(int arg0, String arg1) {                        Toast.makeText(RegisterActivity.this, "注册失败",                                Toast.LENGTH_LONG).show();                    }                });            }        });    }}
我们把项目部署在模拟器上

点击注册之后直接就finish()了说明注册成功了,我们进Bmob后端控制台去看一下

表里面有数据,说明我们已经注册成功了

用户名是12345 密码是67890

2.登录

登录其实是比较简单的
case R.id.btn_login:            Bean bean = new Bean();            bean.setUsername(et_name.getText().toString());            bean.setPassword(et_pass.getText().toString());            bean.login(this, new SaveListener() {                @Override                public void onSuccess() {                    Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_LONG)                            .show();                }                @Override                public void onFailure(int arg0, String arg1) {                    Toast.makeText(MainActivity.this, "账号或密码错误",                            Toast.LENGTH_LONG).show();                }            });            break;
我们把项目部署在模拟器上

3.更新用户信息

我们时常就是会碰到这么一个场景,自己的个人信息填写错了,需要修改这里我们在主布局加一个Button
   <Button  android:id="@+id/btn_update" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="更新用户信息" />
    更新信息的代码其实和上面的数据操作是有异曲同工的
case R.id.btn_update:            // Bmob在登录成功后会缓存            bean = BmobUser.getCurrentUser(this, Bean.class);            bean.setName("刘桂林修改");            bean.update(this, new UpdateListener() {                @Override                public void onSuccess() {                    Toast.makeText(MainActivity.this, "修改成功", Toast.LENGTH_LONG)                            .show();                }                @Override                public void onFailure(int arg0, String arg1) {                }            });            break;
我们把项目部署在模拟器上

注意:我们更新用户信息的前提是已经登录

有图有真相,我们看一下控制台

4.邮箱验证功能

使用邮件验证功能,我们必须去后端控制台开启这个功能

里面的信息我们可以自定义,我们将之前注册的过程进行修改,如果觉得乱的会后续也会贴上源码,其实就是加个邮箱而已
bean.setEmail("748778890@qq.com");
然后我们把项目部署在模拟器上,我们项目注册之后就有一个邮箱了

然后我们会收到验证邮件

是不是很神奇,我们来看看邮件的内容,你会发现,就是Bmob后台的邮件信息,你是可以自定义的

我们点击链接

如果我们没有验证的话,就算你的注册时能finish(),你也不能登录的,挺实用的我们可以在登录的时间写一个判断
if (bean.getEmailVerified()) {        Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_LONG).show();    }else {        Toast.makeText(MainActivity.this, "请前往邮箱验证", Toast.LENGTH_LONG).show();        }

5.修改密码

修改密码同样会使用到邮箱验证的功能,在邮箱信息的地方可以看到密码修改信息

case R.id.tv_etpass:            String email = "[email protected]";            BmobUser.resetPasswordByEmail(this, email, new ResetPasswordByEmailListener() {                @Override                public void onSuccess() {                    Toast.makeText(MainActivity.this, "验证邮箱已发送", Toast.LENGTH_LONG)                    .show();                }                @Override                public void onFailure(int arg0, String arg1) {                    Toast.makeText(MainActivity.this, "更改失败", Toast.LENGTH_LONG)                    .show();                }            });            break;

注意,修改密码的前提是你是登录状态哦

我们把项目部署在模拟器上

然后看短信内容

现在就可以修改密码了,修改迷失是根据你的邮箱来更改的

OK,是不是挺简单的

四.文件管理

1.上传文件

后面其实都是依葫芦画瓢,我就文字多啰嗦几句,代码少些一点了
// 上传文件,这里是指定文件的路径,只要你指定了这个路径下的文件,不管是什么类型,都是可以上传的String picPath = "sdcard/Download/image.png";//然后我们创建一个file对象final BmobFile file = new BmobFile(new File(picPath));//我们拿到这个file对象把他上传file.upload(this, new UploadFileListener() {                @Override                public void onSuccess() {                    //上传成功                }                @Override                public void onProgress(Integer arg0) {                    // 上传进度                }                @Override                public void onFailure(int arg0, String arg1) {                    // 上传失败                }            });        break;
只要我们上传了之后,是可以在控制端后台看到的

2.下载文件

Bmob的操作都是很相似的,我们下载和上传也是差不多的
//我们首先查询这个数据库BmobQuery<Bean> query = new BmobQuery<Bean>();//根据objectid我们进行操作query.getObject(this, "55f9e5c116", new GetListener<Bean>() {                @Override                public void onSuccess(Bean arg0) {                    //这里返回的文件是一个File类型,因为我们这里是图片所以就直接geticon();                    BmobFile icon = arg0.getIcon();                    //我们可以直接获取到这个图片的Url,但是毕竟是一张图片,我们就直接设置在控件上                    // String url = icon.getFileUrl();                    icon.loadImage(MainActivity.this, iv_icon);                }                @Override                public void onFailure(int arg0, String arg1) {                    //失败                }            });
图片采用Bmob官方

3.缩略图加载

所谓的缩略图就是加载图片的时候为了节约啥啥啥的所对图片进行了一定的压缩,我们只要把刚才加载图片的方法改变一下就可以了
//参数:上下文,指定路径,长,宽,照片质量icon.loadImageThumbnail(MainActivity.this, iv_icon, 100, 100, 100);

五.推送功能

要使用推送功能,你必须要有推送SDK,不过估计你也已经添加了

1.在您的应用程序AndroidManifest.xml文件中注册BmobPush SDK运行所需的推送服务和消息接收器:

<service  android:label="PushService" android:name="cn.bmob.push.lib.service.PushService" android:process="cn.bmob.push" android:exported="true">     <intent-filter>           <action android:name="cn.bmob.push.lib.service.PushService"/>      </intent-filter></service> <receiver android:name="cn.bmob.push.PushReceiver" >        <intent-filter android:priority="2147483647" ><!--优先级加最高-->                <!-- 系统启动完成后会调用 -->                <action android:name="android.intent.action.BOOT_COMPLETED" />                               <!-- 解锁完成后会调用 -->                <action android:name="android.intent.action.USER_PRESENT" />                <!-- 监听网络连通性 -->                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />                         </intent-filter></receiver>

2.在你的应用程序中创建一个消息接收器

Push消息通过action=cn.bmob.push.action.MESSAGE的Intent把数据发送给客户端your.package.MyPushMessageReceiver,消息格式由应用自己决定,PushService只负责把服务器下发的消息以字符串格式透传给客户端。我们新建一个广播类
    public class MyPushMessageReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            // TODO Auto-generated method stub            if (intent.getAction().equals("msg")) {                Toast.makeText(context,                        "客户端收到推送内容:" + intent.getStringExtra("msg"),                        Toast.LENGTH_LONG).show();            }        }    }

3.启动推送服务

在你的应用程序主Activity中调用如下方法:
  // 使用推送服务时的初始化操作 BmobInstallation.getCurrentInstallation(this).save(); // 启动推送服务 BmobPush.startWork(this, "你的Application Id");
准备工作都做完之后我们应该在后端控制面板开启推送服务

这些内容自定义之后别急着点击发送,我们还需要配置一下包名

等都绑定了之后我们就可以点击推送了

总结:Bmob的操作相对来说,还真是比较简单,当然,给出的是简单的操作,但是运用得当的话依然能有所作用,不过只推荐给自己做一个小项目的时候使用,毕竟是后台的数据,挺重要的,即时通讯写的就要繁琐很多,最近也在整理,所以暂时先不写上去了,后续会添加

Demo下载地址:http://download.csdn.net/detail/qq_26787115/9387253

更多相关文章

  1. Android(安卓)API Guides---Near Field Communication
  2. Android应用在未启动的情况下无法收到指定广播的问题总结
  3. Android用户体验团队:Android(安卓)UI设计准则
  4. Android(安卓)小項目之---Toast對象詳細使用,兼溫習前內容(附源碼)
  5. Android(安卓)引用外部项目库
  6. 一次偶然机遇找到一个不错的关于Android实现加载gif动画的实例,写
  7. 工作心得
  8. (Android(安卓)Studio)Android(安卓)手机设备与HC05 蓝牙设备的
  9. mvp过渡到mvvm(Android(安卓)架构组件)

随机推荐

  1. java web开发(三) 接口使用
  2. 国内技术社区活跃的 Android(安卓)大神汇
  3. 星云精准测试对安卓底层驱动代码的测试案
  4. android即时通讯开发笔记(一)绪论~实现用户
  5. Android用户界面布局
  6. Android实现登录界面和功能实例
  7. [Android]如何做一个崩溃率少于千分之三
  8. android SQLite数据库1
  9. 浅言架构——Android(安卓)MVP ...
  10. 9个非常棒的Android代码编辑器 移动开发