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