IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android应用生命周期实现简单的秒表App -> 正文阅读

[移动开发]Android应用生命周期实现简单的秒表App

1、功能分析

1.1、秒表功能界面

1.2、App结构

  • 1个Activity :MainActivity
  • 1个Layout :activity_main.xml

2、开发视图布局

2.1、activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

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

        <TextView
            android:id="@+id/time_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:text="0:00:00"
            android:textAppearance="@style/TextAppearance.AppCompat.Large"
            android:textSize="80sp"/>

        <Button
            android:id="@+id/button_start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="@string/start"
            android:onClick="onClickStart"/>

        <Button
            android:id="@+id/button_stop"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="@string/stop"
            android:onClick="onClickStop"/>

        <Button
            android:id="@+id/button_reset"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="@string/reset"
            android:onClick="onClickReset"/>
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

2.2、string.xml

<resources>
    <string name="app_name">Stopwatch</string>
    <string name="start">start</string>
    <string name="stop"> Stop</string>
    <string name="reset">Reset</string>
    <string name="time">Time</string>
</resources>

3、Activity实现

3.1、MainActivity类

public class MainActivity extends AppCompatActivity {

    //计时的秒数
    private  int seconds = 0;
    //计时的状态
    private  boolean running = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //在Activity启动时,onCreate()方法中启动runTimer()
        runTimer();
    }

    //启动计时
    public void onClickStart(View view){
        running = true;
    }
    //停止计时
    public void onClickStop(View view){
        running = false;
    }
    //重置秒表
    public void onClickReset(View view){
        running = false;
        seconds = 0;
    }
  	//循环计时方法
    private void runTimer(){
        final TextView timeView = findViewById(R.id.time_view);
        //创建UI线程的handler,用于消息处理
        final Handler handler = new Handler();
        handler.post(new Runnable() {//立即交一个Runnable,任务在Runnable的run()方法中
            @Override
            public void run() {
                int hours = seconds/3600;
                int minutes = (seconds%3600)/60;
                int secs = seconds%60;
                String time = String.format("%d:%02d:%02d", hours, minutes, secs);
                timeView.setText(time);
                if(running){
                    seconds++;
                }            
                //每隔1000ms,重复提交该任务
                handler.postDelayed(this,1000);
            }
        });
    }
}

4、生命周期的应用

4.1、问题分析

  • 问题一:旋转屏幕,Android检测到屏幕方向变化,计时会重置
  • 问题二:App被切换至后台,秒表不能暂停

4.2、Activity运行过程

4.2、屏幕旋转,计时不重置

  • 设备配置变化时,如屏幕旋转,需保存状态,重启时恢复

  • 在运行后(running),销毁(onDestroy())前会调用 onSaveInstanceState(),保存状态到Bundle

    • 保存状态需要覆盖onSaveInstanceState()方法

    • Bundle可存储键值对

      bundle.put*(“name”,value)

    • 在Bundle中存储running和seconds

      @Override
      public void onSaveInstanceState(Bundle savedInstanceState){
          super.onSaveInstanceState(savedInstanceState);
          
          savedInstanceState.putInt("seconds",seconds);
          savedInstanceState.putBoolean("running",running);
      }
      
  • 在onCreate()方法中恢复,Bundle是其参数,进程第一次新建Activity时为null,
    之后为onSaveInstanceState()保存的Bundle

    • 从Bundle取出键值对

      bundle.get*(“name”);

    • 在Bundle中取出running和seconds

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          Log.d("life cycle","onCreate");
          setContentView(R.layout.activity_main);
          
          if(savedInstanceState!=null){
              seconds = savedInstanceState.getInt("seconds");
              running = savedInstanceState.getBoolean("running");
          }
          runTimer();
      }
      
  • 程序运行流程

    • 用户启动App,点击start按钮,开始计时
      runTimer()方法开始递增seconds,并显示到文本框time_view中
    • 旋转手机,Android检测到屏幕方向变化,销毁原Activity前,调用onSaveInstanceState()保存实例变量
    • Android销毁Activity,再次新建该Activity再次调用onCreate()方法,将保存的Bundle作为参数传入
    • onCreate()方法中,取出Bundle存储的值并恢复到销毁前的状态
    • runTimer()方法从旋转前的seconds继续计时

4.3、App被切换至后台,秒表可以暂停

  • 解决方法

    • 覆盖onStop(),在消失前停止计时

      @Override
      protected void onStop(){
          super.onStop();
          Log.d("life cycle","onStop");
          wasRunning = running; // 记录之前是否运行,
          running = false; //将running设置为false以停止计时
      }
      
    • 覆盖生命周期方法前,必须先调用父类的生命周期

      super.onStop();

    • 覆盖onStart(),在可见前继续计时

      @Override
      //如果之前running==true,则将running设置为true,继续计时
      protected void onStart(){
          super.onStart();
          Log.d("life cycle","onStop");
          if(wasRunning){ 
              running = true;
          }
      }
      
    • App被切换至后台,Activity对象仍存在,可以使用实例变量存储状态

      //计时的秒数
      private  int seconds = 0;
      //计时的状态
      private  boolean running = false;
      //新的变量,用于在onStop()中保存消失前running的状态
      private boolean wasRunning = false;
      
      @Override
      protected void onStop(){
          super.onStop();
          Log.d("life cycle","onStop"); //日志并暂停
          wasRunning = running;
          running = false;
      }
      
      @Override
      protected void onStart(){
          super.onStart();
          Log.d("life cycle","onStop"); //日志并恢复
          if(wasRunning){
              running = true;
          }
      }
      
    • Activity销毁前在Bundle保存wasRunning,
      Activity重新实例化后从Bundle恢复wasRunning

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          Log.d("life cycle","onCreate");
          setContentView(R.layout.activity_main);
          if(savedInstanceState!=null){
              seconds = savedInstanceState.getInt("seconds");
              running = savedInstanceState.getBoolean("running");
              wasRunning = savedInstanceState.getBoolean("wasRunning");
          }
          runTimer();
      }
      
      @Override
      public void onSaveInstanceState(Bundle savedInstanceState){
          super.onSaveInstanceState(savedInstanceState);
          savedInstanceState.putInt("seconds",seconds);
          savedInstanceState.putBoolean("running",running);
          savedInstanceState.putBoolean("wasRunning",wasRunning);
      }
      
  • 运行流程

    • 用户启动App,点击Start按钮,runTimer()开始递增seconds并更新文本框
    • 用户点击Home键,Activity消失,Android调用onStop()
    • 用户返回秒表App,Activity可见,Android调用onStart()

5、MainActivity完整代码

public class MainActivity extends AppCompatActivity {

    //计时的秒数
    private  int seconds = 0;
    //计时的状态
    private  boolean running = false;
    //新的变量,用于在onStop()中保存消失前running的状态
    private boolean wasRunning = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("life cycle","onCreate");
        setContentView(R.layout.activity_main);
        if(savedInstanceState!=null){
            seconds = savedInstanceState.getInt("seconds");
            running = savedInstanceState.getBoolean("running");
            wasRunning = savedInstanceState.getBoolean("wasRunning");
        }
        //在Activity启动时,onCreate()方法中启动runTimer()
        runTimer();
    }

    @Override
    protected void onStart(){
        super.onStart();
        Log.d("life cycle","onStop");
        if(wasRunning){
            running = true;
        }
    }

    @Override
    protected void onStop(){
        super.onStop();
        Log.d("life cycle","onStop");
        wasRunning = running;
        running = false;
    }


    @Override
    public void onSaveInstanceState(Bundle savedInstanceState){
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putInt("seconds",seconds);
        savedInstanceState.putBoolean("running",running);
        savedInstanceState.putBoolean("wasRunning",wasRunning);
    }

    protected void onDestroy(){
        super.onDestroy();
        Log.d("life cycle","onDestroy");
    }

    //启动计时
    public void onClickStart(View view){
        running = true;
    }
    //停止计时
    public void onClickStop(View view){
        running = false;
    }
    //重置秒表
    public void onClickReset(View view){
        running = false;
        seconds = 0;
        wasTiming = false;
    }
    //循环计时方法
    private void runTimer(){
        final TextView timeView = findViewById(R.id.time_view);
        //创建UI线程的handler,用于消息处理
        final Handler handler = new Handler();
        handler.post(new Runnable() {//立即交一个Runnable,任务在Runnable的run()方法中
            @Override
            public void run() {
                int hours = seconds/3600;
                int minutes = (seconds%3600)/60;
                int secs = seconds%60;
                String time = String.format("%d:%02d:%02d", hours, minutes, secs);
                timeView.setText(time);
                if(running){
                    seconds++;
                }
                //每隔1000ms,重复提交该任务
                handler.postDelayed(this,1000);
            }
        });
    }
}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-11-12 19:42:39  更:2021-11-12 19:43:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:27:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码