【用户交互】APP没有退出前台但改变系统属性如何实时更新UI?监听系统广播,让用户交互更舒心~
前日,一小伙伴问我一个问题,说它解决了半天都没解决这个问题,截图如下:
大概楼主理解如下:
如果在应用中有一个判断wifi的开关和一个当前音量大小的seekbar以及一个获取当前电量多少的按钮,想知道如果按home键后调整了wifi开关信息以及媒体音量信息,再切换到前台UI如何才会实时刷新。其实这个问题不难解决,如果你了解activity的生命周期,只需要把设置开关和seekbar的信息放在onResume中就好了,因为无论是锁屏后打开或者是切换后台再前台都是会调用onResume的。但不由得滋生一个问题,大家都知道APP在前台的情况下用户依然是可以下拉状态栏设置Wifi开关信息的,对于音量信息也是可以侧边增减,那APP一直在前台,生命周期明显是无法实时更新了,那我们应该如何解决呢?没错,没当改变系统属性的时候,都会发出系统广播,我们只需要去写一个接收器,并根据它做响应的操作就好了。
分析至此,楼主就把给这位小伙伴写的一些代码分享给大家,也可以帮助不太熟悉的小伙伴更加了解android的广播以及回调机制。对于还不太明白java的回调是什么意思的小伙伴,也可以看看。
1)由于要使用到系统属性,所以先申明权限。
<!--wifi管理必备权限-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <!--操作音频需要权限-->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
2)然后写一个广播接收器,做好过滤,并申明一个回调接口,用于当广播接收到的时候提醒主线程更新UI。
package com.example.nanchen.maweinaitest; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.net.wifi.WifiManager;
import android.util.Log; import static android.content.Intent.ACTION_BATTERY_CHANGED; /**
* @author nanchen
* @fileName MaWeiNaiTest
* @packageName com.example.nanchen.maweinaitest
* @date 2016/11/05 21:35
*/ public class MyStatusReceiver extends BroadcastReceiver { private static final String TAG = "MyStatusReceiver";
private StatusCallback mStatusCallback = MainActivity.callback; public MyStatusReceiver(){
} @Override
public void onReceive(Context context, Intent intent) { String action = intent.getAction();
Log.e(TAG,action);
Log.e(TAG,intent.getAction()+" ==== "); // 首先判断它是否是电量变化的Broadcast Action
if (ACTION_BATTERY_CHANGED.equals(action)) {//如果监听到电量改变广播
// 获取当前电量
int level = intent.getIntExtra("level", 0);
// 电量的总刻度
int scale = intent.getIntExtra("scale", 100);
// 把它转换为百分比
// mActivity.mTextView.setText(level * 100 / scale + "%");
String str = level * 100 / scale + "%"; Log.e(TAG,level+"");
Log.e(TAG,scale+"");
Log.e(TAG,str+""); mStatusCallback.onPowerChanged(level * 100 / scale + "%");
}
// 监听一下音量
if ("android.media.VOLUME_CHANGED_ACTION".equals(action)){
// mActivity.mSeekBar.setProgress(mActivity.mAudioManager.getStreamVolume(AudioManager.STREAM_SYSTEM));
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int progress = audioManager.getStreamVolume(AudioManager.STREAM_SYSTEM);
Log.e(TAG,progress+"");
mStatusCallback.onAudioChanged(audioManager.getStreamVolume(AudioManager.STREAM_SYSTEM));
}
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)){
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mStatusCallback.onWifiChanged(wifiManager.isWifiEnabled());
}
} /**
* 一个回调接口
*/
public interface StatusCallback {
/**
* 当电量改变时应该调用的回调接口
* @param status 当前电量百分比
*/
void onPowerChanged(String status); /**
* 当音频音量改变时会调用的回调接口
* @param status 当前音量数值
*/
void onAudioChanged(int status); /**
* 当wifi改变时会调用的回调接口
* @param status wifi的开关 true-开 false - 关
*/
void onWifiChanged(boolean status);
}
}
3)别忘了在mainfest申明
<receiver android:name=".MyStatusReceiver">
<intent-filter>
<action android:name="android.intent.action.BATTERY_CHANGED"/>
<action android:name="android.media.VOLUME_CHANGED_ACTION"/>
<action android:name="android.net.wifi.WIFI_STATE_CHANGED_ACTION"/>
</intent-filter>
</receiver>
4)布局就采用的这位小伙伴的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <Switch
android:id="@+id/wifi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOn="开"
android:textOff="关"
android:text="WiFi"/> <SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"/> <Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="当前电量百分比" /> <LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="当前电量百分比为:"/> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0%"
android:id="@+id/text"/>
</LinearLayout> </LinearLayout>
5)最后是MainActivity,注意广播注销,否则造成内存泄漏!
package com.example.nanchen.maweinaitest; import android.content.Context;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast; import com.example.nanchen.maweinaitest.MyStatusReceiver.StatusCallback; import static android.content.Intent.ACTION_BATTERY_CHANGED; public class MainActivity extends ActivityBase implements StatusCallback { public static StatusCallback callback; private static final String TAG = "MainActivity";
private Switch mSwitchWifi;
private SeekBar mSeekBar;
private WifiManager mWifiManager;
private AudioManager mAudioManager;
private TextView mTextView;
private MyStatusReceiver mMyStatusReceiver; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
callback = this; bindView(); initManager(); bindListener(); } private void initManager() {
// 获取Wifi管理器
mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
// 把动态获取的信息放在onResume设置 避免按home键后再把APP切换到前台获取不到正常的数据 // 获取音频管理器
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
} /**
* 绑定监听
*/
private void bindListener() {
// 为wifi开关事件设置监听
mSwitchWifi.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isChecked) {
buttonView.setChecked(false);
mWifiManager.setWifiEnabled(false);
Toast.makeText(MainActivity.this, "wifi关闭成功!", Toast.LENGTH_SHORT).show();
} else {
buttonView.setChecked(true);
mWifiManager.setWifiEnabled(true);
Toast.makeText(MainActivity.this, "wifi开启成功!", Toast.LENGTH_SHORT).show();
}
}
}); // 再动态监听SeekBar
mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// 停止滑动
mSeekBar.setProgress(progress);
// 三个参数一次是 模式,值,标志位
mAudioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, progress, 0);
} @Override
public void onStartTrackingTouch(SeekBar seekBar) { } @Override
public void onStopTrackingTouch(SeekBar seekBar) { }
}); // 注册广播,添加三个Action
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_BATTERY_CHANGED);
intentFilter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
mMyStatusReceiver = new MyStatusReceiver();
registerReceiver(mMyStatusReceiver, intentFilter); // 注册监听广播
} private int max;
private int current; /**
* 设置wifi开关
*/
private void setWifiSwitch() {
if (mWifiManager.isWifiEnabled()) {
mSwitchWifi.setChecked(true);
} else {
mSwitchWifi.setChecked(false);
}
} @Override
protected void onResume() {
super.onResume();
// 先动态设置wifi
setWifiSwitch(); // 再动态设置音频音量 参数为音量模式
max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_SYSTEM); // 最大音量
current = mAudioManager.getStreamVolume(AudioManager.STREAM_SYSTEM); // 当前音量 mSeekBar.setMax(max);// 设置seekBar
mSeekBar.setProgress(current);
} @Override
protected void onPause() {
super.onPause();
// 一定记得注销广播,否则会造成内存泄漏
unregisterReceiver(mMyStatusReceiver);
} @SuppressWarnings("ConstantConditions")
private void bindView() {
mSwitchWifi = (Switch) findViewById(R.id.wifi);
mSeekBar = (SeekBar) findViewById(R.id.seekBar);
mTextView = (TextView) findViewById(R.id.text);
findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 在这里获取当前电量信息 // 这里就不写了,实际上监听系统广播,它会自动实时获取电量信息
}
});
} @Override
public void onPowerChanged(String status) {
mTextView.setText(status);
} @Override
public void onAudioChanged(final int status) {
mSeekBar.setProgress(status);
} @Override
public void onWifiChanged(boolean status) {
mSwitchWifi.setChecked(status);
} }
大概运行图如下:
代码已上传至github:https://github.com/nanchen2251/ReceiverDemo
【用户交互】APP没有退出前台但改变系统属性如何实时更新UI?监听系统广播,让用户交互更舒心~的更多相关文章
- 后台自动运行,定期记录定位数据(Hbuilder监听 app由前台切换到后台、切换运行环境的 监听方法)
http://ask.dcloud.net.cn/question/28090 https://blog.csdn.net/qq_37508970/article/details/86649703 各 ...
- 监听指定端口数据交互(HttpListenerContext )
很怀念以前做机票的日子,,,,可惜回不去 以前的项目中的,拿来贴贴 场景:同步第三方数据,监听指定地址(指定时间间隔,否则不满足,因为需要处理粘包问题,改篇未实现) 主要内容四个文件:下面分别说下每个 ...
- datePicker 及 timePicker 监听事件 获取用户选择 年月日分秒信息
public class MainActivity extends AppCompatActivity { private TimePicker timePicker; private DatePic ...
- 重学 Java 设计模式:实战观察者模式「模拟类似小客车指标摇号过程,监听消息通知用户中签场景」
作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 知道的越多不知道的就越多 编程开发这条路上的知识是无穷无尽的, ...
- Linux(Centos7)安装Oracle11.2.0数据字典初始化,监听,网络,创建用户等部分配置
#创建数据字典和pl/sql包 @/u01/app/oracle/product/11.2.0/db_1/rdbms/admin/catalog.sql; @/u01/app/oracle/produ ...
- vue学习-day05 -- 案例:名字合并(监听data数据的改变)
1.案例:名字合并(监听data数据的改变) 使用keyup事件监听data数据的改变 <!DOCTYPE html> <html> <head> <titl ...
- iOS 监听控件某个属性的改变observeValueForKeyPath
创建一个测试的UIButton #import "ViewController.h" @interface ViewController () @property(nonatomi ...
- ionic app 监听网络功能
安装cordova插件: cordova plugin add cordova-plugin-network-information 在app.js 的run()里面的function()注入$cor ...
- Android 监听APP进入后台或切换到前台方案对比
在我们开发的过程中,经常会遇到需要我们判断app进入后台,或者切换到前台的情况.比如我们想判断app切换到前台时,显示一个解锁界面,要求用户输入解锁密码才能继续进行操作:我们想判断app切换到后台,记 ...
随机推荐
- js学习笔记:操作iframe
iframe可以说是比较老得话题了,而且网上也基本上在说少用iframe,其原因大致为:堵塞页面加载.安全问题.兼容性问题.搜索引擎抓取不到等等,不过相对于这些缺点,iframe的优点更牛,跨域请求. ...
- 使用JSONObject.fromObject的时候出现“There is a cycle in the hierarchy”异常 的解决办法
在使用JSONObject.fromObject的时候,出现“There is a cycle in the hierarchy”异常. 意思是出现了死循环,也就是Model之间有循环包含关系: ...
- C#学习资源
# 视频 C#程序设计 Cousera(推荐) # 文档 C#教程 MSDN Microsoft API 和参考目录
- 猖獗的假新闻:2017年1月1日起iOS的APP必须使用HTTPS
一.假新闻如此猖獗 刚才一位老同事 打电话问:我们公司还是用的HTTP,马上就到2017年了,提交AppStore会被拒绝,怎么办? 公司里已经有很多人问过这个问题,回答一下: HTTP还是可以正常提 ...
- jQuery学习之路(1)-选择器
▓▓▓▓▓▓ 大致介绍 终于开始了我的jQuery学习之路!感觉不能再拖了,要边学习原生JavaScript边学习jQuery jQuery是什么? jQuery是一个快速.简洁的JavaScript ...
- jq选择器基础
Jquery $代表选择器 使用jq必须要导入jq文件 <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js&qu ...
- 在centos7(EL7.3 即 kernel-3.10.0-514.X )上安装BCM4312无线网卡驱动要注意的问题
我新装的centos7主机无法使用里面自带的网卡,查询后发现网卡型号为BCM4312.我在看资料安装的过程中遇到了些问题,纠结了好久,现在分享下要注意的点,为后来的遇到同样问题的人提供点帮助.现在开始 ...
- Ubuntu手动设置DSL连接
在安装完Ubuntu之后,发现图形界面的DSL连接不管用了,郁闷了好几天,想想移动每个月120个小时的流量岂不是白白浪费了.正当我想重返Windows系统的时候,却发现了手动设置连接DSL的好方法,感 ...
- Linux 安装Mono环境 运行ASP.NET(一)
1.先看一下Linux环境下面请求的过程,(画的不是很好,简单的了解一下原理.) .NET跨平台其实需要这三个关键:编译器.CLR和基础类库.在.NET下我们编写一个最简单的"Hello W ...
- Membership三步曲之进阶篇 - 深入剖析Provider Model
Membership 三步曲之进阶篇 - 深入剖析Provider Model 本文的目标是让每一个人都知道Provider Model 是什么,并且能灵活的在自己的项目中使用它. Membershi ...