让应用程序始终在 Android 上后台运行

Posted

技术标签:

【中文标题】让应用程序始终在 Android 上后台运行【英文标题】:Keep app running in background on Android all the time 【发布时间】:2017-05-26 18:19:21 【问题描述】:

我必须获取人们的轨迹(例如,从家到工作),所以我的应用获取纬度和经度(我有两个按钮:1. 开始获取纬度和经度 2. 停止获取经度和纬度)。但是,我希望 android 不会杀死应用程序,我希望在用户使用 facebook、twitter(例如)或只是用户锁定他的智能手机时让我的应用程序保持运行。 当用户在使用 facebook 或 twitter(例如)时使用该应用程序时,我的应用程序运行良好,但是当我锁定我的智能手机时,Android 会终止该应用程序。 我曾尝试使用 intentservice 和 service,但当我锁定屏幕时它们不起作用。我应该使用 PowerManager.WakeLock 吗?我不完全知道它是如何工作的以及它的作用。

这是我尝试服务的一个例子,我不知道我是否错了,但它在以下情况下不起作用: 1.我在app里(我已经启动了服务) 2.我点击主页按钮(在服务运行时) 3.我锁屏。 4.然后服务和应用程序被android杀死(并且服务没有完成它的事情)

清单

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.javosoft.intentservice">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        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>
        <service android:name=".MyService"
            android:exported="false"></service>

    </application>

</manifest>

activity_main

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_
    android:layout_
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.javosoft.intentservice.MainActivity">

    <Button
        android:text="start Service"
        android:layout_
        android:layout_
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="63dp"
        android:id="@+id/button"
        android:onClick="startService"/>

    <Button
        android:text="Stop Service"
        android:layout_
        android:layout_
        android:layout_alignParentBottom="true"
        android:layout_alignLeft="@+id/button"
        android:layout_alignStart="@+id/button"
        android:layout_marginBottom="68dp"
        android:id="@+id/button2"
        android:onClick="stopService" />

    <EditText
        android:layout_
        android:layout_
        android:inputType="textPersonName"
        android:hint="textito :D"
        android:ems="10"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/editText" />
</RelativeLayout>

主活动

package com.javosoft.intentservice;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity 

    private Button button;

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

        button = (Button) findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                Intent intent = new Intent(MainActivity.this, MyService.class);
                startService(intent);
            
        );

    

    public void stopService (View view)
        Intent intent = new Intent(this, MyService.class);
        stopService(intent);
    

我的服务类

package com.javosoft.intentservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;

public class MyService extends Service 

    final class MyThreadClass implements Runnable

        int service_id;
        MyThreadClass(int service_id)
            this.service_id = service_id;
        

        @Override
        public void run() 

            synchronized (this)
                int count = 0;
                while (count < 10)
                    Log.i("servicio", "while: " + String.valueOf(count));
                    try 
                        wait(2000);
                        count++;
                     catch (InterruptedException e) 
                        e.printStackTrace();
                    
                
            
            stopSelf(service_id);

        
    

    @Override
    public void onCreate() 
        super.onCreate();
    

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
        Toast.makeText(this, "El servició ha empezado D:", Toast.LENGTH_SHORT).show();
        Log.i("servicio", "El servició ha empezado D:");


        Log.i("servicio", "onStartCommand arriba");

        Thread thread = new Thread(new MyThreadClass(startId));
        thread.start();

        Log.i("servicio", "onStartCommand abajo");
        return START_STICKY;
        //return super.onStartCommand(intent, flags, startId);
    

    @Override
    public void onDestroy() 
        //super.onDestroy();
        Toast.makeText(this, "El servicio ha padarado ._.", Toast.LENGTH_SHORT).show();
        Log.i("servicio", "El servicio ha padarado ._.");
    

    //@Nullable
    @Override
    public IBinder onBind(Intent intent) 

        return null;

    

【问题讨论】:

嗯,关闭屏幕后服务应该可以工作了。 如果我在应用程序中然后我锁定屏幕,它可以工作,但是如果我在应用程序中,我点击主页按钮然后我锁定屏幕,Android 会杀死应用程序. 你能发布你的代码吗?您说您已经尝试过服务,但您如何开始和结束服务很重要。最好发布启动和结束服务的代码以及服务的生命周期方法。我正在做你试图用服务做的事情,所以它可以完成。 好的,我已经更新了我的问题,请忽略标题“IntentService”。在我的代码中,我使用的是服务 这里已经很晚了。我明天再看看这个。你想用 Runnable 做什么? 【参考方案1】:

试试我们的这个

public class ForegroundService extends Service 
    private static final String LOG_TAG = "ForegroundService";

    @Override
    public void onCreate() 
        super.onCreate();
    

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 

        // Your logical code here

        return START_STICKY;
    

    @Override
    public void onTaskRemoved(Intent rootIntent) 

        //When remove app from background then start it again
        startService(new Intent(this, ForegroundService.class));

        super.onTaskRemoved(rootIntent);
    

    @Override
    public void onDestroy() 
        super.onDestroy();
        Log.i(LOG_TAG, "In onDestroy");
    

    @Override
    public IBinder onBind(Intent intent) 
        // Used only in case of bound services.
        return null;
    

点击开始按钮:

Intent startIntent = new Intent(MainActivity.this, ForegroundService.class);
    startService(startIntent);

在清单中

<service
            android:name=".ForegroundService"
            android:enabled="true"
            android:stopWithTask="false" />

【讨论】:

【参考方案2】:

我读到有些智能手机有这样的问题,我发现华为、小米等在实现服务方面有问题,猜猜看:我的智能手机是华为的。问题出在这些设备上预装的节能程序。因此,我尝试在 Nexus(这个模拟器)、Sony 和 Moto G 上运行我的程序,该程序在这 3 台设备上运行良好。 感谢您的帮助。

【讨论】:

【参考方案3】:

正如@Gudin 所说,在我看来,您在 20 秒后停止了服务。但是,由于您说这有时有效,我猜这只是一些测试代码。我怀疑您的问题在于您如何启动服务。传递 Activity 的上下文意味着您的 Service 与该 Activity 的生命周期相关联。如果那被破坏了,我认为您的服务也随之而来。 (只需通过活动的onStop() 而不是onDestroy() 即可使服务保持不变)。试试这个

    Intent intent = new Intent(getApplicationContext(), MyService.class);

我尝试复制您的问题,但不能,所以我不能确定这是您的问题。不过,这是一个很好的起点。

【讨论】:

以上是关于让应用程序始终在 Android 上后台运行的主要内容,如果未能解决你的问题,请参考以下文章

我想让一个app始终在后台运行,不被杀掉进程,怎么设置?

什么是后台运行

如何在 Flutter 中创建服务以使应用始终在后台运行?

应用程序未运行时的iOS后台模式?

让 Android 应用程序在后台运行,防止它停止/死亡

如何让我的 android 应用程序在后台运行?