欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

实战Android踩坑记录(四)

程序员文章站 2022-03-16 17:05:10
...

Android广播

动态注册监听网络变化不可以

本人使用的参考书是郭霖大佬的《第一行代码-Android(第2版)》,因为时间比较久远了,在我开始学习的时候都1902年了,书上的很多东西和现在都不兼容了,在Android的广播这块就是一个例子。
原书的Android Studio的版本是2.2,而现在都更新到3.6版本了,原书的SDK为API24(Android 7.0)现在最新的是API29(Android 10.0)。
我现在学到的广播来说,在动态广播方面,书上使用的例子是动态注册监听网络变化。源代码如下
Mainactivity:

package com.example.broadcasttest;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.con.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver, intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }

    class NetworkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
        }
    }
}

其中问题就在这个android.net.con.CONNECTIVITY_CHANGEaction上,在AndroidManifest.xml文件中添加完权限之后也还是无法收到这个广播,在我花了很长时间搜集各路资料之后,还是找不到好的解决方法。唯一可行的就是更换SDK版本,但是说的容易,更换了SDK版本之后,包括编译器什么的,都需要手动更换,有一个没换好就GG。我之前就这么搞过,弄得我心态爆炸才弄好。上次是因为要参加一个APP设计大赛,为了和一起的同学保持一致,以及使用一些现成的UI模板,更换了SDK版本,弄了好久才换好,我不想再重复上次的悲剧了。
既然我的代码没问题,反正就是写个能发送广播的程序嘛,我为何不能换一个action的广播呢,在我花了一定的时间搜集资料之后选择了动态注册监听电池电量变化

动态注册监听电池电量变化

我们分析一下上面的代码首先注册写一个内部类注册自广播类(NetworkChangeReceiver extends BroadcastReceiver)然后定义一个InterFilter的拦截器(intendFilter)和注册的内部类(networkChangeReceiver),然后把需要的action(android.net.con.CONNECTIVITY_CHANGE)加到这个拦截器中,接着注册这个广播。
在这个广播的内部类里,需要重写一下onReceive这个方法(接受广播之后的动作),为了显示出写了一个Toast
对照来看,我们可以得出如下的代码

package com.example.broadcasttest;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private batteryLevelReceiver batteryLevelReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        batteryLevelReceiver = new batteryLevelReceiver();
        registerReceiver(batteryLevelReceiver, intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(batteryLevelReceiver);
    }

    class batteryLevelReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "battery changes", Toast.LENGTH_SHORT).show();
        }
    }
}

另外需要在AndroidManifest.xml中声明权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="com.example.broadcasttest">
    <uses-permission
            android:name="android.permission.BATTERY_STATS"
            tools:ignore="ProtectedPermissions" />//声明的权限
    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
 tools:ignore="ProtectedPermissions" 

这一行代码的作用是啥,我也不知道,在我写完

 <uses-permission android:name="android.permission.BATTERY_STATS"/>

之后自动提示我增加那一行,我也不知道是啥,反正加上没问题。
运行结果如图
实战Android踩坑记录(四)
附加说一句,让Android studio的模拟器的电量变化,只需要点击如图的箭头实战Android踩坑记录(四)
进入如图的界面,在这个界面中,我们可以对模拟器的状态进行自定义,这个功能在以后的用处感觉会很多,还好我自己琢磨了出来。
实战Android踩坑记录(四)

广播显示电量

广播搞定之后,我们想一个问题,我不仅想能显示出电量变化,我还想知道现在的电量具体是多少。
我们做一个页面,这个页面显示当前的电量。
还是捋一下整体的思路,根据之前学到的知识,我们在布局(layout)中新建一个文本框(TextView),给这个文本框一个ID,然后在Mainactivity中新建一个TextView类的文件,接着根据ID把布局和代码联系起来,接着根据电量的动态变化,显示在页面上。
layout文件代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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">

    <TextView
            android:id="@+id/batteryLevel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

</LinearLayout>

Mainactivity文件代码

package com.example.broadcasttest2;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Bundle;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private TextView batteryLevelText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        batteryLevelReceiver batteryLevelReceiver = new batteryLevelReceiver();
        this.registerReceiver(batteryLevelReceiver, intentFilter);
        batteryLevelText = this.findViewById(R.id.batteryLevel);
    }

    private class batteryLevelReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            int batteryLevelNum = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
            if (batteryLevelText != null) {
                batteryLevelText.setText("当前电量为:"+String.valueOf(batteryLevelNum));
            }
        }
    }
}
batteryLevelText = this.findViewById(R.id.batteryLevel);
//这一行代码的作用就是把代码和布局联系起来
int batteryLevelNum = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
/*这一行代码就是通过BatteryManager这个对象的就是用来管理电池的各种属性的
,这个方法获得的是电量百分比的数值
*/

需要特别说明的是最后一步必须转化成String类型,如果不转化,虽然不报错,但最终程序无法在模拟器中运行。结果如图。
实战Android踩坑记录(四)

总结

在我学习的过程中,遇到了很多版本不兼容的问题,也是花了很长时间学习。我觉得之所以需要这么长时间,主要我还是看不懂源码,如果我能看懂源码,很多问题我自己就能解决(比如说我通过看源码,可以得出各种版本的区别,以及各种属性和方法)之所以不看源码,也不能完全说英文看不懂,主要一些专业名词看不懂,为了弄清楚这些专业名词花的时间可能更多。但如果等我继续学习,相信总有一天能看懂源码,之后的各种问题,我都可以通过看源码解决,而不是看别人的技术博客。毕竟以后Android技术还会迭代,很多bug可能之前没人遇到过,这时候只有靠自己解决才可以。

相关标签: Android