• 【用户交互】APP没有退出前台但改变系统属性如何实时更新UI?监听系统广播,让用户交互更舒心~


    前日,一小伙伴问我一个问题,说它解决了半天都没解决这个问题,截图如下:

    大概楼主理解如下:

    如果在应用中有一个判断wifi的开关和一个当前音量大小的seekbar以及一个获取当前电量多少的按钮,想知道如果按home键后调整了wifi开关信息以及媒体音量信息,再切换到前台UI如何才会实时刷新。其实这个问题不难解决,如果你了解activity的生命周期,只需要把设置开关和seekbar的信息放在onResume中就好了,因为无论是锁屏后打开或者是切换后台再前台都是会调用onResume的。但不由得滋生一个问题,大家都知道APP在前台的情况下用户依然是可以下拉状态栏设置Wifi开关信息的,对于音量信息也是可以侧边增减,那APP一直在前台,生命周期明显是无法实时更新了,那我们应该如何解决呢?没错,没当改变系统属性的时候,都会发出系统广播,我们只需要去写一个接收器,并根据它做响应的操作就好了。

    分析至此,楼主就把给这位小伙伴写的一些代码分享给大家,也可以帮助不太熟悉的小伙伴更加了解android的广播以及回调机制。对于还不太明白java的回调是什么意思的小伙伴,也可以看看。

    1)由于要使用到系统属性,所以先申明权限。

    1 <!--wifi管理必备权限-->
    2     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    3     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    4 
    5     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    6 
    7     <!--操作音频需要权限-->
    8     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

    2)然后写一个广播接收器,做好过滤,并申明一个回调接口,用于当广播接收到的时候提醒主线程更新UI。

     1 package com.example.nanchen.maweinaitest;
     2 
     3 import android.content.BroadcastReceiver;
     4 import android.content.Context;
     5 import android.content.Intent;
     6 import android.media.AudioManager;
     7 import android.net.wifi.WifiManager;
     8 import android.util.Log;
     9 
    10 import static android.content.Intent.ACTION_BATTERY_CHANGED;
    11 
    12 /**
    13  * @author nanchen
    14  * @fileName MaWeiNaiTest
    15  * @packageName com.example.nanchen.maweinaitest
    16  * @date 2016/11/05  21:35
    17  */
    18 
    19 public class MyStatusReceiver extends BroadcastReceiver {
    20 
    21     private static final String TAG = "MyStatusReceiver";
    22     private StatusCallback mStatusCallback = MainActivity.callback;
    23 
    24     public MyStatusReceiver(){
    25     }
    26 
    27     @Override
    28     public void onReceive(Context context, Intent intent) {
    29 
    30         String action = intent.getAction();
    31         Log.e(TAG,action);
    32         Log.e(TAG,intent.getAction()+" ====   ");
    33 
    34 
    35         // 首先判断它是否是电量变化的Broadcast Action
    36         if (ACTION_BATTERY_CHANGED.equals(action)) {//如果监听到电量改变广播
    37             // 获取当前电量
    38             int level = intent.getIntExtra("level", 0);
    39             // 电量的总刻度
    40             int scale = intent.getIntExtra("scale", 100);
    41             // 把它转换为百分比
    42 //            mActivity.mTextView.setText(level * 100 / scale + "%");
    43             String str = level * 100 / scale + "%";
    44 
    45             Log.e(TAG,level+"");
    46             Log.e(TAG,scale+"");
    47             Log.e(TAG,str+"");
    48 
    49             mStatusCallback.onPowerChanged(level * 100 / scale + "%");
    50         }
    51         // 监听一下音量
    52         if ("android.media.VOLUME_CHANGED_ACTION".equals(action)){
    53 //            mActivity.mSeekBar.setProgress(mActivity.mAudioManager.getStreamVolume(AudioManager.STREAM_SYSTEM));
    54             AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    55             int progress = audioManager.getStreamVolume(AudioManager.STREAM_SYSTEM);
    56             Log.e(TAG,progress+"");
    57             mStatusCallback.onAudioChanged(audioManager.getStreamVolume(AudioManager.STREAM_SYSTEM));
    58         }
    59         if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)){
    60             WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    61             mStatusCallback.onWifiChanged(wifiManager.isWifiEnabled());
    62         }
    63     }
    64 
    65     /**
    66      * 一个回调接口
    67      */
    68     public interface StatusCallback {
    69         /**
    70          * 当电量改变时应该调用的回调接口
    71          * @param status 当前电量百分比
    72          */
    73         void onPowerChanged(String status);
    74 
    75         /**
    76          * 当音频音量改变时会调用的回调接口
    77          * @param status 当前音量数值
    78          */
    79         void onAudioChanged(int status);
    80 
    81         /**
    82          * 当wifi改变时会调用的回调接口
    83          * @param status  wifi的开关  true-开   false - 关
    84          */
    85         void onWifiChanged(boolean status);
    86     }
    87 }

    3)别忘了在mainfest申明

    1 <receiver android:name=".MyStatusReceiver">
    2             <intent-filter>
    3                 <action android:name="android.intent.action.BATTERY_CHANGED"/>
    4                 <action android:name="android.media.VOLUME_CHANGED_ACTION"/>
    5                 <action android:name="android.net.wifi.WIFI_STATE_CHANGED_ACTION"/>
    6             </intent-filter>
    7         </receiver>

    4)布局就采用的这位小伙伴的布局

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2               xmlns:tools="http://schemas.android.com/tools"
     3               android:layout_width="match_parent"
     4               android:layout_height="match_parent"
     5               android:orientation="vertical">
     6 
     7 
     8 
     9     <Switch
    10         android:id="@+id/wifi"
    11         android:layout_width="wrap_content"
    12         android:layout_height="wrap_content"
    13         android:textOn="开"
    14         android:textOff="关"
    15         android:text="WiFi"/>
    16 
    17     <SeekBar
    18         android:id="@+id/seekBar"
    19         android:layout_width="match_parent"
    20         android:layout_height="wrap_content"
    21         android:layout_marginTop="16dp"/>
    22 
    23     <Button
    24         android:id="@+id/btn"
    25         android:layout_width="match_parent"
    26         android:layout_height="wrap_content"
    27         android:layout_marginTop="16dp"
    28         android:text="当前电量百分比" />
    29 
    30 
    31     <LinearLayout
    32         android:orientation="horizontal"
    33         android:layout_width="match_parent"
    34         android:layout_height="wrap_content">
    35 
    36         <TextView
    37             android:layout_width="wrap_content"
    38             android:layout_height="wrap_content"
    39             android:text="当前电量百分比为:"/>
    40 
    41         <TextView
    42             android:layout_width="wrap_content"
    43             android:layout_height="wrap_content"
    44             android:text="0%"
    45             android:id="@+id/text"/>
    46     </LinearLayout>
    47 
    48 
    49 </LinearLayout>

    5)最后是MainActivity,注意广播注销,否则造成内存泄漏!

      1 package com.example.nanchen.maweinaitest;
      2 
      3 import android.content.Context;
      4 import android.content.IntentFilter;
      5 import android.media.AudioManager;
      6 import android.net.wifi.WifiManager;
      7 import android.os.Bundle;
      8 import android.view.View;
      9 import android.view.View.OnClickListener;
     10 import android.widget.CompoundButton;
     11 import android.widget.CompoundButton.OnCheckedChangeListener;
     12 import android.widget.SeekBar;
     13 import android.widget.SeekBar.OnSeekBarChangeListener;
     14 import android.widget.Switch;
     15 import android.widget.TextView;
     16 import android.widget.Toast;
     17 
     18 import com.example.nanchen.maweinaitest.MyStatusReceiver.StatusCallback;
     19 
     20 import static android.content.Intent.ACTION_BATTERY_CHANGED;
     21 
     22 
     23 public class MainActivity extends ActivityBase implements StatusCallback {
     24 
     25     public static StatusCallback callback;
     26 
     27     private static final String TAG = "MainActivity";
     28     private Switch mSwitchWifi;
     29     private SeekBar mSeekBar;
     30     private WifiManager mWifiManager;
     31     private AudioManager mAudioManager;
     32     private TextView mTextView;
     33     private MyStatusReceiver mMyStatusReceiver;
     34 
     35     @Override
     36     protected void onCreate(Bundle savedInstanceState) {
     37         super.onCreate(savedInstanceState);
     38         setContentView(R.layout.activity_main);
     39         callback = this;
     40 
     41         bindView();
     42 
     43         initManager();
     44 
     45         bindListener();
     46 
     47     }
     48 
     49     private void initManager() {
     50         // 获取Wifi管理器
     51         mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
     52         // 把动态获取的信息放在onResume设置  避免按home键后再把APP切换到前台获取不到正常的数据
     53 
     54 
     55         // 获取音频管理器
     56         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
     57     }
     58 
     59     /**
     60      * 绑定监听
     61      */
     62     private void bindListener() {
     63         // 为wifi开关事件设置监听
     64         mSwitchWifi.setOnCheckedChangeListener(new OnCheckedChangeListener() {
     65             @Override
     66             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
     67                 if (!isChecked) {
     68                     buttonView.setChecked(false);
     69                     mWifiManager.setWifiEnabled(false);
     70                     Toast.makeText(MainActivity.this, "wifi关闭成功!", Toast.LENGTH_SHORT).show();
     71                 } else {
     72                     buttonView.setChecked(true);
     73                     mWifiManager.setWifiEnabled(true);
     74                     Toast.makeText(MainActivity.this, "wifi开启成功!", Toast.LENGTH_SHORT).show();
     75                 }
     76             }
     77         });
     78 
     79         // 再动态监听SeekBar
     80         mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
     81             @Override
     82             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
     83                 // 停止滑动
     84                 mSeekBar.setProgress(progress);
     85                 // 三个参数一次是  模式,值,标志位
     86                 mAudioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, progress, 0);
     87             }
     88 
     89             @Override
     90             public void onStartTrackingTouch(SeekBar seekBar) {
     91 
     92             }
     93 
     94             @Override
     95             public void onStopTrackingTouch(SeekBar seekBar) {
     96 
     97             }
     98         });
     99 
    100         // 注册广播,添加三个Action
    101         IntentFilter intentFilter = new IntentFilter();
    102         intentFilter.addAction(ACTION_BATTERY_CHANGED);
    103         intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
    104         intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    105         mMyStatusReceiver = new MyStatusReceiver();
    106         registerReceiver(mMyStatusReceiver, intentFilter); // 注册监听广播
    107     }
    108 
    109 
    110     private int max;
    111     private int current;
    112 
    113     /**
    114      * 设置wifi开关
    115      */
    116     private void setWifiSwitch() {
    117         if (mWifiManager.isWifiEnabled()) {
    118             mSwitchWifi.setChecked(true);
    119         } else {
    120             mSwitchWifi.setChecked(false);
    121         }
    122     }
    123 
    124     @Override
    125     protected void onResume() {
    126         super.onResume();
    127         // 先动态设置wifi
    128         setWifiSwitch();
    129 
    130         // 再动态设置音频音量  参数为音量模式
    131         max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_SYSTEM); // 最大音量
    132         current = mAudioManager.getStreamVolume(AudioManager.STREAM_SYSTEM); // 当前音量
    133 
    134         mSeekBar.setMax(max);// 设置seekBar
    135         mSeekBar.setProgress(current);
    136     }
    137 
    138     @Override
    139     protected void onPause() {
    140         super.onPause();
    141         // 一定记得注销广播,否则会造成内存泄漏
    142         unregisterReceiver(mMyStatusReceiver);
    143     }
    144 
    145     @SuppressWarnings("ConstantConditions")
    146     private void bindView() {
    147         mSwitchWifi = (Switch) findViewById(R.id.wifi);
    148         mSeekBar = (SeekBar) findViewById(R.id.seekBar);
    149         mTextView = (TextView) findViewById(R.id.text);
    150         findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
    151             @Override
    152             public void onClick(View v) {
    153                 // 在这里获取当前电量信息
    154 
    155                 // 这里就不写了,实际上监听系统广播,它会自动实时获取电量信息
    156             }
    157         });
    158     }
    159 
    160 
    161     @Override
    162     public void onPowerChanged(String status) {
    163         mTextView.setText(status);
    164     }
    165 
    166     @Override
    167     public void onAudioChanged(final int status) {
    168         mSeekBar.setProgress(status);
    169     }
    170 
    171     @Override
    172     public void onWifiChanged(boolean status) {
    173         mSwitchWifi.setChecked(status);
    174     }
    175 
    176 }

    大概运行图如下:

    代码已上传至github:https://github.com/nanchen2251/ReceiverDemo

  • 相关阅读:
    spring boot打包出现yaml配置文件问题
    spring boot定时器使用异常
    常见mysql死锁案例行死锁与表死锁
    数据库三范式
    【leetcode】26. 删除排序数组中的重复项
    【数据结构与算法】10.2 二叉排序树
    【设计模式】5、适配器设计模式之对象适配器
    【数据结构与算法】10.1、赫夫曼树代码实现
    【设计模式】4、建造者模型以及Stringbuilder源码分析
    【设计模式】2、工厂模式之简单工厂、方法工厂、抽象工厂
  • 原文地址:https://www.cnblogs.com/liushilin/p/6037466.html
Copyright © 2020-2023  润新知