本項目來自菜鳥窩,有興趣者點擊http://www.cniao5.com/course/
項目已經做完,
https://github.com/15829238397/CN5E-shop
仿京東商城系列0------項目簡介
仿京東商城系列1------fragmentTabHost實現底部導航欄
仿京東商城系列2------自定義toolbar
仿京東商城系列3------封裝Okhttp
仿京東商城系列4------輪播廣告條
仿京東商城系列5------商品推薦欄
仿京東商城系列6------下拉刷新上拉加載的商品列表
仿京東商城系列7------商品分類頁面
仿京東商城系列8------自定義的數量控制器
仿京東商城系列9------購物車數據存儲器實現
仿京東商城系列10------添加購物車,管理購物車功能實現
仿京東商城系列11------商品排序功能以及布局切換實現(Tablayout)
仿京東商城系列12------商品詳細信息展示(nativie與html交互)
仿京東商城系列13------商品分享(shareSDK)
仿京東商城系列14------用戶登錄以及app登錄攔截
仿京東長城系列15------用戶注冊,SMSSDK集成
仿京東商城系列16------支付SDK集成
仿京東商城系列17------支付功能實現
仿京東商城系列18------xml文件讀取(地址選擇器)
仿京東商城系列19------九宮格訂單展示
仿京東商城系列20------終章
前言
本次將完成菜鳥商城的登錄功能,以及app登陸攔截。登錄想必大家都懂,那什么叫登錄攔截呢?
登陸攔截的意思就是,假如你還沒有登錄該app,但是你直接點擊了我的訂單功能,此時app就會自動跳轉到登錄界面讓你完成登錄,待登錄完畢以后,再直接跳轉到目標頁面(也就是本例中的訂單頁面),效果圖如下:
內容
界面分析
- 我的界面由一個自定義ToolBar與若干個Text,以及一個退出登錄按鈕。具體代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.cne_shop.widget.CnToolbar
android:id="@+id/toolBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:minWidth="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:titleTextColor="@color/white"
app:isShowSearchView="false"
></com.example.cne_shop.widget.CnToolbar>
<View
style="@style/line_max_vertical"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:id="@+id/my_list"
android:text=" 我的訂單"
android:gravity="center_vertical"
android:background="@color/white"
android:drawableLeft="@drawable/icon_list_o"
/>
<View
style="@style/line_vertical"
></View>
<TextView
android:id="@+id/my_favorite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:drawableLeft="@drawable/icon_favorite"
android:gravity="center_vertical"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text=" 我的收藏" />
<View
style="@style/line_vertical"
></View>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingBottom="5dp"
android:gravity="center_vertical"
android:text=" 收貨地址"
android:background="@color/white"
android:drawableLeft="@drawable/icon_location"
android:id="@+id/my_consignee"/>
<View
style="@style/line_max_vertical"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="退出登錄"
android:id="@+id/loginOut"
android:background="@color/red"
android:visibility="gone"
android:textColor="@color/white"/>
</LinearLayout>
- 用戶登錄界面就如所有的界面一樣,不做贅述
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.cne_shop.widget.CnToolbar
android:id="@+id/toolBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:minWidth="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:leftButtonIcon="@drawable/icon_back_32px"
app:title="@string/title_login"
android:titleTextColor="@color/white"
app:isShowSearchView="false"
></com.example.cne_shop.widget.CnToolbar>
<View
style="@style/line_max_vertical"
></View>
<com.example.cne_shop.widget.MyEditText
android:id="@+id/userId"
android:layout_width="match_parent"
android:layout_height="35dp"
android:background="@color/white"
android:hint="@string/text_user"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:enabled="true"
android:textSize="14sp"
android:drawableLeft="@drawable/icon_telphone_32"/>
<View
style="@style/line_vertical"/>
<com.example.cne_shop.widget.MyEditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="35dp"
android:background="@color/white"
android:enabled="true"
android:hint="@string/text_pass"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:drawableLeft="@drawable/icon_lock"
android:textSize="14sp" />
<View
style="@style/line_max_vertical"
></View>
<Button
android:id="@+id/button_log"
android:layout_width="match_parent"
android:layout_height="35dp"
android:background="@color/red"
android:text="@string/but_login"
android:textColor="@color/white" />
<View
style="@style/line_max_vertical"
></View>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true">
<TextView
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:id="@+id/register"
android:textColor="@color/red"
android:clickable="true"
android:text="@string/but_regist"/>
<TextView
android:paddingRight="10dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:id="@+id/forgetPass"
android:clickable="true"
android:textColor="@color/red"
android:text="@string/but_forget_pass"/>
</RelativeLayout>
</LinearLayout>
功能分析
- 用戶登錄
1.用戶通過okhttp向服務器發出請求。
String uri = Contents.API.LOGIN ;
Map< String , String > params = new HashMap<String, String>() ;
params.put("phone" , phoneNum ) ;
params.put("password" , DESUtil.encode(Contents.DES_KEY , pwd)) ;
okhttpHelper.doPost(uri, new loadingSpotsDialog<LoginRespMsg<User>>(LoginActivity.this ) {
@Override
public void onErroe(Response response, int responseCode, Exception e) throws IOException {
this.closeSpotsDialog();
}
@Override
public void callBackSucces(Response response, LoginRespMsg<User> userLoginRespMsg) throws IOException {
this.closeSpotsDialog();
if(userLoginRespMsg.getStatus() == 1){
MyApplication.getInstance().putUser(userLoginRespMsg.getData() , userLoginRespMsg.getTocken());
closeKeyMode() ;
if (null == MyApplication.getInstance().getIntent()){
setResult(RESULT_OK);
finish();
}else {
MyApplication.jumpToTargetoActivity(LoginActivity.this);
finish();
}
}else {
showLoginErrorMsg() ;
phone.setText("");
password.setText("");
}
}
}, params);
3.新建工具類,從SharedPreferences存取用戶信息。
package com.example.cne_shop.utils;
import android.content.Context;
import android.text.TextUtils;
import com.example.cne_shop.bean.User;
import com.example.cne_shop.contents.Contents;
/**
* Created by 博 on 2017/7/23.
*/
public class UserLocalData {
public static void putUser(Context context , User user){
String user_json = JsonUtil.toJSON(user) ;
PreferenceUtil.putString(context , Contents.USER_JSON , user_json);
}
public static void putToken(Context context , String token){
PreferenceUtil.putString(context , Contents.TOKEN , token);
}
public static User getUser(Context context){
String user_json = PreferenceUtil.getString(context , Contents.USER_JSON , null);
if (!TextUtils.isEmpty(user_json)){
return JsonUtil.fromJson(user_json , User.class) ;
}
return null ;
}
public static String getToken(Context context){
String token = PreferenceUtil.getString(context , Contents.TOKEN , null);
if (!TextUtils.isEmpty(token)){
return JsonUtil.fromJson(token , String.class) ;
}
return null ;
}
public static void clearUser(Context context){
PreferenceUtil.putString(context , Contents.USER_JSON , "");
}
public static void clearToken(Context context){
PreferenceUtil.putString(context , Contents.TOKEN , "");
}
}
2.服務器返回登陸結果,如果成功了就將用戶信息存儲到SharedPreferences中,并在Application類中建立私有變量,將SharedPreferences存儲的用戶信息,復制到Application的私有變量中。便于隨時訪問用戶信息。
package com.example.cne_shop.application;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.widget.ImageView;
import com.example.cne_shop.bean.User;
import com.example.cne_shop.utils.UserLocalData;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.squareup.picasso.Picasso;
/**
* Created by 博 on 2017/8/23.
*/
public class MyApplication extends Application {
public static final int START_FOR_RESULT = 0 ;
public static final int START_NO_RESULT = 1 ;
private User user ;
private String token ;
private static Intent intent ;
private static int startIntentStype ;
public static int getStartIntentStype() {
return startIntentStype;
}
public static void setStartIntentStype(int startIntentStype) {
MyApplication.startIntentStype = startIntentStype;
}
public Intent getIntent() {
return intent;
}
public void setIntent(Intent intent) {
this.intent = intent;
}
public static MyApplication myApplication ;
public static MyApplication getInstance(){
return myApplication ;
}
@Override
public void onCreate() {
super.onCreate();
this.myApplication = this ;
initUser();
Fresco.initialize(this);
// NineGridView.setImageLoader(new PicassoImageLoader());
}
public void initUser(){
this.user = UserLocalData.getUser(this );
this.token = UserLocalData.getToken(this) ;
}
public User getUser(){
return user ;
}
public String getToken(){
return token ;
}
public void putUser(User user , String token){
this.token = token ;
this.user = user ;
UserLocalData.putUser(this , user);
UserLocalData.putToken(this , token);
}
public void clearUser(){
this.user = null ;
this.token = null ;
UserLocalData.clearUser(this);
UserLocalData.clearToken(this);
}
public static void jumpToTargetoActivity(Activity activity){
activity.startActivity(intent);
intent = null ;
}
}
3.以后每次進入app都會自動檢測application中有沒有user值。如果有則獲得,直接加載已經登錄的用戶界面。
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
User user = MyApplication.getInstance().getUser() ;
showUser(user) ;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void showUser(User user){
if (user != null){
cnToolbar.setUserPhotoIcon(this.getActivity() , user.getLogo_url() , R.drawable.default_head );
cnToolbar.setUserNameText(user.getUsername());
loginOut.setVisibility(View.VISIBLE);
cnToolbar.setUserClickable(false);
}else {
cnToolbar.setUserNameText("點擊登錄");
cnToolbar.setUserPhotoIcon(getContext() , R.drawable.default_head);
loginOut.setVisibility(View.GONE);
cnToolbar.setUserClickable(true);
}
}
app登錄攔截
1.activity切換方面
在打開需要用戶權限的Activity時調用該方法。
protected void startActivityWithLogin(Intent intent , boolean isNeedLogin , int startIntentStype){
if (isNeedLogin){
if(MyApplication.getInstance().getUser() == null){
Intent intent1 = new Intent(this , LoginActivity.class) ;
if (MyApplication.START_FOR_RESULT == startIntentStype){
startActivityForResult(intent1 , Contents.REQUEST_CODE);
}else if(MyApplication.START_NO_RESULT == startIntentStype){
MyApplication.getInstance().setIntent(intent);
startActivity(intent1);
}
}else {
this.startActivity(intent);
}
}else {
this.startActivity(intent);
}
}
2.網絡請求方面。在我們提交成功時會獲得一個status變量,這個變量表述了我們當前的用戶信息是否可用。在提交okhttp請求時,加上status參數。
private String getUriWithParams( String uri ,Map<String , String> formData){
if (formData == null){
formData = new HashMap<>(1);
}
String symbol = null ;
int signNum = 0 ;
String token = MyApplication.getInstance().getToken() ;
if (!TextUtils.isEmpty(token)){
formData.put("token" , MyApplication.getInstance().getToken());
}
for(String key : formData.keySet()){
symbol = (signNum++ == 0 )? "?" : "&" ;
uri = uri+symbol+key+"="+formData.get(key) ;
}
return uri ;
}
驗證status是否可用。
else if (response.code() == TOKEN_ERROR ||response.code() == TOKEN_EXPRISE ||response.code() == TOKEN_MISSING ){
callbackTokenError(callback , response) ;
}
- 如果不可用,那么要求用戶進行登錄。
public void onTokenError(Response response, int responseCode) {
Toast.makeText(mContext , "TokenError" , Toast.LENGTH_SHORT).show();
Intent intent = new Intent(mContext , LoginActivity.class);
mContext.startActivity(intent);
MyApplication.getInstance().clearUser();
}
我們的app登錄,以及登陸攔截已經完成。詳細內容點擊頁首源碼。