问题描述
即使关闭了应用程序,我仍使用Service来保持对Android手机的扫描。遇难时,我使用广播接收器重新启动了服务。它重新启动扫描,仅工作约15秒钟,然后停止 当我在{MainActivity}中单击button1时,我启动了服务,并在{ExampleService}中的startCommand方法中调用了startdiscovery() 请帮助我在后台运行该应用程序
MainActivity.java
import android.Manifest;
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.broadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.bluetooth.le.ScanResult;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.ResolvableApiException;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResponse;
import com.google.android.gms.location.LocationSettingsstatusCodes;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.FirebaseFirestore;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
ListView scanListView;
ArrayList<String> stringArrayList = new ArrayList<String>();
ArrayAdapter<String> arrayAdapter;
static BluetoothAdapter myAdapter = BluetoothAdapter.getDefaultAdapter();
FirebaseFirestore db = FirebaseFirestore.getInstance();
static int count=0;
ScanResult sc;
String Uuid;
Date currentTime;
private LocationSettingsRequest.Builder builder;
private final int REQUEST_CHECK_CODE=8989;
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
LocationManager locationm;
String provider;
Button button1;
BluetoothAdapter bluetoothAdapter;
Intent btEnablingIntent;
int requestCodeForEnable;
Button button;
Button scanButton1;
Registeractivity registeractivity=new Registeractivity();
String email ;
String phone ;
///
Intent discoverableIntenet = new Intent(BluetoothAdapter.ACTION_REQUEST_disCOVERABLE);
Intent mServiceIntent;
private ExampleService mYourService;
Context ctx;
public Context getCtx() {
return ctx;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
currentTime = Calendar.getInstance().getTime();
setContentView(R.layout.activity_main);
checkLocationPermission();
btEnablingIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
requestCodeForEnable=1;
discoverableIntenet.putExtra(BluetoothAdapter.EXTRA_disCOVERABLE_DURATION,3000);
startActivity(discoverableIntenet);
button=(Button) findViewById(R.id.button4);
Intent intent = new Intent(MainActivity.this,ble.class);
button.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,ble.class);
MainActivity.this.startActivity(intent);
}
});
button=(Button) findViewById(R.id.button6);
button.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
open(view);
}
});
button=(Button) findViewById(R.id.button3);
button.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
pdfs(view);
}
});
button=(Button) findViewById(R.id.button5);
button.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
myths(view);
}
});
button1=(Button) findViewById(R.id.button2);
button1.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
analytics(view);
}
});
scanListView = (ListView) findViewById(R.id.scannedListView);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
scanButton1=(Button) findViewById(R.id.Button1);
scanButton1.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("disc","discoveeery!");
Log.i("hiiiiiii",String.valueOf(myAdapter.isdiscovering()));
Intent serviceIntent = new Intent(MainActivity.this,ExampleService.class);
serviceIntent.putExtra("inputExtra","hi");
// startService( serviceIntent);
mYourService = new ExampleService();
mServiceIntent = new Intent(MainActivity.this,mYourService.getClass());
if (!isMyServiceRunning(mYourService.getClass())) {
startService(mServiceIntent);
}
}
});
bluetoothOnMethod();
BluetoothFunctions();
}
public void BluetoothFunctions(){
Log.d("disc","discovery!");
IntentFilter intentFilter;
intentFilter=new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(myreceiver,intentFilter);
intentFilter = new IntentFilter(BluetoothAdapter.ACTION_disCOVERY_FINISHED);
registerReceiver(myreceiver,intentFilter);
arrayAdapter = new ArrayAdapter<String>(getApplicationContext(),android.R.layout.simple_list_item_1,stringArrayList);
scanListView.setAdapter(arrayAdapter);
Uuid="02.020202.020.02";
}
@Override
protected void onActivityResult(int requestCode,int resultCode,@Nullable Intent data) {
super.onActivityResult(requestCode,resultCode,data);
if (requestCode == requestCodeForEnable) {
if (resultCode == RESULT_OK) {
Toast.makeText(getApplicationContext(),"Bluetooth is enabled",Toast.LENGTH_LONG).show();
}
else if(resultCode==RESULT_CANCELED) {
Toast.makeText(getApplicationContext(),"Bluetooth enabling cancelled",Toast.LENGTH_LONG).show();
}
}
}
final broadcastReceiver myreceiver = new broadcastReceiver() {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context,Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getName() == null) {
return;
}
String address = device.getName();
int N = 2;
float type = intent.getFloatExtra((BluetoothDevice.EXTRA_UUID),Float.MIN_VALUE);
int RSSi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE);
String RSSi_val = String.valueOf(RSSi);
String data = device.getAddress() + " " + RSSi_val;
Vibrator v1 = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
stringArrayList.add(data);
if (RSSi >= -50) {
v1.vibrate(VibrationEffect.createOneshot(1000,VibrationEffect.DEFAULT_AMPLITUDE));
count++;
if (device.getAddress() != null) {
Firebasepush(device.getAddress(),RSSi_val);
}
}
Log.i("lll",device.getAddress());
Log.i("lll",device.getName());
Log.i("+>>>>>>>>>>>>>",BluetoothDevice.EXTRA_UUID);
Log.i("lll",RSSi_val);
arrayAdapter.notifyDataSetChanged();
// Toast.makeText(getApplicationContext()," TX power: " +sc.getTxPower() + "dBm",Toast.LENGTH_SHORT).show();
//startThread();
} else if (BluetoothAdapter.ACTION_disCOVERY_FINISHED.equals(action)) {
Log.v("ggggggggg","Entered the Finished ");
myAdapter.startdiscovery();
}
}
};
public void Firebasepush(String uuid,String rrsi){
Map<String,Object> updateMap = new HashMap();
updateMap.put("RSSI",rrsi);
updateMap.put("time",currentTime);
Map<String,Object> countMap = new HashMap();
countMap.put("Count",count);
countMap.put("time",currentTime);
countMap.put("Name",registeractivity.NameString);
countMap.put("Email",registeractivity.EmailId);
countMap.put("Phone Number",registeractivity.PhoneNumber);
// Add a new document with a generated ID
db.collection("users").document(Uuid).collection("contacts").document(uuid)
.set(updateMap);
db.collection("users").document(Uuid).
set(countMap);
}
void bluetoothOnMethod() {
if(bluetoothAdapter==null){
Toast.makeText(getApplicationContext(),"Bluetooth does not support ",Toast.LENGTH_LONG).show();
}
else {
if(!bluetoothAdapter.isEnabled()){
startActivityForResult(btEnablingIntent,requestCodeForEnable);
}
}
}
public boolean checkLocationPermission() {
LocationRequest request = new LocationRequest()
.setFastestInterval(1500)
.setInterval(3000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
builder = new LocationSettingsRequest.Builder()
.addLocationRequest(request);
Task<LocationSettingsResponse> result = LocationServices.getSettingsClient( this).checkLocationSettings(builder.build());
result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
@Override
public void onComplete(@NonNull Task<LocationSettingsResponse> task) {
try{
task.getResult(ApiException.class);
}catch (ApiException e){
switch (e.getStatusCode())
{
case LocationSettingsstatusCodes
.RESOLUTION_required:
try {
ResolvableApiException resolvableApiException= (ResolvableApiException) e;
resolvableApiException.startResolutionForResult(MainActivity.this,REQUEST_CHECK_CODE);
} catch (IntentSender.SendIntentException ex) {
ex.printstacktrace();
}catch (ClassCastException ex){
}break;
case LocationSettingsstatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
{ break;}
}
}
}
});
if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation,try again to request the permission.
new AlertDialog.Builder(this)
.setTitle(R.string.title_location_permission)
.setMessage(R.string.text_location_permission)
.setPositiveButton(R.string.ok,new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface,int i) {
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},MY_PERMISSIONS_REQUEST_LOCATION);
}
})
.create()
.show();
} else {
ActivityCompat.requestPermissions(this,MY_PERMISSIONS_REQUEST_LOCATION);
}
return false;
} else {
return true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode,String permissions[],int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled,the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted,yay! Do the
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Request location updates:
// locationm.requestLocationUpdates(provider,400,1,this);
}
} else {
// permission denied,boo! disable the
// functionality that depends on this permission.
}
return;
}
}
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
Log.i ("Service status","Running");
return true;
}
}
Log.i ("Service status","Not running");
return false;
}
@Override
protected void onDestroy() {
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("restartservice");
broadcastIntent.setClass(this,Restarter.class);
this.sendbroadcast(broadcastIntent);
super.onDestroy();
// Don't forget to unregister the ACTION_FOUND receiver.
// unregisterReceiver(myreceiver);
}
public void openservices(){
Intent intnt=new Intent(this,Services.class);
startActivity(intnt);
}
public void open(View view)
{
Intent browserIntent=new Intent(Intent.ACTION_VIEW,Uri.parse("https://www.hogist.com/#/"));
startActivity(browserIntent);
}
public void pdfs(View view)
{
Intent browserIntent=new Intent(Intent.ACTION_VIEW,Uri.parse("https://www.mohfw.gov.in/pdf/Illustrativeguidelineupdate.pdf"));
startActivity(browserIntent);
}
public void myths(View view)
{
Intent browserIntent=new Intent(Intent.ACTION_VIEW,Uri.parse("https://www.mohfw.gov.in/pdf/Illustrativeguidelineupdate.pdf"));
startActivity(browserIntent);
}
public void analytics(View view){
final Intent intent1 = new Intent(MainActivity.this,Analytics.class);
startActivity(intent1);
}
}
ExampleService.java
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.notificationmanager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import java.util.Timer;
import java.util.TimerTask;
public class ExampleService extends Service {
BluetoothAdapter myAdapter = BluetoothAdapter.getDefaultAdapter();
MainActivity mainActivity=new MainActivity();
public int counter=0;
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
startMyOwnForeground();
else
startForeground(1,new Notification());
}
@RequiresApi(Build.VERSION_CODES.O)
private void startMyOwnForeground()
{
String NOTIFICATION_CHANNEL_ID = "example.permanence";
String channelName = "Background Service";
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID,channelName,notificationmanager.IMPORTANCE_NONE);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
notificationmanager manager = (notificationmanager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID);
Notification notification = notificationBuilder.setongoing(true)
.setContentTitle("App is running in background")
.setPriority(notificationmanager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(2,notification);
}
@Override
public int onStartCommand(Intent intent,int flags,int startId) {
super.onStartCommand(intent,flags,startId);
// startTimer();
myAdapter.startdiscovery();
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
// stoptimertask();
myAdapter.canceldiscovery();
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("restartservice");
broadcastIntent.setClass(this,Restarter.class);
this.sendbroadcast(broadcastIntent);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}```
Restarter.java
import android.content.broadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
public class Restarter extends broadcastReceiver {
@Override
public void onReceive(Context context,Intent intent) {
Log.i("broadcast Listened","Service tried to stop");
Toast.makeText(context,"Service restarted",Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.i(Restarter.class.getSimpleName(),"Service Stops! Oooooooooooooppppssssss!!!!");
context.startForegroundService(new Intent(context,ExampleService.class));
} else {
context.startService(new Intent(context,ExampleService.class));
}
}
}
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hogist_social_distancing">
<uses-permission android:name="android.permission.BLUetoOTH" />
<uses-permission android:name="android.permission.BLUetoOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name=".App"
android:fullBackupContent="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=".Analytics"
android:screenorientation="portrait" />
<activity
android:name=".Services"
android:screenorientation="portrait" />
<activity
android:name=".Permissions"
android:screenorientation="portrait" />
<activity
android:name=".MainActivity"
android:screenorientation="portrait" />
<activity android:name=".Registeractivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".OTPActivity" />
<activity android:name=".ble" />
<service
android:name=".ExampleService"
android:enabled="true" />
<receiver
android:name="Restarter"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="restartservice" />
</intent-filter>
</receiver>
</application>
</manifest>```
解决方法
- 您确定您的蓝牙代码可以很好地进行活动(无需服务)吗?
- 当服务被终止时,您无法通过调用广播来重新启动服务,因为当服务被OS系统终止时,它将终止您的应用程序进程,因此广播将无法进行。当您致电
return START_STICKY;
时,这意味着系统将在有可用资源时自动重新启动您的服务
Android努力节省电池,因此预计您的服务将停止,尤其是当它运行耗电量大的操作(例如蓝牙扫描)时。
此外,请记住,从Android 7开始,每30秒启动BLE扫描的次数不能超过5次。
如果您确实想在后台运行蓝牙扫描,建议您使用JobIntentService
,在其中启动BLE扫描几秒钟。
JobIntentService
与IntentService
非常相似,但是没有什么好处,例如持有唤醒锁可以防止CPU进入睡眠状态
此外,此类服务不需要向您的用户显示通知。有关更多信息:https://developer.android.com/reference/androidx/core/app/JobIntentService