草庐IT

android - 是否可以在锁定设备后继续在 android 平台上运行服务?

coder 2023-11-29 原文

我们一直致力于为安卓平台开发服务。

在我们的服务中,我们需要每隔一分钟将设备的 GPS 数据(纬度和经度)发送到一些外部 REST 服务。

锁定设备后,它可以正常运行近 15 分钟。但在那之后它不发送任何数据。

解锁设备后,它再次开始通过 REST 服务发送数据。

到目前为止我的代码

public class MainActivity extends AppCompatActivity {

private PendingIntent pendingIntent;
private PowerManager.WakeLock wakeLock;

public static final String USER_NAME = "USERNAME";

String username;
String password;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Intent alarm = new Intent(this, AlarmReceiver.class);
    boolean alarmRunning = (PendingIntent.getBroadcast(this, 0, alarm, PendingIntent.FLAG_NO_CREATE) != null);
    if(alarmRunning == false) {
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarm, 0);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), 30000, pendingIntent);
    }

    PowerManager mgr = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
    wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakeLock");
    wakeLock.acquire();
 }

public class BackgroundService extends Service  {

private boolean isRunning;
private Context context;
private Thread backgroundThread;

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    this.context = this;
    this.isRunning = false;
    this.backgroundThread = new Thread(myTask);
}

private Runnable myTask = new Runnable() {
    public void run() {
        // Do something here
        login("admin","admin");
        stopSelf();
    }
};

@Override
public void onDestroy() {
    this.isRunning = false;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if(!this.isRunning) {
        this.isRunning = true;
        this.backgroundThread.start();
    }
    return START_STICKY;
}

private void login(final String strLatitude, final String strLongitude) {


    class LoginAsync extends AsyncTask<String, Void, String> {

        String charset = "UTF-8";
        HttpURLConnection conn;
        DataOutputStream wr;
        StringBuilder result = new StringBuilder();
        URL urlObj;
        JSONObject jObj = null;
        StringBuilder sbParams;
        String paramsString;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // loadingDialog = ProgressDialog.show(MainActivity.this, "Please wait", "Loading...");
        }

        @Override
        protected String doInBackground(String... params) {
            String uname = params[0];
            String pass = params[1];

            sbParams = new StringBuilder();

            try {
                sbParams.append("name").append("=")
                        .append(URLEncoder.encode(uname, charset));
                sbParams.append("&");
                sbParams.append("password").append("=")
                        .append(URLEncoder.encode(pass, charset));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            try {

                String url="http://192.168.0.122:1234/YegoService.svc/AddVehicleMovement";
                URL object=new URL(url);

                HttpURLConnection con = (HttpURLConnection) object.openConnection();
                con.setDoOutput(true);
                con.setDoInput(true);
                con.setRequestProperty("Content-Type", "application/json");
                con.setRequestProperty("Accept", "application/json");
                con.setRequestMethod("POST");

                JSONObject parent = new JSONObject();

                parent.put("strValidatorID","111");
                parent.put("TXT_LAT", "28.25252525");

                parent.put("TXT_LONG", "77.7777777");
                parent.put("DAT_DATE", "");
                con.connect();

                OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream());
                wr.write(parent.toString());
                wr.flush();
                wr.close();

                InputStream input = con.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(input));
                String line;

                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }

                con.disconnect();

            } catch (IOException e) {
                e.printStackTrace();
            }
            catch (Exception ex) {
                ex.printStackTrace();
            }

            return result.toString();
        }

        @Override
        protected void onPostExecute(String result){
            String s = result.trim();
        }
    }

    LoginAsync la = new LoginAsync();
    la.execute("admin", "admin");

}

}

public class AlarmReceiver extends BroadcastReceiver {
String strLatitude;
String strLongitude;

@Override
public void onReceive(Context context, Intent intent) {
    Intent background = new Intent(context, BackgroundService.class);
    context.startService(background);
}
}

要做什么?

最佳答案

一种方法是让您依赖 AlarmManager :一旦您订阅了 AlarmManager,系统本身就会按照您设置的时间间隔运行您的代码,即使您的应用程序未处于 Activity 状态。每次运行时,您都可以决定处理一些代码...因此您完全避免了保持服务 Activity 的需要。

您需要的是一个将处理 AlarmManager Intent 的 Alarm 类。


创建您的闹钟:

public class Alarm extends BroadcastReceiver 
{

    private static final String TAG = "Alarm";

    @Override
    public void onReceive(Context context, Intent intent) 
    {   
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
        wl.acquire();

        /***************
        Here you can do your stuff...
        This will be triggered every second. 
        Send data from here, or better: call an IntentService
        that will take care of it.
        ****************/

        wl.release();
    }

    public void SetAlarm(Context context)
    {
        Intent i = new Intent(context, Alarm.class);

        boolean alarmUp = (PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_NO_CREATE) != null);

        if (alarmUp)
        {
            // The alarm is already running, do not set it twice
        }
        else
        {
            AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
            PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
            am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000, pi); // 1000 Millisec means it will trigger it every second... and RTC_WAKEUP means that it will wake up your device if needed.
        }
    }

    // later on, use this method if you want to manually cancel the AlarmManager :

    public void CancelAlarm(Context context)
    {
        Intent intent = new Intent(context, Alarm.class);
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(sender);
    }
}

在你的 Manifest 中声明这个 Alarm BroadcastReceiver

<receiver 
    android:name=".utils.Alarm"
    android:process=":remote" >
</receiver>

然后从您想要在 Activity 中调用此 AlarmManager 的位置!

Alarm alarm = new Alarm();

@Override
protected void onCreate(Bundle savedInstanceState) 
{

    alarm.SetAlarm(this);

}

// or if elsewhere you need to stop the Alarm :
alarm.CancelAlarm(this);

这是主要思想。 现在你需要处理屏幕打开或关闭。 对于这 2 种解决方案:您可以注册设备屏幕状态 Intent 并管理 AlarmManager 开/关...或者您可以让 AlarmManager 始终运行但在发送数据之前检查设备是否开/关...

希望这会有所帮助!

关于android - 是否可以在锁定设备后继续在 android 平台上运行服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36399123/

有关android - 是否可以在锁定设备后继续在 android 平台上运行服务?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  3. 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

  4. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

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

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

  6. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  7. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  8. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  9. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  10. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

随机推荐