六、编写用户数据获取模块
通常应用程序应当提供用户个人信息和配置模块以浏览、编辑个人配置,或者退出登录状态。
我们编写一个简单的个人信息模块,能够根据当前登录的用户账号从服务器端查询用户信息并显示,并且提供注销操作。具体设计如下:
- 前置条件:用户已登录
- 用户点击笔记列表页面ActionBar上的用户图标,进入用户信息页面
- 用户信息页面展示用户email地址和个人签名
- 用户信息页面提供登出按钮
- 用户点击登出按钮后,APP清除登录数据,同时切换到登录页面
编写服务端查询页面
回到DreamWeaver(以下简称DW),创建新页面,命名为user_info.php,仍然保存到simple_note目录下。页面代码如下:
<?
session_start();
include( "conn.php" );
$email = $_POST[ "email" ];
// 在数据库中查询与email和密码完全匹配的记录
$sql = "SELECT * FROM `user` WHERE `email`='$email'";
$result = mysql_query( $sql );
$num_rows = mysql_num_rows( $result );
// 将用JSON返回登录结果
header( 'Content-type: text/json' );
if ( $num_rows == 1 ) {
// 查询成功
$row = mysql_fetch_array( $result );
// 生成含有结果信息的JSON
$ret = array(
"code" => "1",
"msg" => "OK",
"email" => $row[ 'email' ],
"personalSign" => $row[ 'sign' ]
);
echo json_encode( $ret, JSON_UNESCAPED_UNICODE );
} else {
// 不存在对应用户信息,返回出错信息
$ret = array(
"code" => "0",
"msg" => "No such a user",
"email" => $row[ 'email' ]
);
echo json_encode( $ret, JSON_UNESCAPED_UNICODE );
}
?>
创建用户信息页面
新建名为UserInfoActivity的新页面:
配置其对应的布局文件activity_user_info.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".UserInfoActivity">
<!--登出按钮-->
<Button
android:id="@+id/btn_logout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:text="登出账户"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<!--Email信息-->
<TextView
android:id="@+id/tv_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="100dp"
android:text="a@abc.com"
android:textColor="@color/black"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--个人签名-->
<TextView
android:id="@+id/tv_personal_sign"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="24dp"
android:text="Personal sign"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_email" />
<!--加载等待动画-->
<ProgressBar
android:id="@+id/load_progress"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
回到UserInfoActivity类中,为其添加成员变量如下:
// 等待动画
private ProgressBar mProgressBar;
// Email文本
private TextView mEmailView;
// 个人签名文本
private TextView mPersonalSignView;
// 登出按钮
private Button mLogoutView;
private Handler mHandler = new Handler();
修改onCreate()方法:
mProgressBar = findViewById(R.id.load_progress);
mEmailView = findViewById(R.id.tv_email);
mPersonalSignView = findViewById(R.id.tv_personal_sign);
mLogoutView = findViewById(R.id.btn_logout);
// 执行登出
mLogoutView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onLogout();
}
});
// 从服务器加载用户信息
loadUserInfo();
基于okhttp3框架实现loadUserInfo()函数:
private void loadUserInfo() {
String email = Utils.getUserEmail(this);
// 当前并没有登录,跳转到登录页面
if (TextUtils.isEmpty(email)) {
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
finish();
return;
}
OkHttpClient client = new OkHttpClient();
FormBody.Builder fb = new FormBody.Builder();
FormBody formBody = fb.add("email", email)
.build();
Request request = new Request.Builder()
.url(HttpHelper.getUserInfoUrl())
.post(formBody)
.build();
showProgress(true);
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
mHandler.post(new Runnable() {
@Override
public void run() {
showProgress(false);
Toast.makeText(UserInfoActivity.this, R.string.error_check_network, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
...
}
});
}
在onResponse()回调函数中编写下面的代码:
final String rsp = response.body().string();
mHandler.post(new Runnable() {
@Override
public void run() {
showProgress(false);
try {
JSONObject jo = new JSONObject(rsp);
int code = jo.optInt("code", 0);
String email = jo.optString("email");
String personalSign = jo.optString("personalSign");
if (code == 1) {
// 查询成功,设置当前要显示的各个字段
mEmailView.setText(email);
mPersonalSignView.setText(personalSign);
} else {
// 查询失败,关闭页面退出
finish();
return;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
下面实现登出功能,这里简单的处理,就是将之前登录后保存的账户设置为空即可:
private void onLogout() {
Utils.saveUserEmail(this, "");
finish();
}
还要实现控制等待动画显示与隐藏的showProgress()函数:
private void showProgress(final boolean show) {
mProgressBar.setVisibility(show ? View.VISIBLE : View.GONE);
}
为笔记列表页ActionBar添加用户信息项
将以下图标文件放置到res/drawable-xxhdpi目录中:
ic_person.png进入到笔记列表页对应的菜单资源文件menu_note_list.xml中,增加菜单项menu_item_user如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_item_notebook"
android:title="@string/notebook"
android:icon="@drawable/ic_notebook"
app:showAsAction="always"/>
<!--新增用户信息项-->
<item
android:id="@+id/menu_item_user"
android:title="@string/user_info"
android:icon="@drawable/ic_person"
app:showAsAction="always"/>
</menu>
需要新增的字符串:
<string name="user_info">用户信息</string>
回到笔记列表页,找到onOptionsItemSelected()方法,为其添加代码,在点击用户信息图标时打开用户信息页面:
case R.id.menu_item_user:
intent = new Intent(this, UserInfoActivity.class);
startActivity(intent);
return true;
运行程序,效果如下:
网友评论