AndroidTCP通信:Activity页面建立连接与Fragment页面断开连接

问题:想要实现点击退出登录时,先断开TCP连接,再退出整个程序。然而在点击退出登录按钮之后,TCP一直未断开连接,只有用手机后台清理掉它,才会断开TCP连接。
一、编写一个TCP客户端工具类
public class TcpClient {
    private static final String SERVER_IP = "####";
    private static final int SERVER_PORT = ###;
    private static final String TAG = "TcpClient";//日志输出标签

    private Socket socket;//socket连接
    private BufferedReader reader;//带缓冲的输入流
    private PrintWriter writer;//带缓冲的输出流
    private ConnectionCallback connectionCallback;//接口回调,用于在连接成功或失败通知调用者
    private ReceiveCallback receiveCallback;//接口回调,用于在接收到数据或连接断开时通知调用者
    private boolean isConnected;//标识当前是否连接到服务器
    private final Object connectionLock = new Object();//锁对象

    private static final int MAX_RETRIES = 3; // 最大重试次数
    private static final int RETRY_DELAY_MS = 2000; // 重试间隔(毫秒)

    private int connectionRetries = 0; // 连接重试次数

    //连接状态的回调方法
    public interface ConnectionCallback {
        void onConnected();

        void onFailure(String errorMessage);
    }
    //数据接收和连接断开的回调方法
    public interface ReceiveCallback {
        void onDataReceived(int data);

        void onDisconnected();
    }
    //连接方法
    public void connect(ConnectionCallback callback) {
        //用synchronized来确保线程安全地执行连接操作
        synchronized (connectionLock) {
            this.connectionCallback = callback;

            Thread connectThread = new Thread(new Runnable() {
                @Override
                public void run() {
                  //通过循环尝试建立连接,重试次数不超过 MAX_RETRIES(3次)
                  while (connectionRetries < MAX_RETRIES) {
                    try {
                        synchronized (connectionLock) {
                            socket = new Socket(SERVER_IP, SERVER_PORT);
                            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                            writer = new PrintWriter(socket.getOutputStream(), true);
                            isConnected = true;

                            if (connectionCallback != null) {
                                connectionCallback.onConnected();
                            }
                        }

                        // 接收数据
                        while (isConnected) {
                            String data = reader.readLine();
                            if (data != null && receiveCallback != null) {
                                int value = Integer.parseInt(data);
                                receiveCallback.onDataReceived(value);
                                //【隐患】:回调方法ReceiveCallback中的 void onDataReceived(int data)data类型是int
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        isConnected = false;
                        connectionRetries++;

                        if (connectionRetries <= MAX_RETRIES){
                            Log.e(TAG, "连接失败正在重试 " + RETRY_DELAY_MS + "ms");
                            try{
                                Thread.sleep(RETRY_DELAY_MS);
                            }catch (InterruptedException ignored) {

                            }
                        }else{
                                Log.e(TAG, "最大重试次数后连接失败");
                                if (connectionCallback != null) {
                                    connectionCallback.onFailure("连接失败"+ e.getMessage());
                                }
                                //日志记录
                                Log.e(TAG, "连接过程中出现错误!", e);
                             }
                        }
                    }
                }
            });
            connectThread.start();
        }
    }
    //通过synchronized确保线程安全地执行断开连接操作
    public void disconnect(){
        synchronized (connectionLock) {
            disconnectInternal();
        }
    }
    //用于实际关闭连接、释放资源的操作,包括关闭输入输出流和套接字
    public void disconnectInternal() {
        isConnected = false;

        try {
            if (reader != null) {
                reader.close();
                //reader = null;
            }

            if (writer != null) {
                writer.close();
                //writer = null;
            }

            if (socket != null) {
                socket.close();
                //socket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
            //记录异常信息
            Log.e(TAG, "关闭资源时出错!", e);
        }
    }
    //用于设置接收数据回调,以便在数据接收时通知调用者
    public void setReceiveCallback(ReceiveCallback callback) {
        this.receiveCallback = callback;
    }
    //用于发送数据到服务器,通过输出流将数据发送出去
    public void sendData(String data) {
        if (writer != null) {
            writer.println(data);
        }
    }
}
二、Activity登录页面:点击”登录“按钮建立TCP连接
public class LoginUpActivity extends BaseActivity {
    private EditText etAccount;//用户名
    private EditText etPwd;//密码
    private Button btnLogin;//登录按钮
    private UserHelper userHelper;//数据库
    private TcpClient tcpClient;
    private ProgressDialog progressDialog;// 进度对话框实例

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initView();//初始化界面
        userHelper = new UserHelper(this);
    }

    @Override
    protected int initLayout() {
        return R.layout.activity_login_up;
    }

    @Override
    protected void initView() {
        etAccount = findViewById(R.id.et_account);
        etPwd = findViewById(R.id.et_pwd);
        btnLogin = findViewById(R.id.btn_login);
        //获取保存的用户名
        String savedUsername = SharedPreferencesUtils.getUsername(this);
        String savedPassword = SharedPreferencesUtils.getPassword(this);
        etAccount.setText(savedUsername);
        etPwd.setText(savedPassword);

        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 在点击登录按钮后显示进度对话框
                showProgressDialog("正在建立TCP连接...");
                new TcpConnectTask().execute();
            }
        });
    }

    @Override
    protected void initData() {
    }

     // 异步任务建立TCP连接
    private class TcpConnectTask extends AsyncTask<Void, Void, Boolean> {
        // ... 其他方法 ...

        @Override
        protected Boolean doInBackground(Void... voids) {
            // 建立TCP连接
            tcpClient = new TcpClient();
            try {
                // 这里调用TcpClient中的connect方法用于建立连接
                tcpClient.connect(new TcpClient.ConnectionCallback() {
                    @Override
                    public void onConnected() {
                        // 连接成功的处理
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                // 在连接成功后,继续执行登录逻辑
                                doLogin();
                            }
                        });
                    }


                    @Override
                    public void onFailure(String errorMessage) {
                        // 连接失败的处理
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                // 连接失败时的处理
                                dismissProgressDialog();
                                Toast.makeText(LoginUpActivity.this, "TCP连接失败,请检查网络设置", Toast.LENGTH_LONG).show();
                            }
                        });
                    }
                });
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
         @Override
         protected void onPostExecute(Boolean success) {
            dismissProgressDialog();
         }
    }
    private void doLogin() {
        String username = etAccount.getText().toString().trim();
        String password = etPwd.getText().toString().trim();
        ArrayList<User> data = userHelper.getAllData();
        boolean match = false;
        for (int i = 0; i < data.size(); i++) {
            User user = data.get(i);
            if (username.equals(user.getUsername()) && password.equals(user.getPassword())) {
                match = true;
                break;
            }
        }

        if (match) {
            // 登录成功
            Toast.makeText(LoginUpActivity.this, "登录成功", Toast.LENGTH_LONG).show();
            // 导航到下一个界面
            Intent intent = new Intent(LoginUpActivity.this, PageActivity.class);
            startActivity(intent);
            finish(); // 关闭当前Activity,防止通过返回按钮回到登录界面
        } else {
            // 登录失败
            Toast.makeText(LoginUpActivity.this, "用户名或密码不正确,请重新输入", Toast.LENGTH_LONG).show();
            dismissProgressDialog();
        }
    }

    // 显示进度对话框方法
    private void showProgressDialog(String message) {
        if (progressDialog == null) {
            progressDialog = new ProgressDialog(this);
            progressDialog.setMessage(message);
            progressDialog.setCancelable(false);
            progressDialog.setCanceledOnTouchOutside(false);
            progressDialog.show();
            // 设置3秒的显示时间
            final int displayTimeMillis = 5000;
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    dismissProgressDialog();
                }
            }, displayTimeMillis);
        }
    }

    // 关闭进度对话框方法
    private void dismissProgressDialog() {
        if (progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();
            progressDialog = null; // 重置对话框实例,以便下次重新创建
        }
    }

    // 断开TCP连接方法
    public void disconnectTcpClient() {
        if (tcpClient != null) {
            tcpClient.disconnect();
        }
    }
}
三、退出登录Fragment页面:点击退出登录按钮,在退出整个app前,主动断开TCP连接
public class MyFragment extends Fragment {

    private TcpClient tcpClient;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_my, container, false);
        //头像显示
        ImageView avatarImageView = view.findViewById(R.id.img_header);
        avatarImageView.setImageResource(R.drawable.logo);

        /**可以通过 getContext()方法获取到与该Fragment 相关联的上下文Context。
         从而达到调用SharedPreferencesUtils.getUsername()的目的*/
        TextView textViewUsername = view.findViewById(R.id.my_name);
        textViewUsername.setText(SharedPreferencesUtils.getUsername(getContext()));
        //获取"退出登录"按钮id,调用以下的私有方法,执行dialog_logout页面中的退出登录按钮逻辑
        Button id = view.findViewById(R.id.bt_exit);
        id.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showLogoutConfirmationDialog();
            }
        });
        return view;
    }

    //dialog_logout页面中的退出登录按钮逻辑
    private void showLogoutConfirmationDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        View dialogView = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_logout, null);
        builder.setView(dialogView);
        Button confirmButton = dialogView.findViewById(R.id.btnConfirm);
        Button cancelButton = dialogView.findViewById(R.id.btnCancel);
        final AlertDialog dialog = builder.create();
        //确认按钮监听事件
        confirmButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 用户点击确认退出
                dialog.dismiss(); // 关闭对话框
                logout(); // 执行退出登录逻辑
            }
        });
        //取消按钮监听事件
        cancelButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 用户点击取消退出,关闭对话框
                dialog.dismiss();
            }
        });
        dialog.show();
    }

    private void logout(){
        // 断开TCP连接
        tcpClient.disconnectInternal();
        disconnectTcpClient();

    }

    private void disconnectTcpClient() {
        // 退出整个应用程序
        if (getActivity() != null) {
            getActivity().finishAffinity();
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值