修改:我已将代码添加到最近尝试的底部。
我正在尝试按照示例代码here。我在检索最后一个已知位置时遇到困难。我尝试了几种方法。
我对如何获得位置感到茫然。我的目标与第一个链接的示例类似。我想构建一个在后台运行的服务,并将在指定的时间间隔内将其位置的更新发送到服务器。到目前为止,我已经创建了两个按钮,允许服务启动和停止。服务启动后,它会检查设备是否有移动数据。然后,我想要检查位置是否已打开并且有GPS信号。我只想要GPS信号而不是网络位置。最后,如果数据和位置/ GPS信号都为真,那么它会在指定的时间间隔内将其位置发送到服务器。到目前为止,这是我的代码。
MainActivity.java
package com.testtracker;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyService.setUp(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@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.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings)
{
return true;
}
return super.onOptionsItemSelected(item);
}
public void startService(View view)
{
startService(new Intent(getBaseContext(), MyService.class));
}
public void stopService(View view)
{
stopService(new Intent(getBaseContext(), MyService.class));
}
}
MyService.java
package com.testtracker;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.os.IBinder;
import android.os.PowerManager;
import android.widget.Button;
import android.widget.Toast;
import java.lang.reflect.Method;
import java.util.Timer;
import java.util.TimerTask;
public class MyService extends Service
{
PowerManager powerManager;
PowerManager.WakeLock wakeLock;
static Button startButton;
static Button stopButton;
public static void setUp(Activity act)
{
startButton = (Button)act.findViewById(R.id.button2);
stopButton = (Button)act.findViewById(R.id.button);
}
@Override
public IBinder onBind(Intent intent)
{
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
startButton.setEnabled(false);
stopButton.setEnabled(true);
final ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
Timer timer = new Timer();
final int TIME_INTERVAL = 10000;
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
timer.schedule(new TimerTask()
{
boolean mobileDataEnabled = false;
public void run() {
try {
//Check if phone has data
Class cmClass = Class.forName(connectivityManager.getClass().getName());
Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
method.setAccessible(true);
mobileDataEnabled = (Boolean) method.invoke(connectivityManager);
if (mobileDataEnabled)
{
//Has data. Check if phone has location and GPS signal. If it does, get location and send to server.
}
else
{
//No data. Check again during the next timer interval.
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, 0, TIME_INTERVAL);
return START_STICKY;
}
@Override
public void onDestroy()
{
super.onDestroy();
wakeLock.release();
startButton.setEnabled(true);
stopButton.setEnabled(false);
Toast.makeText(this, "Service Stopped", Toast.LENGTH_SHORT).show();
}
}
通过我一直在进行的尝试(记录在我的下面的评论中),我想我会发布更新后的代码。我将使用当前的尝试更新以下代码,并将上述代码保留为原始代码。我最好使用FusedLocationProviderApi或Little Fluffy Location Library,因为它们似乎已针对在后台运行进行了优化。
MainActivity.java
package com.testtracker;
import android.app.Activity;
import android.content.Intent;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity implements Button.OnClickListener
{
Button startButton;
Button stopButton;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton = (Button)findViewById(R.id.button2);
stopButton = (Button)findViewById(R.id.button);
startButton.setEnabled(true);
stopButton.setEnabled(false);
LocationManager service = (LocationManager)getSystemService(LOCATION_SERVICE);
boolean locationEnabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(!locationEnabled)
{
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
startButton.setOnClickListener(this);
stopButton.setOnClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@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.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings)
{
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onClick(View v)
{
switch(v.getId())
{
case R.id.button2:
startButton.setEnabled(false);
stopButton.setEnabled(true);
Intent intentStart = new Intent(this, MyService.class);
startService(intentStart);
break;
case R.id.button:
startButton.setEnabled(true);
stopButton.setEnabled(false);
Intent intentStop = new Intent(this, MyService.class);
stopService(intentStop);
break;
}
}
}
MyService.java
package com.testtracker;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.widget.Toast;
import java.lang.reflect.Method;
import java.util.Timer;
import java.util.TimerTask;
public class MyService extends Service implements LocationListener
{
protected LocationManager locationManager;
protected LocationListener locationListener;
PowerManager powerManager;
PowerManager.WakeLock wakeLock;
public void onCreate()
{
Toast.makeText(this, "in on create", Toast.LENGTH_SHORT).show();
}
@Override
public IBinder onBind(Intent intent)
{
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
final ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
Timer timer = new Timer();
final int TIME_INTERVAL = 10000;
Looper.prepare(); //Fatal error said this must be added?
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
timer.schedule(new TimerTask()
{
boolean mobileDataEnabled = false;
public void run() {
try {
//Check if phone has data
Class cmClass = Class.forName(connectivityManager.getClass().getName());
Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
method.setAccessible(true);
mobileDataEnabled = (Boolean) method.invoke(connectivityManager);
if (mobileDataEnabled)
{
//Has data. Check if phone has location and GPS signal. If it does, get location and send to server.
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
final Criteria cri = new Criteria();
String bestProvider = locationManager.getBestProvider(cri, true);
Location loc = locationManager.getLastKnownLocation(bestProvider);
double lat = loc.getLatitude();
double lng = loc.getLongitude();
Toast.makeText(getBaseContext(), lat + " - " + lng, Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
onDestroy();
}
}
}, 0, TIME_INTERVAL);
return START_STICKY;
}
@Override
public void onDestroy()
{
super.onDestroy();
wakeLock.release();
Toast.makeText(this, "Service Stopped", Toast.LENGTH_SHORT).show();
}
@Override
public void onLocationChanged(Location location) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
logcat的 错误看起来像是由Looper.prepare()引起的。如果我不添加,那么我得到致命错误“无法在未调用Looper.prepare()的线程内创建处理程序”。不能赢这个吗?
2263-2263/com.testtracker E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.testtracker, PID: 2263
java.lang.RuntimeException: Unable to start service com.testtracker.MyService@18edb4e4 with Intent { cmp=com.testtracker/.MyService }: java.lang.RuntimeException: Only one Looper may be created per thread
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2914)
at android.app.ActivityThread.access$2100(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1401)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5257)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: java.lang.RuntimeException: Only one Looper may be created per thread
at android.os.Looper.prepare(Looper.java:76)
at android.os.Looper.prepare(Looper.java:71)
at com.testtracker.MyService.onStartCommand(MyService.java:53)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2897)
at android.app.ActivityThread.access$2100(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1401)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5257)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)