草庐IT

java - 如何?监听位置设置是否已打开(Android 应用程序)

coder 2023-11-28 原文

因此,在过去的几周里,我一直在开发我的 Android 应用程序,并寻找实现我需要做的事情的最佳方式,但仍然不能完全正确。非常感谢任何/所有帮助,因为我还在掌握一些东西..

任务:

(假设“位置”/GPS 设置当前关闭),我需要让我的应用程序不断监听“位置”设置是否打开。此时,只需启动一个 Activity 即可。

想法:

这些是我认为它可能起作用的所有不同方式:

  • 使用“onProviderEnabled”的 LocationListener

  • GpsStatusListener 使用“onGpsStatusChanged”和“GPS_EVENT_STARTED”

  • GpsProvider 需要卫星(以确定它是否启动),或以某种方式使用 GpsProvider 的“AVAILABLE”常量/int

  • SettingInjectorService 使用“ACTION_SERVICE_INTENT”(和/或)“ACTION_INJECTED_SETTING_CHANGED”和“onGetEnabled”或“isEnabled”

  • 设置。使用“LOCATION_MODE”安全!=“LOCATION_MODE_OFF”

  • ContentObserver/ContentResolver

  • Intent getAction (...)

  • 某种“if/else”

问题:

非常感谢对以下任何问题的任何建议或答案..

  • 以上哪项想法是完成任务的最佳方式?越简单越好,但最重要的是它需要时刻监听,并在位置设置打开时立即响应。

  • 对于上述想法中哪一个最有效,我将如何实现它? (例如,我需要一个 BroadcastListener 还是一个 Service?它们如何组合在一起?

我非常感谢您能为我提供的任何建议或帮助。我仍然掌握所有这一切,但有足够的信心去做,并渴望发布我的第一个应用程序。谢谢,它意义重大,对我有很大帮助。


编辑:

好的,这就是我到目前为止所得到的...
这是我的接收器:

我的接收器.Java

public class MyReceiver extends BroadcastReceiver {

    private final static String TAG = "LocationProviderChanged";

    boolean isGpsEnabled;
    boolean isNetworkEnabled;



    public MyReceiver() {
    // EMPTY

    // MyReceiver Close Bracket
    }



    // START OF onReceive
    @Override
    public void onReceive(Context context, Intent intent) {


        // PRIMARY RECEIVER
        if (intent.getAction().matches("android.location.PROVIDERS_CHANGED")) {

            Log.i(TAG, "Location Providers Changed");

            LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
            isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            Toast.makeText(context, "GPS Enabled: " + isGpsEnabled + " Network Location Enabled: " + isNetworkEnabled, Toast.LENGTH_LONG).show();

            // START DIALOG ACTIVITY
            if (isGpsEnabled || isNetworkEnabled) {
                Intent runDialogActivity = new Intent(context, DialogActivity.class);
                context.startActivity(runDialogActivity);

            }

        }



        // BOOT COMPLETED (REPLICA OF PRIMARY RECEIVER CODE FOR WHEN BOOT_COMPLETED)
        if (intent.getAction().matches("android.intent.action.BOOT_COMPLETED")) {

            Log.i(TAG, "Location Providers Changed Boot");

            LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
            isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            Toast.makeText(context, "GPS Enabled Boot: " + isGpsEnabled + " Network Location Enabled Boot: " + isNetworkEnabled, Toast.LENGTH_LONG).show();

            // START DIALOG ACTIVITY
            if (isGpsEnabled || isNetworkEnabled) {
                Intent runDialogActivity = new Intent(context, DialogActivity.class);
                context.startActivity(runDialogActivity);

            }

        }



    // onReceive CLOSE BRACKET
    }



// CLOSE OF FULL CLASS
}

list 如下所示:

list .XML

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.ender.projects.receivertest">

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

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

    <application
        android:allowBackup="true"
        android:fullBackupContent="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        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>

        <activity android:name=".DialogActivity">
        </activity>

        <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.location.PROVIDERS_CHANGED" />

                <action android:name="android.intent.action.BOOT_COMPLETED" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

    </application>

</manifest>

除了这些文件,我还有以下文件:
MainActivity.JavaDialogActivity.Java,均带有布局文件,
activity_main.xmlactivity_dialog.xml 来匹配它们。

所以如果我理解正确的话,当用户下载应用程序并打开它时,我的 MainActivity.Java 和相应的布局将启动。但我只会将其用作首选项屏幕。所以一旦他们第一次打开应用程序,广播接收器应该会自动开始监听要打开的位置设置,对吗?我还希望 Broadcast Listener 保持收听状态,即使在它接收到初始广播之后(这样我的 onReceive 仍然会在他们关闭 LOCATION 设置时触发,然后他们再次打开它..< br/="">
那么 (A) 目前我的代码看起来如何?
(B) 要完成我刚才描述的内容,需要添加什么?
和 (C) 当我打开 LOCATION 设置时运行它会抛出这个错误。
..我该如何修复它?:
java.lang.RuntimeException:无法启动接收器 com.bryce.projects.servicesthreadsetc.MyReceiver:android.util.AndroidRuntimeException:从 Activity 上下文外部调用 startActivity() 需要 FLAG_ACTIVITY_NEW_TASK 标志。这真的是你想要的吗?


再次感谢所有的帮助!

最佳答案

由于您不需要实际获取 Location,因此满足您需求的最佳实现是 BroadcastReceiver。

这是最佳选择,因为您不需要一直运行服务(导致额外的电池耗尽),并且您可以从 BroadcastReceiver 启动 Activity 。

使用 Intent 过滤器和 BroadcastReceiver,只要 Location 设置发生更改(启用或禁用),操作系统就会启动您的应用程序,如果它已启用,您可以从 BroadcastReceiver 启动 Activity。

首先添加 Intent 过滤器,当 OS 发出设置已更改的隐式 Intent 时将捕获该过滤器。

<receiver
    android:name=".LocationProviderChangedReceiver"
    android:exported="false" >
    <intent-filter>
        <action android:name="android.location.PROVIDERS_CHANGED" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</receiver>

请注意,要使其在 Android Oreo 及更高版本上运行,您需要在运行时注册广播接收器,请参见此处:https://developer.android.com/guide/components/broadcasts#context-registered-receivers

然后,在 LocationProviderChangedReceiver.java 中,您的实现将如下所示:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.util.Log;
import android.widget.Toast;

public class LocationProviderChangedReceiver extends BroadcastReceiver {
    private final static String TAG = "LocationProviderChanged";

    boolean isGpsEnabled;
    boolean isNetworkEnabled;

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().matches("android.location.PROVIDERS_CHANGED"))
        {
            Log.i(TAG, "Location Providers changed");

            LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
            isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            //Start your Activity if location was enabled:
            if (isGpsEnabled || isNetworkEnabled) {
                  Intent i = new Intent(context, YourActivity.class);
                  context.startActivity(i);
            }
        }
    }
}

编辑

针对 Android 9 使用 Kotlin 和在运行时注册接收器的更新解决方案。

Kotlin 中的 BroadcastReceiver 类:

class LocationProviderChangedReceiver : BroadcastReceiver() {

    internal var isGpsEnabled: Boolean = false
    internal var isNetworkEnabled: Boolean = false

    override fun onReceive(context: Context, intent: Intent) {
        intent.action?.let { act ->
            if (act.matches("android.location.PROVIDERS_CHANGED".toRegex())) {
                val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
                isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
                isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)

                Log.i(TAG, "Location Providers changed, is GPS Enabled: " + isGpsEnabled)

                //Start your Activity if location was enabled:
                if (isGpsEnabled || isNetworkEnabled) {
                    val i = Intent(context, YourActivity::class.java)
                    context.startActivity(i)
                }
            }
        }
    }

    companion object {
        private val TAG = "LocationProviderChanged"
    }
}

在运行时注册,例如在您应用的 MainActivity 的 onCreate() 中:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val br: BroadcastReceiver = LocationProviderChangedReceiver()
    val filter = IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION)
    registerReceiver(br, filter)
}

关于java - 如何?监听位置设置是否已打开(Android 应用程序),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36325088/

有关java - 如何?监听位置设置是否已打开(Android 应用程序)的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

随机推荐