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

发布于:2025-06-24 ⋅ 阅读:(16) ⋅ 点赞:(0)

目录

一、测试环境说明

二、项目简介

三、项目演示

四、部设计详情(部分)

登录页面

注册页面

首页

新增页面

五、项目源码 


一、测试环境说明

二、项目简介

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

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

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

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

三、项目演示

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

四、部设计详情(部分)

登录页面

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. 界面与功能概述

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

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

2. 核心逻辑处理

- 输入验证:检查账号密码是否为空,若为空则弹出Toast提示用户。

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

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

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

3. 数据存储机制

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

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

- 账号字符串(`key_account`)

- 密码字符串(`key_password`)

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

4. 交互与跳转设计

- 登录成功直接进入MainActivity并销毁当前页面。

- 注册按钮跳转至RegisterActivity。

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

注册页面

<?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显示标题和返回箭头,整体设计简洁。

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

2. 核心逻辑处理

- 输入验证:检查账号、密码及确认密码是否为空,若为空则弹出Toast提示并终止流程。

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

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

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

3. 交互与导航设计

- 返回逻辑:ActionBar的返回箭头点击事件直接销毁当前Activity,符合用户预期。

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

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

4. 安全与健壮性

- 密码一致性检查在客户端完成,减少无效服务器请求。

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

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

首页

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的线性布局。

2. 数据加载与展示机制

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

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

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

3. 交互与导航设计

- FAB功能:点击浮动按钮跳转AddAndEditActivity,并通过Intent传递"type=add"标识新增操作。

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

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

4. 异常处理与扩展性

- 对数据库操作进行try-catch捕获,异常时Toast提示"未知错误"。

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

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

新增页面

<?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主要实现公交线路信息的新增功能,属于数据录入模块的核心界面。

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

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

2. 交互设计特点

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

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

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

3. 数据校验机制

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

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

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

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

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

4. 技术实现亮点

- 采用异步线程处理数据库插入操作,主线程仅负责UI更新,保证界面流畅性。

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

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

五、项目源码 

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


网站公告

今日签到

点亮在社区的每一天
去签到