Android开发 在子线程进行登录操作
注意:
在android开发中,主线程不能进行耗时操作,所以我们经常把耗时操作放在子线程中进行,那么就需要子线程与主线程相互交流,就需要使用到handler. 而在使用handler过程中,如果对handler使用不太熟练的话就偶尔会出现
Can't create handler inside thread that has not called Looper.prepare()的报错异常。
之前在Handler的原理的博文中有讲到,Handler的使用会依靠Looper循环来发送消息,如果不创建Looper对象,消息就无法发送,系统就会崩溃。
那么为什么使用handler有时候可以运行,有时候不能运行呢? 其实就是如果在主线程中创建handler时,系统会自动创建Looper,但是在子线程中创建handler时,是不会自动创建Looper的,
此时如果不手动创建Looper,系统就会崩溃。
一、在LoginActivity点击登录按钮
public void onClick(View v) { switch (v.getId()){ case R.id.login_btn: //登录
//获取输入框信息 String name = lg_username.getText().toString().trim(); String password = lg_password.getText().toString().trim(); if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(password)) { UserBean userBean = new UserBean(); userBean.setUserName(name); userBean.setUserPassword(password); userBean.setBalance(0.0); //在这开启子线程 } }
二、在onClick()方法中开启子线程
//显示正在登录 dialog.showProgressDialog(LoginActivity.this,"提示","正在登录..."); new Thread(new Runnable() { @Override public void run() { try { String result = new DealData().getDateFromSever(Constance.LOGIN,userBean); UserBean resultUser = JSON.parseObject(result,UserBean.class); Message msg = new Message(); Bundle bundle = new Bundle(); bundle.putSerializable("curUser",resultUser); bundle.putString("password",password); msg.setData(bundle); msg.what = 1; handler.sendMessage(msg); }catch (Exception e){ e.printStackTrace(); } } }).start(); } else { Toast.makeText(this, "请输入你的用户名或密码!", Toast.LENGTH_SHORT).show(); } break; }
三、主线程的handler处理消息
//主线程中接收子线程发送的消息并处理 private Handler handler=new Handler(){ @SuppressLint("HandlerLeak") public void handleMessage(Message msg){ try { switch (msg.what){ case 1: UserBean resultUser = (UserBean) msg.getData().getSerializable("curUser"); String password = msg.getData().getString("password"); if(resultUser!=null&&resultUser.getUserName()!=null){ dialog.hideProgressDialog(); //判断 if (password.equals(resultUser.getUserPassword())){ new ShowMassage().showMsg("登录成功!",LoginActivity.this); Intent intent1 = new Intent(LoginActivity.this,MainActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable("curUser",resultUser); intent1.putExtras(bundle); startActivity(intent1); finish();//销毁此Activity }else{ new ShowMassage().showMsg("用户名或密码错误!",LoginActivity.this); } }else{ dialog.hideProgressDialog(); new ShowMassage().showMsg("您未注册!",LoginActivity.this); } default: Log.e("400", " handler fail in send" ); } }catch (Exception e){ e.printStackTrace(); } } };
四、所有代码
activity_login.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" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:background="@drawable/app_bg"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="100dp" android:layout_marginLeft="20dp" android:layout_marginRight="20dp"> <!--圆形图片--> <com.google.android.material.imageview.ShapeableImageView android:id="@+id/login_avatar" android:layout_width="100dp" android:layout_height="100dp" android:layout_centerHorizontal="true" android:src="@drawable/logo" app:shapeAppearanceOverlay="@style/circleImageStyle" /> <EditText android:id="@+id/lg_username" android:layout_width="match_parent" android:layout_height="60dp" android:layout_below="@id/login_avatar" android:layout_alignParentEnd="true" android:layout_marginTop="27dp" android:layout_marginEnd="0dp" android:drawablePadding="5dp" android:hint="用户名" android:maxLines="1" /> <EditText android:id="@+id/lg_password" android:layout_width="match_parent" android:layout_height="60dp" android:layout_below="@id/lg_username" android:drawablePadding="5dp" android:hint="密码" android:inputType="textPassword" android:maxLines="1" /> <LinearLayout android:id="@+id/ly" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/lg_password" android:orientation="horizontal"> <CheckBox android:id="@+id/lg_rememberPsd" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="5" android:text="记住密码" android:textColor="#1E90FF" /> <TextView android:id="@+id/lg_forgetPsd" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="忘记密码" android:textColor="#1E90FF" /> </LinearLayout> <Button android:id="@+id/login_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/ly" android:layout_centerHorizontal="true" android:layout_marginTop="30dp" android:background="@drawable/search_shape_btn_accent" android:text="登录" android:textColor="#FFFFFF" android:textSize="18sp" /> </RelativeLayout> <TextView android:id="@+id/lg_register" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="9dp" android:layout_gravity="right" android:layout_marginRight="20dp" android:text="没有账号?立即注册" android:textColor="#1E90FF"/> <TextView android:id="@+id/lg_other" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="其他登录方式" android:layout_centerHorizontal="true" android:layout_marginTop="150dp" android:layout_gravity="center_horizontal"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="15dp"> <ImageView android:id="@+id/lg_qq" android:layout_width="30dp" android:layout_height="30dp" android:src="@drawable/qq" android:layout_marginRight="15dp"/> <ImageView android:id="@+id/lg_wechat" android:layout_width="30dp" android:layout_height="30dp" android:src="@drawable/wechat"/> </LinearLayout> </LinearLayout>
LoginActivity.java
package com.example.campus.app; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.annotation.SuppressLint; import android.app.ProgressDialog; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.WindowManager; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.alibaba.fastjson.JSON; import com.example.campus.R; import com.example.campus.bean.Result; import com.example.campus.bean.UserBean; import com.example.campus.utils.Constance; import com.example.campus.utils.DealData; import com.example.campus.utils.LoadingDataUtil; import com.example.campus.utils.MainConstant; import com.example.campus.utils.ShowMassage; import com.google.android.material.imageview.ShapeableImageView; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; import okhttp3.Call; import okhttp3.Callback; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; /** * 此类 implements View.OnClickListener 之后, * 就可以把onClick事件写到onCreate()方法之外 * 这样,onCreate()方法中的代码就不会显得很冗余 */ public class LoginActivity extends AppCompatActivity implements View.OnClickListener { private ShapeableImageView lg_avatar; private EditText lg_username, lg_password; private TextView lg_forgetPsd; private TextView lg_register; private Button login_btn; private ImageView lg_qq; private ImageView lg_wechat; private LoadingDataUtil dialog = new LoadingDataUtil(); //声明主线程的handler //主线程中接收子线程发送的消息并处理 private Handler handler=new Handler(){ @SuppressLint("HandlerLeak") public void handleMessage(Message msg){ try { switch (msg.what){ case 1: UserBean resultUser = (UserBean) msg.getData().getSerializable("curUser"); String password = msg.getData().getString("password"); if(resultUser!=null&&resultUser.getUserName()!=null){ dialog.hideProgressDialog(); //判断 if (password.equals(resultUser.getUserPassword())){ new ShowMassage().showMsg("登录成功!",LoginActivity.this); Intent intent1 = new Intent(LoginActivity.this,MainActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable("curUser",resultUser); intent1.putExtras(bundle); startActivity(intent1); finish();//销毁此Activity }else{ new ShowMassage().showMsg("用户名或密码错误!",LoginActivity.this); } }else{ dialog.hideProgressDialog(); new ShowMassage().showMsg("您未注册!",LoginActivity.this); } default: Log.e("400", " handler fail in send" ); } }catch (Exception e){ e.printStackTrace(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);//禁止横屏 setContentView(R.layout.activity_login); initView();//初始化界面 } private void initView() { //初始化控件 lg_avatar = findViewById(R.id.login_avatar); lg_username = findViewById(R.id.lg_username); lg_password = findViewById(R.id.lg_password); lg_forgetPsd = findViewById(R.id.lg_forgetPsd); login_btn = findViewById(R.id.login_btn); lg_register = findViewById(R.id.lg_register); lg_qq = findViewById(R.id.lg_qq); lg_wechat = findViewById(R.id.lg_wechat); login_btn.setOnClickListener(this); lg_register.setOnClickListener(this); lg_forgetPsd.setOnClickListener(this); lg_qq.setOnClickListener(this); lg_wechat.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.lg_register: //注册 Intent intent = new Intent(LoginActivity.this, RegisteredActivity.class);//跳转到注册界面 startActivity(intent); finish(); break; case R.id.lg_forgetPsd: Intent intent2 = new Intent(LoginActivity.this,PhoneLoginActivity.class); startActivity(intent2); break; case R.id.login_btn: //登录 String name = lg_username.getText().toString().trim(); String password = lg_password.getText().toString().trim(); if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(password)) { UserBean userBean = new UserBean(); userBean.setUserName(name); userBean.setUserPassword(password); userBean.setBalance(0.0); //显示正在登录 dialog.showProgressDialog(LoginActivity.this,"提示","正在登录..."); new Thread(new Runnable() { @Override public void run() { try { String result = new DealData().getDateFromSever(Constance.LOGIN,userBean); UserBean resultUser = JSON.parseObject(result,UserBean.class); Message msg = new Message(); Bundle bundle = new Bundle(); bundle.putSerializable("curUser",resultUser); bundle.putString("password",password); msg.setData(bundle); msg.what = 1; handler.sendMessage(msg); }catch (Exception e){ e.printStackTrace(); } } }).start(); } else { Toast.makeText(this, "请输入你的用户名或密码!", Toast.LENGTH_SHORT).show(); } break; } } }
ShowMassage.java
package com.example.campus.utils; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.view.Gravity; import android.widget.Toast; import com.example.campus.app.RegisteredActivity; public class ShowMassage { public void showMsg(String msg, Context mContext) { Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { //放在UI线程弹Toast Toast toast = Toast.makeText(mContext,msg,Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER,0,0); toast.show(); } }); } }
DealData.java
//进行http请求并获取返回的数据 public String getDateFromSever(String url, UserBean userBean) { try { OkHttpClient client = new OkHttpClient(); RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), JSON.toJSON(userBean).toString()); Request request = new Request.Builder() .url(url) .addHeader("key","value") .post(requestBody) .build(); Response response = client.newCall(request).execute(); Log.d("100", "Ipaws response="+response); String responseData = response.body().string(); if (response.isSuccessful()) { return responseData; }else { Log.d("400", "responseData: error"); } } catch (Exception e) { e.printStackTrace(); } return null; }