Retrofit+okhtp3实现登录功能( 简易音乐 三 )

关于

  本篇主要是搭建网络请求框架、使用ARouter(路由)跳转activity,编写登录功能。上一篇请看Android音乐App开发准备( 简易音乐 二 )

效果图

在这里插入图片描述
  因为涉及到个人隐私手机号,就没输入,后面你可以自己输入测试一下。
  项目目前结构图:
在这里插入图片描述

第一步,新增ARouter使用

  添加项目build引用,添加javaCompileOptions

 defaultConfig {
      ...
        //arouter跳转需要,少了的话会爆编译错误
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [moduleName: project.getName()]
            }
        }
      
    }
//路由
    implementation "com.alibaba:arouter-api:1.3.1"
    annotationProcessor "com.alibaba:arouter-compiler:1.1.4"

  在App中初始化(修改App.java):

 @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        ToastUtils.init(this,new ToastQQStyle(this));
       Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
           @Override
           public boolean queueIdle() {
               //空闲时初始化
               return false;
           }
       });
        ExecutorService pool = Executors.newFixedThreadPool(CORE_POOL_SIZE);
        pool.submit(new Runnable() {
            @Override
            public void run() {
                //吐司初始化
              
                ARouter.init(instance);
                mCountDownLatch.countDown();

            }
        });

        pool.submit(new Runnable() {
            @Override
            public void run() {
            //    mCountDownLatch.countDown();

            }
        });
        try {
            //如果await之前没有调用countDown那么就会一直阻塞在这里
            mCountDownLatch.await();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        pool.shutdown();
    }    

  编写config.java,新增路由配置以及接口url和其他配置如下:

public interface Config {

    String BaseUrl = "http://xxxxxxx:xxxx/";

    //设置默认超时时间
    int DEFAULT_TIME=6;
    
    String PERERNCE_FILE_NAME = "Tobeyr1_sp";

    //router使用
    String ROUTE_LOGIN = "/app/login";

    String ROUTE_LOGINSELECT = "/app/selectLogin";

    String ROUTE_SPLASH = "/app/splash";

    String ROUTE_HOME = "/app/main";
}

  修改SplashActivity,使用Arouter跳转页面:

//1.在使用路由跳转的页面添加这个路由路径
@Route(path = Config.ROUTE_SPLASH)
public class SplashActivity extends BaseActivity {

    //计时器
    private CountDownTimer countDownTimer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //防止安装完直接打开造成页面多次加载
        if (!isTaskRoot()) {
            final Intent intent = getIntent();
            final String intentAction = intent.getAction();
            if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
                finish();
                return;
            }
        }
        setContentView(R.layout.activity_splash);

    }

    @Override
    protected BasePresenter onCreatePresenter() {
        return null;
    }

    @Override
    protected void initData() {
        PermissionX.init(this)
                .permissions(ARR_NEED_PERMISSIONS)
                .request((allGranted, grantedList, deniedList) -> {
                    if (allGranted){
                        //开始倒计时
                        startCountDown();
                    }else {
                        ToastUtils.show("缺少运行必需权限");
                    }
                });
    }

    /**
     * 判断是否需要检测,防止不停的弹框
     */

    public boolean checkPermissionMethod(@NonNull String permission) {
        return ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED;
    }


    private void startCountDown() {
        countDownTimer = new CountDownTimer(2000,1000) {
            @Override
            public void onTick(long millisUntilFinished) {

            }

            @Override
            public void onFinish() {
               //倒计时结束2s
               //2.使用config配置文件中的路径地址跳转
                ARouter.getInstance()
                        .build(Config.ROUTE_LOGINSELECT)//跳转到选择按钮页面
                        .navigation(SplashActivity.this);
                finish();
            }
        };
        countDownTimer.start();
    }

    @Override
    protected void initModule() {

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //防止异常奔溃造成内存泄露
        if (countDownTimer !=null){
            countDownTimer.cancel();
            countDownTimer = null;
        }
    }

    @Override
    public void finish() {
        super.finish();
        if (countDownTimer !=null){
            countDownTimer.cancel();
            countDownTimer = null;
        }
    }
}

  添加LoginSelectActivity页面,修改activity_login_select.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    android:background="@color/colorPrimary"
    tools:context=".login.mvp.view.LoginSelectActivity">

    <ImageView
        android:id="@+id/image1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="@dimen/dp_120"
        android:src="@drawable/launcher_back" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_below="@+id/image1"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/app_name"
        android:layout_marginTop="16dp"
        android:textStyle="bold"
        android:textSize="18sp"
        android:textColor="#2c2c2c"/>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">

        <Button
            android:id="@+id/btn_phone_login"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dp_40"
            android:layout_centerInParent="true"
            android:layout_marginStart="@dimen/dp_80"
            android:layout_marginTop="@dimen/dp_40"
            android:layout_marginEnd="@dimen/dp_80"
            android:layout_marginBottom="@dimen/dp_120"
            android:background="@drawable/shape_btn_login"
            android:text="@string/login_phone_number"
            android:textColor="@color/colorPrimary" />
    </RelativeLayout>
</RelativeLayout>

  添加按钮的背景样式shape_btn_login.xml

<shape android:shape="rectangle"
    xmlns:android="http://schemas.android.com/apk/res/android" >
    <corners android:radius="@dimen/dp_30"/>
    <solid android:color="#FFFFFF"/>
</shape>

  修改LoginSelectActivity.java类:

//路由路径
@Route(path = Config.ROUTE_LOGINSELECT)
public class LoginSelectActivity extends BaseActivity {

    @BindView(R.id.btn_phone_login)
    Button button_login;

    private long firstTime = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login_select);
    }

    @Override
    protected BasePresenter onCreatePresenter() {
        return null;
    }

    @Override
    protected void initData() {
        button_login.setOnClickListener(v -> {
            ARouter.getInstance()
                    .build(Config.ROUTE_LOGIN)//跳转到login页面
                    .withFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK)
                    .navigation(LoginSelectActivity.this);

        });
    }

    @Override
    protected void initModule() {

    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() ==KeyEvent.ACTION_UP){
           long secondTime = System.currentTimeMillis();
           if (secondTime - firstTime >2000){
               ToastUtils.show("再按一次退出程序");
               firstTime = secondTime;
               return true;
           }else {
               AppManager.getAppManager().AppExit();
           }
        }
        return super.onKeyDown(keyCode, event);
    }
}

第二步,编写Retrofit+okhttp3网络请求框架

  在data/retrofit/下新增RetrofitUtils.java文件:

public class RetrofitUtils {

   public static ApiService apiService;

   public static ApiService getmApi(){
       if (apiService == null){
           synchronized (RetrofitUtils.class){
               apiService = new RetrofitUtils().getRetrofit();
           }
       }
       return apiService;
   }

   private ApiService getRetrofit(){
       //初始化Retrofit
       ApiService apiService = initRetrofit(initClient()).create(ApiService.class);
       return apiService;
   }

/**
     * 初始化OKHttp
     */
   private OkHttpClient initClient(){
       ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(),new SharedPrefsCookiePersistor(App.getInstance()));
       return new OkHttpClient().newBuilder()
               .readTimeout(DEFAULT_TIME, TimeUnit.SECONDS)
               .writeTimeout(DEFAULT_TIME,TimeUnit.SECONDS)
               .cookieJar(cookieJar)
               .addInterceptor(new LogInterceptor())
               .connectTimeout(DEFAULT_TIME,TimeUnit.SECONDS)
               .retryOnConnectionFailure(true)
               .build();

   }

    /**
     * 初始化Retrofit
     */
   private Retrofit initRetrofit(OkHttpClient client){
       return new Retrofit.Builder()
               .client(client)
               .baseUrl(BaseUrl)
               .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
               .addConverterFactory(GsonConverterFactory.create())
               .build();
   }

}

  新增LogInterceptor.java拦截器:

/**
 *  TODO Log拦截器代码
 */
public class LogInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Log.d("拦截器---->","request:"+request.toString());
        long t1 = System.nanoTime();
        Response response = chain.proceed(chain.request());
        long t2 = System.nanoTime();
        Log.d("拦截器---->",String.format(Locale.getDefault(), "Received response for %s in %.1fms%n%s",
                response.request().url(), (t2 - t1) / 1e6d, response.headers()));
        MediaType mediaType = response.body().contentType();
        String content = response.body().string();
        Log.d("拦截器---->","response body:"+content);

        return response.newBuilder()
                .body(ResponseBody.create(mediaType,content))
                .build();
    }
}

  编写RXHelper.java实现IO/main线程切换监听:

public class RXHelper {

    public static <T> ObservableTransformer<T, T> observableIO2Main(final Context context) {
        return upstream -> {
            Observable<T> observable = upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread());
            return composeContext(context, observable);
        };
    }

    public static <T> ObservableTransformer<T, T> observableIO2Main(final RxFragment fragment) {
        return upstream -> upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()).compose(fragment.<T>bindToLifecycle());
    }

    public static <T> FlowableTransformer<T, T> flowableIO2Main() {
        return upstream -> upstream
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    private static <T> ObservableSource<T> composeContext(Context context, Observable<T> observable) {
        if(context instanceof RxActivity) {
        //实现销毁实例时候的解除订阅
            return observable.compose(((RxActivity) context).bindUntilEvent(ActivityEvent.DESTROY));
        } else if(context instanceof RxFragmentActivity){
            return observable.compose(((RxFragmentActivity) context).bindUntilEvent(ActivityEvent.DESTROY));
        }else if(context instanceof RxAppCompatActivity){
            return observable.compose(((RxAppCompatActivity) context).bindUntilEvent(ActivityEvent.DESTROY));
        }else {
            return observable;
        }
    }
}

  编写ApiService接口类,后面的接口方法都在这里定义:

public interface ApiService {

    @GET("login/cellphone")
    Observable<Login_Bean> login(@Query("phone")String phone,@Query("password")String password);

}

  其中Login_Bean实体类(在postman上请求,获取对应返回数据后,使用GsonFormat插件生成实体类):

/**
 * 手机号登录Bean
 * Created By Tobey on 2020/9/9
 */
public class Login_Bean {

   

    private int loginType;
    private int code;
    private AccountBean account;
    private String token;
    private ProfileBean profile;
    private String cookie;
    private List<BindingsBean> bindings;

    public int getLoginType() {
        return loginType;
    }

    public void setLoginType(int loginType) {
        this.loginType = loginType;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public AccountBean getAccount() {
        return account;
    }

    public void setAccount(AccountBean account) {
        this.account = account;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public ProfileBean getProfile() {
        return profile;
    }

    public void setProfile(ProfileBean profile) {
        this.profile = profile;
    }

    public String getCookie() {
        return cookie;
    }

    public void setCookie(String cookie) {
        this.cookie = cookie;
    }

    public List<BindingsBean> getBindings() {
        return bindings;
    }

    public void setBindings(List<BindingsBean> bindings) {
        this.bindings = bindings;
    }

    public static class AccountBean {
       

        private int id;
        private String userName;
        private int type;
        private int status;
        private int whitelistAuthority;
        private long createTime;
        private String salt;
        private int tokenVersion;
        private int ban;
        private int baoyueVersion;
        private int donateVersion;
        private int vipType;
        private long viptypeVersion;
        private boolean anonimousUser;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }

        public int getStatus() {
            return status;
        }

        public void setStatus(int status) {
            this.status = status;
        }

        public int getWhitelistAuthority() {
            return whitelistAuthority;
        }

        public void setWhitelistAuthority(int whitelistAuthority) {
            this.whitelistAuthority = whitelistAuthority;
        }

        public long getCreateTime() {
            return createTime;
        }

        public void setCreateTime(long createTime) {
            this.createTime = createTime;
        }

        public String getSalt() {
            return salt;
        }

        public void setSalt(String salt) {
            this.salt = salt;
        }

        public int getTokenVersion() {
            return tokenVersion;
        }

        public void setTokenVersion(int tokenVersion) {
            this.tokenVersion = tokenVersion;
        }

        public int getBan() {
            return ban;
        }

        public void setBan(int ban) {
            this.ban = ban;
        }

        public int getBaoyueVersion() {
            return baoyueVersion;
        }

        public void setBaoyueVersion(int baoyueVersion) {
            this.baoyueVersion = baoyueVersion;
        }

        public int getDonateVersion() {
            return donateVersion;
        }

        public void setDonateVersion(int donateVersion) {
            this.donateVersion = donateVersion;
        }

        public int getVipType() {
            return vipType;
        }

        public void setVipType(int vipType) {
            this.vipType = vipType;
        }

        public long getViptypeVersion() {
            return viptypeVersion;
        }

        public void setViptypeVersion(long viptypeVersion) {
            this.viptypeVersion = viptypeVersion;
        }

        public boolean isAnonimousUser() {
            return anonimousUser;
        }

        public void setAnonimousUser(boolean anonimousUser) {
            this.anonimousUser = anonimousUser;
        }
    }

    public static class ProfileBean {
        

        private String description;
        private int userId;
        private int accountStatus;
        private int vipType;
        private int gender;
        private long avatarImgId;
        private String nickname;
        private long birthday;
        private int city;
        private int userType;
        private long backgroundImgId;
        private String avatarUrl;
        private boolean defaultAvatar;
        private int province;
        private int djStatus;
        private ExpertsBean experts;
        private boolean mutual;
        private Object remarkName;
        private Object expertTags;
        private int authStatus;
        private boolean followed;
        private String backgroundUrl;
        private String detailDescription;
        private String avatarImgIdStr;
        private String backgroundImgIdStr;
        private String signature;
        private int authority;
        private String avatarImgId_str;
        private int followeds;
        private int follows;
        private int eventCount;
        private int playlistCount;
        private int playlistBeSubscribedCount;

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public int getUserId() {
            return userId;
        }

        public void setUserId(int userId) {
            this.userId = userId;
        }

        public int getAccountStatus() {
            return accountStatus;
        }

        public void setAccountStatus(int accountStatus) {
            this.accountStatus = accountStatus;
        }

        public int getVipType() {
            return vipType;
        }

        public void setVipType(int vipType) {
            this.vipType = vipType;
        }

        public int getGender() {
            return gender;
        }

        public void setGender(int gender) {
            this.gender = gender;
        }

        public long getAvatarImgId() {
            return avatarImgId;
        }

        public void setAvatarImgId(long avatarImgId) {
            this.avatarImgId = avatarImgId;
        }

        public String getNickname() {
            return nickname;
        }

        public void setNickname(String nickname) {
            this.nickname = nickname;
        }

        public long getBirthday() {
            return birthday;
        }

        public void setBirthday(long birthday) {
            this.birthday = birthday;
        }

        public int getCity() {
            return city;
        }

        public void setCity(int city) {
            this.city = city;
        }

        public int getUserType() {
            return userType;
        }

        public void setUserType(int userType) {
            this.userType = userType;
        }

        public long getBackgroundImgId() {
            return backgroundImgId;
        }

        public void setBackgroundImgId(long backgroundImgId) {
            this.backgroundImgId = backgroundImgId;
        }

        public String getAvatarUrl() {
            return avatarUrl;
        }

        public void setAvatarUrl(String avatarUrl) {
            this.avatarUrl = avatarUrl;
        }

        public boolean isDefaultAvatar() {
            return defaultAvatar;
        }

        public void setDefaultAvatar(boolean defaultAvatar) {
            this.defaultAvatar = defaultAvatar;
        }

        public int getProvince() {
            return province;
        }

        public void setProvince(int province) {
            this.province = province;
        }

        public int getDjStatus() {
            return djStatus;
        }

        public void setDjStatus(int djStatus) {
            this.djStatus = djStatus;
        }

        public ExpertsBean getExperts() {
            return experts;
        }

        public void setExperts(ExpertsBean experts) {
            this.experts = experts;
        }

        public boolean isMutual() {
            return mutual;
        }

        public void setMutual(boolean mutual) {
            this.mutual = mutual;
        }

        public Object getRemarkName() {
            return remarkName;
        }

        public void setRemarkName(Object remarkName) {
            this.remarkName = remarkName;
        }

        public Object getExpertTags() {
            return expertTags;
        }

        public void setExpertTags(Object expertTags) {
            this.expertTags = expertTags;
        }

        public int getAuthStatus() {
            return authStatus;
        }

        public void setAuthStatus(int authStatus) {
            this.authStatus = authStatus;
        }

        public boolean isFollowed() {
            return followed;
        }

        public void setFollowed(boolean followed) {
            this.followed = followed;
        }

        public String getBackgroundUrl() {
            return backgroundUrl;
        }

        public void setBackgroundUrl(String backgroundUrl) {
            this.backgroundUrl = backgroundUrl;
        }

        public String getDetailDescription() {
            return detailDescription;
        }

        public void setDetailDescription(String detailDescription) {
            this.detailDescription = detailDescription;
        }

        public String getAvatarImgIdStr() {
            return avatarImgIdStr;
        }

        public void setAvatarImgIdStr(String avatarImgIdStr) {
            this.avatarImgIdStr = avatarImgIdStr;
        }

        public String getBackgroundImgIdStr() {
            return backgroundImgIdStr;
        }

        public void setBackgroundImgIdStr(String backgroundImgIdStr) {
            this.backgroundImgIdStr = backgroundImgIdStr;
        }

        public String getSignature() {
            return signature;
        }

        public void setSignature(String signature) {
            this.signature = signature;
        }

        public int getAuthority() {
            return authority;
        }

        public void setAuthority(int authority) {
            this.authority = authority;
        }

        public String getAvatarImgId_str() {
            return avatarImgId_str;
        }

        public void setAvatarImgId_str(String avatarImgId_str) {
            this.avatarImgId_str = avatarImgId_str;
        }

        public int getFolloweds() {
            return followeds;
        }

        public void setFolloweds(int followeds) {
            this.followeds = followeds;
        }

        public int getFollows() {
            return follows;
        }

        public void setFollows(int follows) {
            this.follows = follows;
        }

        public int getEventCount() {
            return eventCount;
        }

        public void setEventCount(int eventCount) {
            this.eventCount = eventCount;
        }

        public int getPlaylistCount() {
            return playlistCount;
        }

        public void setPlaylistCount(int playlistCount) {
            this.playlistCount = playlistCount;
        }

        public int getPlaylistBeSubscribedCount() {
            return playlistBeSubscribedCount;
        }

        public void setPlaylistBeSubscribedCount(int playlistBeSubscribedCount) {
            this.playlistBeSubscribedCount = playlistBeSubscribedCount;
        }

        public static class ExpertsBean {
        }
    }

    public static class BindingsBean {
       

        private int userId;
        private String tokenJsonStr;
        private int expiresIn;
        private int refreshTime;
        private boolean expired;
        private String url;
        private long bindingTime;
        private long id;
        private int type;

        public int getUserId() {
            return userId;
        }

        public void setUserId(int userId) {
            this.userId = userId;
        }

        public String getTokenJsonStr() {
            return tokenJsonStr;
        }

        public void setTokenJsonStr(String tokenJsonStr) {
            this.tokenJsonStr = tokenJsonStr;
        }

        public int getExpiresIn() {
            return expiresIn;
        }

        public void setExpiresIn(int expiresIn) {
            this.expiresIn = expiresIn;
        }

        public int getRefreshTime() {
            return refreshTime;
        }

        public void setRefreshTime(int refreshTime) {
            this.refreshTime = refreshTime;
        }

        public boolean isExpired() {
            return expired;
        }

        public void setExpired(boolean expired) {
            this.expired = expired;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public long getBindingTime() {
            return bindingTime;
        }

        public void setBindingTime(long bindingTime) {
            this.bindingTime = bindingTime;
        }

        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }
    }
}

编写 LoginContract接口类管理Model与Presenter:

public interface LoginContract {
    interface View extends BaseView{

        void onLoginSuccess(Login_Bean bean);

        void onLoginFail(String e);
    }

    interface Model extends BaseModel{
        Observable<Login_Bean> login(String phone,String password);
    }
    abstract class Presenter extends BasePresenter<View,Model>{
        public abstract void login(String phone,String password);
    }
}

  编写LoginModel继承LoginContract.Model

public class LoginModel implements LoginContract.Model {

    @Override
    public Observable<Login_Bean> login(String phone, String password) {
        return RetrofitUtils.getmApi().login(phone, password);
    }
}

  编写LoginPresenter继承LoginContract.Presenter

public class LoginPresenter extends LoginContract.Presenter {


    Disposable disposable;

    public LoginPresenter(LoginContract.View view){
        this.mView = view;
        this.mModel = new LoginModel();
    }

    @Override
    public void login(String phone, String password) {
        mModel.login(phone, password)
               .compose(RXHelper.observableIO2Main(App.getInstance()))
               .subscribe(new Observer<Login_Bean>() {
                   @Override
                   public void onSubscribe(Disposable d) {
                       disposable = d;
                   }

                   @Override
                   public void onNext(Login_Bean bean) {
                        mView.onLoginSuccess(bean);
                   }

                   @Override
                   public void onError(Throwable e) {
                       mView.onLoginFail(e.getMessage());
                   }

                   @Override
                   public void onComplete() {
                         if (disposable != null && !disposable.isDisposed()) {
                           disposable.dispose();
                           disposable = null;
                       }
                   }
               });

    }
}

修改LoginActivity页面

  效果图,背景图会在下面贴出链接(仅供参考):
在这里插入图片描述
  图片链接:提取码:tf7x

  修改activity_login.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    android:background="@mipmap/login_background_image"
    tools:context=".login.mvp.view.LoginActivity">
    <include
        android:id="@+id/title"
        layout="@layout/common_title"/>
    <TextView
        android:id="@+id/login_name"
        android:layout_width="wrap_content"
        android:text="@string/login_title"
        android:textSize="@dimen/sp_28"
        android:textStyle="bold"
        android:layout_marginTop="@dimen/dp_130"
        android:layout_centerHorizontal="true"
        android:textColor="@android:color/white"
        android:layout_below="@+id/title"
        android:layout_height="wrap_content"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:id="@+id/layout_view1"
        android:layout_weight="1"
        android:layout_marginLeft="25dp"
        android:layout_marginRight="25dp"
        android:background="@drawable/ic_view_border_normal"
        android:layout_marginTop="@dimen/dp_80"
        android:layout_below="@id/login_name"
        android:orientation="horizontal"
        android:paddingBottom="10dp"
        android:paddingTop="10dp">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="30dp"
            android:src="@mipmap/login_user" />

        <EditText
            android:id="@+id/edit_usercode"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="35dp"
            android:layout_weight="1"
            android:background="@null"
            android:hint="输入手机号"
            android:layout_marginRight="@dimen/dp_30"
            android:inputType="number"
            android:maxLength="20"
            android:maxLines="1"
            android:textColorHint="#c9c9c9"
            android:textColor="#333333"
            android:textSize="15sp" />

    </LinearLayout>


    <LinearLayout
        android:id="@+id/layout_view2"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_below="@+id/layout_view1"
        android:layout_marginTop="@dimen/dp_30"
        android:layout_weight="1"
        android:layout_marginLeft="25dp"
        android:layout_marginRight="25dp"
        android:background="@drawable/ic_view_border_normal"
        android:orientation="horizontal"
        android:paddingBottom="10dp"
        android:paddingTop="10dp">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="30dp"
            android:src="@mipmap/login_pasw" />

        <EditText
            android:id="@+id/edit_userpwd"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="35dp"
            android:layout_marginRight="@dimen/dp_30"
            android:layout_weight="1"
            android:background="@null"
            android:hint="输入密码"
            android:inputType="textPassword"
            android:maxLength="20"
            android:maxLines="1"
            android:textColorHint="#c9c9c9"
            android:textColor="#333333"
            android:textSize="15sp" />

    </LinearLayout>


    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_45"
        android:layout_below="@id/layout_view2"
        android:layout_marginTop="@dimen/dp_30"
        android:text="@string/login"
        android:background="@drawable/shape_btn_login_confirm"
        android:textColor="@android:color/white"
        android:layout_marginStart="@dimen/dp_60"
        android:layout_marginEnd="@dimen/dp_60"/>

</RelativeLayout>

  LinearLayout的背景图片、账号与密码的图片资源也放在上面的网盘里面了,有兴趣的可以下载下来:
在这里插入图片描述
  登录的按钮样式shape_btn_login_confirm.xml

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="@dimen/dp_10"></corners>
    <solid android:color="@color/colorPrimary"></solid>
</shape>

  修改LoginActivity.java

@Route(path = Config.ROUTE_LOGIN)
public class LoginActivity extends BaseActivity<LoginPresenter> implements LoginContract.View {
    @BindView(R.id.edit_usercode)
    EditText editText_phone;
    @BindView(R.id.edit_userpwd)
    EditText editText_psw;
    @BindView(R.id.btn_login)
    Button button_login;
    @BindView(R.id.tv_title)
    TextView textView_title;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
    }

    @Override
    protected LoginPresenter onCreatePresenter() {
        return new LoginPresenter(this);
    }

    @Override
    protected void initData() {
        button_login.setOnClickListener(v -> {
            mPresenter.login(editText_phone.getText().toString().trim(),editText_psw.getText().toString().trim());
        });
    }

    @Override
    protected void initModule() {
        //设置图片沉浸状态栏
        StatusBarUtil.setTranslucent(this,0);
    }


    @Override
    public void onLoginSuccess(Login_Bean bean) {
        ToastUtils.show("登录成功"+bean.toString());

    }

    @Override
    public void onLoginFail(String e) { 
        if (e.equals("HTTP 502 Bad Gateway")) {
            ToastUtils.show(R.string.enter_correct_password);
        } else {
            ToastUtils.show(e);
        }
    }
}

  到此,简易音乐的登录功能算是实现了,下一篇将会账号信息保存以及跳转主界面功能。有问题欢迎批评指正,觉得不错的也请点个赞奥。
  下一篇 修改登录判断以及数据保存( 简易音乐 四)

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪の星空朝酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值