网络资源模板--基于Android Studio 实现的公交线路App

目录

一、测试环境说明

二、项目简介

三、项目演示

四、部设计详情(部分))

登录页面

注册页面

首页

新增页面

五、项目源码


一、测试环境说明

二、项目简介

基于Android的公交线路查询系统旨在为乘客提供一种快速、便捷、准确的公交车路线查询方式。

通过本系统,乘客可以随时随地利用移动设备查询所需的公交车路线信息,从而提高市民的出行效率,促进城市公共交通事业的可持续发展,并进一步完善公交系统的智能化服务。

本系统采用Android平台作为开发基础,结合Java语言和SQLite数据库技术,实现了轻量级、高效的数据存储与查询功能。

系统的主要功能包括用户注册登录、公交线路查询、站点查询等并且项目带有详细的中文注释。

三、项目演示

网络资源模板--基于Android studio 公交线路APP

四、部设计详情(部分)

登录页面

java 复制代码
package com.my.myapplication.ui;
import com.my.myapplication.R;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.my.myapplication.bean.UserBean;
import com.my.myapplication.helper.MyHelper;
import com.my.myapplication.utils.SpUtils;

//登录页
public class LoginActivity extends AppCompatActivity implements View.OnClickListener {
    //是否记住账号 SharedPreferences存储用的key
    private final String key_is_remember = "key_is_remember";
    // 存储账号 SharedPreferences用的key
    private final String key_account = "ke_account";
    //存储密码 SharedPreferences用的key
    private final String key_password = "key_password";
    //账号
    private EditText mEtName;
    private EditText mEtPassword;
    //密码
    private Button mBtLogin;
    //记住密码
    private CheckBox mCkRemember;
    //注册按钮
    private TextView mTvRegister;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        设置全屏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        if (Build.VERSION.SDK_INT >= 21) {
            Window window = getWindow();
            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
            window.setStatusBarColor(Color.TRANSPARENT);
            //
        }
        setContentView(R.layout.activity_login);

        initView();
    }

    private void initView() {
        //查找控件
        mEtName = findViewById(R.id.et_name);
        mEtPassword = findViewById(R.id.et_password);
        mBtLogin = findViewById(R.id.bt_login);
        mCkRemember = findViewById(R.id.ck_remember);
        //获取是否记账密码的状态
        boolean is_remember = SpUtils.getInstance(this).getBoolean(key_is_remember, false);
//如果记住密码 则从SharedPreferences存储中获取 账号密码 并赋值给对应的控件
        if (is_remember) {
            mCkRemember.setChecked(true);
            mEtName.setText(SpUtils.getInstance(this).getString(key_account));
            mEtPassword.setText(SpUtils.getInstance(this).getString(key_password));
        }
        //绑定 登录注册按钮点击事件
        mBtLogin.setOnClickListener(this);
        mTvRegister = findViewById(R.id.tv_register);
        mTvRegister.setOnClickListener(this);
    }

    //登录注册按钮点击事件处理
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.bt_login:
                login();
                break;
            case R.id.tv_register:
                // 点注册按钮跳注册页面
                startActivity(new Intent(this, RegisterActivity.class));
                break;
        }
    }

    //登录逻辑处理
    private void login() {
        //获取账号密码
        String userName = mEtName.getText().toString().trim();
        String passWord = mEtPassword.getText().toString().trim();
        //判断账号密码是否为空 如果是则提示用户 并返回 不在继续执行后续代码
        if (TextUtils.isEmpty(userName)) {
            Toast.makeText(this, "账号必须填写", Toast.LENGTH_SHORT).show();
            return;
        }
        if (TextUtils.isEmpty(passWord)) {
            Toast.makeText(this, "密码必须填写", Toast.LENGTH_SHORT).show();
            return;
        }
//判断记住密码按钮是否是被勾选 如果是 则把记住密码的状态 账号 密码 写入SharedPreferences中
        if (mCkRemember.isChecked()) {
            SpUtils.getInstance(this).putBoolean(key_is_remember, true);
            SpUtils.getInstance(this).putString(key_account, userName);
            SpUtils.getInstance(this).putString(key_password, passWord);
        } else {
            //没有勾选记住密码 清空SharedPreferences保存的 记住账号密码状态 用户名 和密码
            SpUtils.getInstance(this).putBoolean(key_is_remember, false);
            SpUtils.getInstance(this).putString(key_account, "");
            SpUtils.getInstance(this).putString(key_password, "");
        }
        //开个线程进行登录 因为耗时操作不能再ui线程中操作 否则会引起ui界面卡顿
        new Thread(new Runnable() {
            @SuppressLint("WrongConstant")
            @Override
            public void run() {

                try {
                    // 这里是调用耗时操作方法 调用数据库方法 判断账号密码是否正确
                    UserBean user = MyHelper.getInstance(LoginActivity.this).matchAccount(userName, passWord);
                    //返回不为空 则说明查到用户 账号密码正则
                    if (user != null) {
                        //再ui线程中更新ui 因为安卓不能子子线程中更新ui
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //登录成功 跳主页面 并销毁登录页面
                                startActivity(new Intent(LoginActivity.this, MainActivity.class));
                                finish();
                            }
                        });

                    } else {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //登录失败 提示用户
                                Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                            }
                        });

                    }

                } catch (Exception e) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(LoginActivity.this, "未知错误", Toast.LENGTH_SHORT).show();

                        }
                    });
                }


            }
        }).start();


    }


}
  1. 界面与功能概述

主要实现用户登录功能。界面包含账号输入框、密码输入框、登录按钮、记住密码复选框和注册跳转链接。

页面采用沉浸式状态栏设计,整体风格简洁。核心功能包括:验证用户输入、记住密码、登录跳转和注册跳转。

  1. 核心逻辑处理
  • 输入验证:检查账号密码是否为空,若为空则弹出Toast提示用户。

  • 记住密码:通过SharedPreferences持久化存储用户账号密码,勾选后下次自动填充。

  • 登录验证:通过子线程异步查询数据库(MyHelper类),匹配账号密码正确性,成功则跳转主页面,失败提示错误。

  • 线程安全:耗时的数据库操作在子线程执行,通过`runOnUiThread`安全更新UI。

  1. 数据存储机制

使用SpUtils工具类管理SP存储,保存三种数据:

  • 是否记住密码的布尔值(`key_is_remember`)

  • 账号字符串(`key_account`)

  • 密码字符串(`key_password`)

用户取消勾选时会清空存储的密码信息。

  1. 交互与跳转设计
  • 登录成功直接进入MainActivity并销毁当前页面。

  • 注册按钮跳转至RegisterActivity。

  • 错误处理涵盖空输入、账号密码不匹配及未知异常,均通过Toast友好提示。整体流程符合典型登录场景需求,兼顾用户体验与数据安全性。

注册页面

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"
    android:background="@color/white"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="50dp"
        android:layout_marginRight="30dp"
        android:orientation="vertical">


        <EditText
            android:id="@+id/et_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginRight="15dp"
            android:background="@null"
            android:hint="请输入账号"
            android:paddingLeft="10dp"
            android:paddingTop="12dp"
            android:paddingBottom="12dp"
            android:textSize="19sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#cccccc" />
    </LinearLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="10dp"
        android:layout_marginRight="30dp"
        android:layout_marginBottom="10dp"

        android:orientation="vertical">


        <EditText
            android:id="@+id/et_password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginRight="15dp"
            android:background="@null"
            android:hint="请输入密码"
            android:inputType="textPassword"
            android:paddingLeft="10dp"
            android:paddingTop="12dp"
            android:paddingBottom="12dp"

            android:textSize="19sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#cccccc" />
    </LinearLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:orientation="vertical">


        <EditText
            android:id="@+id/et_password_again"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginRight="15dp"
            android:background="@null"
            android:hint="请再次输入密码"
            android:inputType="textPassword"
            android:paddingLeft="10dp"
            android:paddingTop="12dp"
            android:paddingBottom="12dp"

            android:textSize="19sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#cccccc" />
    </LinearLayout>

    <Button
        android:id="@+id/bt_register"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="20dp"
        android:layout_marginRight="30dp"
        android:background="@drawable/bt_selector"
        android:gravity="center"
        android:paddingLeft="60dp"
        android:paddingTop="15dp"
        android:paddingRight="60dp"
        android:paddingBottom="15dp"
        android:text="注册"
        android:textColor="@color/white"
        android:textSize="18sp"
        android:textStyle="bold" />

</LinearLayout>
  1. 界面与功能概述

主要实现用户注册功能。界面包含账号输入框、密码输入框、确认密码输入框和注册按钮。

顶部ActionBar显示标题和返回箭头,整体设计简洁。

核心功能包括:输入验证、账号查重、密码一致性检查、数据写入数据库及注册结果反馈。

  1. 核心逻辑处理
  • 输入验证:检查账号、密码及确认密码是否为空,若为空则弹出Toast提示并终止流程。

  • 密码一致性:比对两次输入的密码,不一致时立即提示用户。

  • 账号查重:通过子线程查询数据库(MyHelper类),若账号已存在则提示"注册失败"。

  • 数据写入:创建UserBean对象并调用数据库插入方法,根据返回值判断注册成功与否,成功则自动关闭页面。

  1. 交互与导航设计
  • 返回逻辑:ActionBar的返回箭头点击事件直接销毁当前Activity,符合用户预期。

  • 异步处理:数据库操作在子线程执行,通过`runOnUiThread`安全更新UI,避免主线程卡顿。

  • 结果反馈:所有操作结果(成功/失败/错误)均通过Toast即时提示,用户体验友好。

  1. 安全与健壮性
  • 密码一致性检查在客户端完成,减少无效服务器请求。

  • 异常捕获全面,包括数据库操作异常和未知错误,均会提示用户。

  • 线程管理规范,耗时操作与UI更新严格分离,避免内存泄漏风险。整体流程覆盖典型注册场景,兼顾功能完整性和操作安全性。

首页

java 复制代码
package com.my.myapplication.ui;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.my.myapplication.adapter.MyAdapter;
import com.my.myapplication.bean.BusBean;
import com.my.myapplication.helper.MyHelper;

import java.util.ArrayList;
import java.util.List;import com.my.myapplication.R;

//主界面
public class MainActivity extends AppCompatActivity {

    //recyclerview 适配器
    private MyAdapter mMyAdapter;
    //recyclerview 数据
    private List<BusBean> mBeanList = new ArrayList<>();
    //浮动按钮 添加按钮
    private FloatingActionButton mFl1;

    //RecyclerView
    private RecyclerView mRecyclerview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        设置标题
        getSupportActionBar().setTitle(getResources().getString(R.string.app_name));


//查找Recyclerview控件
        mRecyclerview = findViewById(R.id.recyclerview);
        //绑定Recyclerview适配器
        mMyAdapter = new MyAdapter(MainActivity.this, mBeanList);


        //设置Recyclerview 布局管理器
        mRecyclerview.setLayoutManager(new LinearLayoutManager(MainActivity.this));
        //  mRecyclerView.setLayoutManager(new GridLayoutManager(this,3));
        //设置Recyclerview适配器
        mRecyclerview.setAdapter(mMyAdapter);
        mFl1 = findViewById(R.id.fl_1);
        //添加按钮点击处理事件
        mFl1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //跳转添加编辑界面 添加编辑公用一个界面 用intent携带的type数据区分
                Intent intent = new Intent(MainActivity.this, AddAndEditActivity.class);
                intent.putExtra("type", "add");
                startActivity(intent);
            }
        });

    }

    //界面重新可见时候调用 添加数据返回界面 从新刷新界面数据
    @Override
    public void onResume() {
        super.onResume();
        //开线程
        new Thread(new Runnable() {
            @SuppressLint("WrongConstant")
            @Override
            public void run() {
                try {
                    // 这里是调用耗时操作方法 获取该分类数据
                    mBeanList = MyHelper.getInstance(MainActivity.this).getAllData();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //更新recyclerview 显示数据
                            mMyAdapter.upDate(mBeanList);
                        }
                    });

                } catch (Exception e) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "未知错误", Toast.LENGTH_SHORT).show();

                        }
                    });
                }

            }
        }).start();


    }


    //创建菜单
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //将菜单资源加载到当前的菜单资源

        getMenuInflater().inflate(R.menu.main1, menu);

        return true;
    }

    //菜单栏 点击事件
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

//        搜索按钮
        if (item.getItemId() == R.id.id1) {
            Intent intent = new Intent(MainActivity.this, SearchActivity.class);
            startActivity(intent);

        }


        return true;
    }


}
  1. 界面与功能概述

采用RecyclerView展示数据列表(BusBean对象),顶部ActionBar显示应用名称和搜索菜单。

核心功能包括:数据列表展示、浮动按钮跳转新增页面、菜单栏搜索跳转、数据自动刷新。

界面设计遵循Material Design规范,包含FAB(浮动操作按钮)和RecyclerView的线性布局。

  1. 数据加载与展示机制
  • 异步数据加载:在onResume生命周期中启动子线程,通过MyHelper从数据库获取全部数据(getAllData()),避免主线程卡顿。

  • 列表动态更新:使用自定义Adapter(MyAdapter)绑定数据,通过upDate()方法实现数据变化时的UI刷新。

  • 线程安全控制:数据库操作在子线程完成,结果通过runOnUiThread回调更新RecyclerView,确保线程安全。

  1. 交互与导航设计
  • FAB功能:点击浮动按钮跳转AddAndEditActivity,并通过Intent传递"type=add"标识新增操作。

  • 菜单功能:右上角菜单包含搜索项(R.id.id1),点击跳转SearchActivity实现搜索功能。

  • 自动刷新:页面重新可见时(onResume)自动重载数据,保证数据时效性。

  1. 异常处理与扩展性
  • 对数据库操作进行try-catch捕获,异常时Toast提示"未知错误"。

  • RecyclerView支持切换布局管理器(注释中保留GridLayoutManager示例),便于后期扩展多样式布局。

  • 菜单资源(R.menu.main1)独立配置,方便后续功能迭代。整体架构清晰,兼顾功能完整性和可维护性。

新增页面

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    android:orientation="vertical">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

    
                <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal"
                    android:gravity="center_vertical"
                        >
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="*"
                        android:textColor="#ff0000" />
                           <TextView
                               android:id="@+id/tv_qibujia"
                                   android:layout_width="wrap_content"
                                   android:layout_height="wrap_content"
                                   android:text="起步价"
                                   />
                
android:inputType="number"
                        android:background="@drawable/llshap2"
                        android:gravity="top|left"
                        android:hint="起步价(元)"
                        android:padding="10dp"
                        android:paddingTop="12dp"
                        android:paddingBottom="12dp" />


                    </LinearLayout>
                <LinearLayout
                    android:id="@+id/ll_zuigaojia"
                    android:gravity="center_vertical"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal"
                        >
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="*"
                        android:textColor="#ff0000" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="最高价"
                        />
                    <EditText
                        android:id="@+id/et_zuigaojia"
                        android:layout_width="0dp"
                        android:layout_weight="1"
                        android:layout_height="wrap_content"
                        android:layout_margin="10dp"
                        android:inputType="number"
                        android:background="@drawable/llshap2"
                        android:gravity="top|left"
                        android:hint="最高价(元)"
                        android:padding="10dp"
                        android:paddingTop="12dp"
                        android:paddingBottom="12dp" />
                    </LinearLayout>
                <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal"
                        >
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="*"
                        android:textColor="#ff0000" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="运营时间:"
                        />
                    </LinearLayout>

                <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal"
                    android:gravity="center_vertical"
                        >
                   
                        android:id="@+id/tv_xuanzemoban"
                        android:layout_width="wrap_content"
                        android:gravity="center"
                        android:layout_height="wrap_content"
                        android:text="选择末班时间"
                        android:background="@drawable/bt_selector"
                        android:paddingLeft="20dp"
                        android:paddingRight="20dp"
                        android:paddingTop="10dp"
                        android:paddingBottom="10dp"
                        android:textColor="@color/white"
                        />
                    </LinearLayout>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:gravity="center_vertical"
                >
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="*"
                    android:textColor="#ff0000" />
               <TextView
                       android:layout_width="wrap_content"
                       android:layout_height="wrap_content"
                       android:text="发车间隔"
                       />
                <EditText
                    android:id="@+id/et_jiange"
                    android:layout_width="0dp"
                    android:layout_weight="1"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp"
                    android:background="@drawable/llshap2"
                    android:gravity="top|left"
                    android:hint="如10-15分钟"
                    android:padding="10dp"
                    android:paddingTop="12dp"
                    android:paddingBottom="12dp" />

            </LinearLayout>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_vertical"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="*"
                    android:textColor="#ff0000" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="所属城市:" />

                <EditText
                    android:id="@+id/et_chengshi"
                    android:layout_width="0dp"
                    android:layout_weight="1"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp"
                    android:background="@drawable/llshap2"
                    android:gravity="top|left"
                    android:hint="如广东省深圳市"
                    android:padding="10dp"
                    android:paddingTop="12dp"
                    android:paddingBottom="12dp" />
            </LinearLayout>
                <RadioGroup
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    >
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textSize="15sp"
                        android:text="运营状态:"/>
                    <RadioButton
                       android:id="@+id/rb_zhengchang"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:checked="true"
                        android:text="正常"/>
                    <RadioButton
                       android:id="@+id/rb_tingyun"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="停运"/>
                    <RadioButton
                        android:id="@+id/rb_shigong"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="道路施工临时更改线路"/>
                   </RadioGroup>
            <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal"
                    android:layout_marginTop="10dp"
                    android:layout_marginBottom="10dp"
                        >
                           <TextView
                               android:id="@+id/tv_addtext"
                                   android:layout_width="0dp"
                               android:layout_weight="1"
                               android:gravity="center"
                                   android:layout_height="wrap_content"
                                   android:text="添加站点"
                                   android:background="@drawable/bt_selector"
                               android:paddingLeft="20dp"
                               android:paddingRight="20dp"
                               android:paddingTop="10dp"
                               android:paddingBottom="10dp"
                               android:textColor="@color/white"
                                   />

                    </LinearLayout>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="5dp"
                android:gravity="center"

                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="*"
                    android:textColor="#ff0000" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="站点内容(最少2站)" />

            </LinearLayout>
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_weight="1"
                android:descendantFocusability="blocksDescendants"
                >
                <androidx.recyclerview.widget.RecyclerView

                    android:id="@+id/recyclerview"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                   />
            </RelativeLayout>

        </LinearLayout>

        <Button
            android:id="@+id/bt_write"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginBottom="10dp"
            android:background="@drawable/bt_selector"
            android:gravity="center"
            android:paddingLeft="60dp"
            android:paddingTop="15dp"
            android:paddingRight="60dp"
            android:paddingBottom="15dp"
            android:text="保存"
            android:textColor="@color/white"
            android:textSize="18sp"
            android:textStyle="bold" />
    </LinearLayout>


</ScrollView>
  1. 核心功能定位

该Activity主要实现公交线路信息的新增功能,属于数据录入模块的核心界面。

通过表单收集线路名称、票价模式、运营时间等关键信息,并支持动态添加公交站点。

采用"统一票价"和"分段收费"两种模式,根据用户选择动态调整表单字段,提供时间选择器等便捷输入方式。

  1. 交互设计特点
  • 动态表单:通过单选按钮切换票价模式,实时显示/隐藏"最高票价"字段,并智能调整标签文字("起步价"或"全程票价")。

  • 时间选择:集成系统原生时间选择器,对首末班车时间进行格式化处理(自动补零),提升数据规范性。

  • 站点管理:采用自定义弹窗收集站点信息,通过RecyclerView实现站点列表的动态增删,强制校验至少需要2个站点。

  1. 数据校验机制

提交时执行严格的多维度校验:

  • 必填字段非空检查(线路名称、票价等)

  • 票价模式差异化校验(分段收费需检查最高票价)

  • 业务规则校验(站点数量不得少于2个)

所有校验失败均通过Toast即时反馈,防止无效数据提交。

  1. 技术实现亮点
  • 采用异步线程处理数据库插入操作,主线程仅负责UI更新,保证界面流畅性。

  • 使用事务型操作:先插入主表数据获取ID,再批量插入关联的站点数据,确保数据完整性。

  • 通过自定义Dialog实现站点输入,结合Adapter实时更新列表,形成完整的数据采集闭环。整体设计兼顾用户体验与数据可靠性。

五、项目源码

👇👇👇👇👇快捷方式👇👇👇👇👇

相关推荐
踢球的打工仔17 小时前
PHP面向对象(7)
android·开发语言·php
安卓理事人17 小时前
安卓socket
android
安卓理事人1 天前
安卓LinkedBlockingQueue消息队列
android
万能的小裴同学1 天前
Android M3U8视频播放器
android·音视频
q***57741 天前
MySql的慢查询(慢日志)
android·mysql·adb
JavaNoober1 天前
Android 前台服务 "Bad Notification" 崩溃机制分析文档
android
王六岁1 天前
UIAutomatorViewer 安装指南 (macOS m3pro 芯片)
android studio
城东米粉儿1 天前
关于ObjectAnimator
android
zhangphil1 天前
Android渲染线程Render Thread的RenderNode与DisplayList,引用Bitmap及Open GL纹理上传GPU
android
火柴就是我1 天前
从头写一个自己的app
android·前端·flutter