我在我的应用程序中添加后台位置服务功能时遇到问题。该代码不起作用。我希望在后台每 1 分钟将用户的位置发送到后端服务器。但我没有在后端服务器上受到攻击,我认为我的代码存在与用户位置相关的问题。即使我也没有进入该位置的 Android 代码。也许我的代码中有一些。
下面是我的MainActivity代码
package ses.hasnain.sesproduct;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static ses.hasnain.sesproduct.BuildConfig.VERSION_NAME;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.navigation.NavigationView;
import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import ses.hasnain.sesproduct.Database.DBHelper;
import ses.hasnain.sesproduct.Retrofit.ApiClient;
import ses.hasnain.sesproduct.Retrofit.RequestApi;
import ses.hasnain.sesproduct.Retrofit.SpinnerData;
import ses.hasnain.sesproduct.Retrofit.Tasks;
import ses.hasnain.sesproduct.SharedPreference.SaveSharedPreference;
import ses.hasnain.sesproduct.UXFragments.ActiveProjects;
import ses.hasnain.sesproduct.UXFragments.CEODashboard;
import ses.hasnain.sesproduct.UXFragments.ChangePassword;
import ses.hasnain.sesproduct.UXFragments.Dashboard;
import ses.hasnain.sesproduct.UXFragments.LocationCheck;
import ses.hasnain.sesproduct.UXFragments.Login;
import ses.hasnain.sesproduct.UXFragments.MarkAttendance;
import ses.hasnain.sesproduct.UXFragments.MyJobIntentService;
import ses.hasnain.sesproduct.UXFragments.NotificationList;
import ses.hasnain.sesproduct.UXFragments.Splash;
import ses.hasnain.sesproduct.UXFragments.SyncData;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
@SuppressLint("StaticFieldLeak")
public static Toolbar toolbar;
@SuppressLint("StaticFieldLeak")
public static TextView nav_username;
@SuppressLint("StaticFieldLeak")
public static ImageView profile_pic;
@SuppressLint("StaticFieldLeak")
public static FrameLayout redCircle;
@SuppressLint("StaticFieldLeak")
public static TextView countTextView;
@SuppressLint("StaticFieldLeak")
public static Context activity;
public static FloatingActionButton fab;
public static DrawerLayout drawer;
public static NavigationView navigationView;
public static String UserId = null;
public static String UserIndex = null;
public static String UserImage = null;
public static String CompanyID = null;
public static String versionName = null;
public static boolean logoutStatus = false;
public static DBHelper db;
public static int alertCount = 0;
private static ProgressDialog progress;
Context context;
private boolean isFirstLaunch = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
versionName = VERSION_NAME;
activity = this;
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
context = getBaseContext();
db = new DBHelper(getApplicationContext());
fab = findViewById(R.id.fab);
fab.setOnClickListener(view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show());
drawer = findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
getSupportFragmentManager().beginTransaction().add(R.id.frameLayout, new Splash()).commit();
Handler handler = new Handler();
Intent mIntent = new Intent(context, MyJobIntentService.class);
mIntent.putExtra("maxCountValue", 1500);
final Runnable r = new Runnable() {
public void run() {
MyJobIntentService.enqueueWork(context,mIntent);
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(r, 1000);
}
@Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (logoutStatus) {
System.exit(0);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
alertCount = 0;
final MenuItem alertMenuItem = menu.findItem(R.id.activity_main_alerts_menu_item);
FrameLayout rootView = (FrameLayout) alertMenuItem.getActionView();
redCircle = rootView.findViewById(R.id.view_alert_red_circle);
countTextView = rootView.findViewById(R.id.view_alert_count_textview);
redCircle.setVisibility((alertCount > 0) ? VISIBLE : GONE);
rootView.setOnClickListener(v -> onOptionsItemSelected(alertMenuItem));
return true;
}
@SuppressLint("NonConstantResourceId")
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
switch (item.getItemId()) {
case R.id.action_refresh:
updateAlertIcon();
return true;
case R.id.activity_main_alerts_menu_item:
alertCount = 0;
redCircle.setVisibility(GONE);
getSupportFragmentManager().beginTransaction().addToBackStack(String.valueOf(MainActivity.class)).replace(R.id.frameLayout, new NotificationList()).commit();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void updateAlertIcon() {
alertCount = 0;
RequestApi api = ApiClient.getInstance();
Call<ArrayList<Tasks>> call = api.getCountTotal("getCountTotal", MainActivity.UserIndex, MainActivity.CompanyID);
call.enqueue(new Callback<ArrayList<Tasks>>() {
@Override
public void onResponse(@NonNull Call<ArrayList<Tasks>> call, @NonNull Response<ArrayList<Tasks>> response) {
if (response.isSuccessful()) {
assert response.body() != null;
Tasks data = response.body().get(0);
alertCount = Integer.parseInt(data.getTaskpopup()) + Integer.parseInt(data.getFollowuppopup());
// if alert count extends into two digits, just show the red circle
if (0 < alertCount) {
if (alertCount > 10) {
String text = alertCount + "+";
countTextView.setText(text);
} else
countTextView.setText(String.valueOf(alertCount));
} else {
countTextView.setText("");
}
redCircle.setVisibility((alertCount > 0) ? VISIBLE : GONE);
}
}
@Override
public void onFailure(@NonNull Call<ArrayList<Tasks>> call, @NonNull Throwable t) {
Toast.makeText(getBaseContext(), "Failed to connect with server", Toast.LENGTH_LONG).show();
}
});
}
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.dashboard) {
getSupportFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.frameLayout, new Dashboard()).commit();
} else if (id == R.id.logout) {
LogoutSession(getBaseContext(), SaveSharedPreference.getuserIndex(getBaseContext()), SaveSharedPreference.getcompany_ID(getBaseContext()));
} else if (id == R.id.ceo_dashboard) {
getSupportFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.frameLayout, new CEODashboard()).commit();
} else if (id == R.id.nav_password) {
getSupportFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.frameLayout, new ChangePassword()).commit();
} else if (id == R.id.nav_syncData) {
getSupportFragmentManager().beginTransaction().addToBackStack(String.valueOf(MainActivity.class)).replace(R.id.frameLayout, new SyncData()).commit();
} else if (id == R.id.activeProjects) {
getSupportFragmentManager().beginTransaction().addToBackStack(String.valueOf(MainActivity.class)).replace(R.id.frameLayout, new ActiveProjects()).commit();
} else if(id==R.id.mark_attendance){
getSupportFragmentManager().beginTransaction().addToBackStack(String.valueOf(MainActivity.class)).replace(R.id.frameLayout, new MarkAttendance()).commit();
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
public static void startProgress(boolean isCancelable) {
stopProgress();
progress = new ProgressDialog(activity, R.style.ProgressBarTheme);
progress.setProgressStyle(android.R.style.Widget_ProgressBar_Small);
progress.setIndeterminate(true);
progress.setCancelable(isCancelable);
progress.setCanceledOnTouchOutside(isCancelable);
progress.show();
}
public static void stopProgress() {
if (null != progress && progress.isShowing()) {
progress.dismiss();
}
}
private void LogoutSession(final Context context, final String userIndex, final String CompanyName) {
RequestApi api = ApiClient.getInstance();
Call<ArrayList<SpinnerData>> call = api.LogoutSession("LogoutSession", userIndex, CompanyName);
call.enqueue(new Callback<ArrayList<SpinnerData>>() {
@Override
public void onResponse(@NonNull Call<ArrayList<SpinnerData>> call, @NonNull Response<ArrayList<SpinnerData>> response) {
if (response.isSuccessful()) {
SaveSharedPreference.removeValues(context);
db.deleteDatabase();
MainActivity.logoutStatus = true;
Bundle bundle = new Bundle();
bundle.putString("pCheck", "0");
bundle.putString("link", "");
Login login = new Login();
login.setArguments(bundle);
Toast.makeText(context, "You have successfully logged out from the application.", Toast.LENGTH_LONG).show();
getSupportFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.frameLayout, login).commit();
}
}
@Override
public void onFailure(@NonNull Call<ArrayList<SpinnerData>> call, @NonNull Throwable t) {
Toast.makeText(context, "Unable to connect the server at this time, please try again later.", Toast.LENGTH_LONG).show();
}
});
}
@Override
protected void onDestroy() {
db = new DBHelper(getBaseContext());
super.onDestroy();
Intent mIntent = new Intent(context, MyJobIntentService.class);
mIntent.putExtra("maxCountValue", 1500);
MyJobIntentService.enqueueWork(context, mIntent);
}
}
下面是我的 MyJobIntent 代码,我正在其中完成用户位置的所有工作
package ses.hasnain.sesproduct.UXFragments;
import static ses.hasnain.sesproduct.UXFragments.ScheduledService.context;
import android.Manifest;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
import androidx.core.app.NotificationCompat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import ses.hasnain.sesproduct.Database.DBHelper;
import ses.hasnain.sesproduct.R;
import ses.hasnain.sesproduct.Retrofit.ApiClient;
import ses.hasnain.sesproduct.Retrofit.FormSubmitPOJO;
import ses.hasnain.sesproduct.Retrofit.RequestApi;
import ses.hasnain.sesproduct.SharedPreference.SaveSharedPreference;
public class MyJobIntentService extends JobIntentService implements LocationListener {
private static final String TAG = "MyJobIntentService";
private static final int JOB_ID = 39992;
private static DBHelper db;
private static Context activity;
private static LocationManager locationManager;
private static boolean isTrackingStarted = false;
private static boolean isSendingData = false;
private static int idCheck = 0;
private static final int INITIAL_DELAY = 0; // Start immediately
private static final int INTERVAL = 60 * 1000; // Every 1 minute
private static final String CHANNEL_ID = "LocationTrackingChannel";
private static final String CHANNEL_NAME = "Location Tracking";
@Override
public void onCreate() {
super.onCreate();
db = new DBHelper(getApplicationContext());
activity = getApplicationContext();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
if (!isTrackingStarted) {
startForegroundService();
isTrackingStarted = true;
}
scheduleLocationUpdates();
}
// Start a foreground service for continuous location tracking
private void startForegroundService() {
createNotificationChannel();
Intent notificationIntent = new Intent(this, MyJobIntentService.class);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Location Tracking")
.setContentText("Tracking your location in background")
.build();
startForeground(1, notification);
// Start tracking location
startLocationTracking();
}
// Schedule periodic tasks to send location data to backend
private void scheduleLocationUpdates() {
if (!isSendingData) {
isSendingData = true;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
sendLocationDataToBackend();
handler.postDelayed(this, INTERVAL);
}
}, INITIAL_DELAY);
}
}
// Method to send location data to backend
private void sendLocationDataToBackend() {
Location location = getLastKnownLocation();
if (location != null) {
String lat = String.valueOf(location.getLatitude());
String lon = String.valueOf(location.getLongitude());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
String currentDateandTime = sdf.format(new Date());
// Assuming ActionID is fixed for your case, adjust as needed
String actionId = "insertEmployeeLoc";
// Insert data to backend via Retrofit
RequestApi api = ApiClient.getInstance();
Call<ArrayList<FormSubmitPOJO>> call = api.InsertEmployeeLoc(actionId, lat, lon, currentDateandTime,
String.valueOf(idCheck), SaveSharedPreference.getuserIndex(activity),
SaveSharedPreference.getcompany_ID(activity));
call.enqueue(new Callback<ArrayList<FormSubmitPOJO>>() {
@Override
public void onResponse(Call<ArrayList<FormSubmitPOJO>> call, Response<ArrayList<FormSubmitPOJO>> response) {
if (response.isSuccessful()) {
Toast.makeText(context, "Permission granted", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Permission denied", Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(Call<ArrayList<FormSubmitPOJO>> call, Throwable t) {
Toast.makeText(context, "Server Error", Toast.LENGTH_LONG).show();
}
});
}
}
// Helper method to get last known location
private Location getLastKnownLocation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return null;
}
}
return locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
// Start tracking location if it's not already started
private void startLocationTracking() {
// Implement your logic to start tracking location here
// This typically involves setting up a location listener
// and requesting location updates from LocationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
// Create notification channel for foreground service
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
if (manager != null) {
manager.createNotificationChannel(serviceChannel);
}
}
}
@Override
public void onLocationChanged(Location location) {
// Handle location updates here if needed
}
// Other LocationListener methods
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onProviderDisabled(String provider) {}
// Enqueue work method to start the service
public static void enqueueWork(Context context, Intent intent) {
activity = context;
enqueueWork(context, MyJobIntentService.class, JOB_ID, intent);
}
}
好的,请告诉我您的服务等级是否被触发?你检查了吗?
如果否,请在清单中注册您的服务。
<application>
....
<service android:enabled="true" android:name=".MyJobIntentService " />
</application>