我有一个Android应用程序,具有一个动作,显示一个地图,一个位置。这个可能会在带有服务的sharedPreferences上更新......好吧,这样可以正常工作。
我需要将我的活动实现runnable作为一个线程,读取每1000ms的sharedPreferences的位置,然后更新地图上的项目位置......但它不起作用。
正如我在调试模式下看到的那样,我的线程无法正常工作,只能在RUN()方法上输入一次......我的意思是再也没有进入RUN()方法,只有一次,导致这个,职位未在地图上更新
有什么问题?为什么这个线程不能正常工作?
public class Locate扩展MapActivity {
private TextView userText = null;
private TextView permissionText = null;
private TextView lastUpdateText = null;
private Button locateButton = null;
private Button traceButton = null;
private MapView mapView = null;
List<Overlay> mapOverlays = null;
double lat;
double lng;
GeoPoint p;
MapController mc;
Drawable drawable;
Drawable drawable2;
MyItemizedOverlay itemizedoverlay;
MyItemizedOverlay itemizedoverlay2;
//para almacenar la config local de mi app, mostrarme o no en el mapa...
static SharedPreferences settings;
static SharedPreferences.Editor configEditor;
private MyLooper mLooper;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.locate);
userText = (TextView) findViewById(R.id.User);
permissionText= (TextView) findViewById(R.id.Permission);
lastUpdateText= (TextView) findViewById(R.id.LastUpdate);
locateButton = (Button) findViewById(R.id.locate);
traceButton = (Button) findViewById(R.id.trace);
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapOverlays = mapView.getOverlays();
mc = mapView.getController();
settings=PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext());
configEditor = settings.edit();
drawable = this.getResources().getDrawable(R.drawable.minifriend); // Icono de la cara, para posiciones de mis amigos
drawable2 = this.getResources().getDrawable(R.drawable.miniicon2); // Icono del programa, para mi posicion GPS
itemizedoverlay = new MyItemizedOverlay(drawable, this); // Aqui almaceno otras posiciones gps
itemizedoverlay2 = new MyItemizedOverlay(drawable2, this); // Aqui almaceno mi posicion gps
if (this.getIntent().getExtras() != null) /// si he recibido datos del friend en el Bundle
{
updateFriendPosition();
}
if (settings.getBoolean("showMeCheckBox", true))
{
updateMyPosition();
}
locateButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Perform action on clicks
//itemizedoverlay2.getItem(0).
itemizedoverlay.clear();
updateFriendPosition();
itemizedoverlay2.clear();
updateMyPosition();
}
});
traceButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Perform action on clicks
}
});
///////////////////////////////////////////////////////////////////////////////////////////
/// CODIGO PARA QUITAR EL FOCO DEL PRIMER TEXTEDIT Y QUE NO SALGA EL TECLADO DE ANDROID ///
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
///////////////////////////////////////////////////////////////////////////////////////////
//Thread thread = new Thread(this);
//thread.start();
mLooper = new MyLooper();
mLooper.start();
}
private void updateFriendPosition()
{
Bundle bundle = this.getIntent().getExtras();//get the intent & bundle passed by X
userText.setText(bundle.getString("user"));
permissionText.setText(bundle.getString("permission"));
lastUpdateText.setText(bundle.getString("lastupdate"));
String coordinates[] = {bundle.getString("lat"), bundle.getString("lon")};
lat = Double.parseDouble(coordinates[0]);
lng = Double.parseDouble(coordinates[1]);
p = new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6));
OverlayItem overlayitem1 = new OverlayItem(p, bundle.getString("user"), "Hi Friend!");
itemizedoverlay.addOverlay(overlayitem1);
mapOverlays.add(itemizedoverlay);// dibujo la estrella con la posicion actual del friend
mc.animateTo(p); ///nos centra el mapa en la posicion donde esta nuestro amigo
mc.setZoom(10); /// ajusta el zoom a 10
}
public void updateMyPosition()
{
String coordinates[] = {settings.getString("mylatitude", null),settings.getString("mylongitude", null)};
lat = Double.parseDouble(coordinates[0]);
lng = Double.parseDouble(coordinates[1]);
p = new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6));
OverlayItem overlayitem1 = new OverlayItem(p, "Me", "My Position");
itemizedoverlay2.addOverlay(overlayitem1);
mapOverlays.add(itemizedoverlay2);//dibujo mi icono para mostrarme a mi
}
@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
/////metodos del hilo
/*
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Boolean fallo=false;
itemizedoverlay2.clear();
updateMyPosition();
try{ Thread.sleep(1000);}
catch (Exception e)
{
fallo=true;
}
}
};
public void run()
{
Looper.prepare();
handler.sendEmptyMessage(0);
Looper.loop();
}
*/
private class MyLooper extends Thread {
public void run() {
while (mLooper==Thread.currentThread()) {
// Your code here
Boolean fallo=false;
itemizedoverlay2.clear();
updateMyPosition();
try{ Thread.sleep(5000);}
catch (Exception e)
{
fallo=true;
}
}
}
}
}
当我试图解决我的问题以及TOMS和MARVINLABS答案的方法时的例外:
11-18 17:37:43.489: ERROR/AndroidRuntime(729): Uncaught handler: thread main exiting due to uncaught exception
11-18 17:37:43.528: ERROR/AndroidRuntime(729): java.util.ConcurrentModificationException
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:66)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at com.google.android.maps.OverlayBundle.draw(OverlayBundle.java:41)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at com.google.android.maps.MapView.onDraw(MapView.java:471)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.View.draw(View.java:5838)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewGroup.drawChild(ViewGroup.java:1486)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1228)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewGroup.drawChild(ViewGroup.java:1484)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1228)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.View.draw(View.java:5944)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.widget.FrameLayout.draw(FrameLayout.java:352)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewGroup.drawChild(ViewGroup.java:1486)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1228)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.View.draw(View.java:5841)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.widget.FrameLayout.draw(FrameLayout.java:352)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewGroup.drawChild(ViewGroup.java:1486)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1228)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewGroup.drawChild(ViewGroup.java:1484)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1228)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.View.draw(View.java:5841)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.widget.FrameLayout.draw(FrameLayout.java:352)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1847)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewRoot.draw(ViewRoot.java:1217)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewRoot.performTraversals(ViewRoot.java:1030)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.view.ViewRoot.handleMessage(ViewRoot.java:1482)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.os.Handler.dispatchMessage(Handler.java:99)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.os.Looper.loop(Looper.java:123)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at android.app.ActivityThread.main(ActivityThread.java:3948)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at java.lang.reflect.Method.invokeNative(Native Method)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at java.lang.reflect.Method.invoke(Method.java:521)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
11-18 17:37:43.528: ERROR/AndroidRuntime(729): at dalvik.system.NativeStart.main(Native Method)
答案 0 :(得分:1)
您应该为自己的活动创建私有类,而不是让您的活动实现Runnable:
public class Locate extends MapActivity {
// ...
private MyLooper mLooper;
public void onCreate(Bundle savedInstanceState) {
//...
mLooper = new MyLooper(this);
mLooper.start();
}
public void onDestroy() {
// Don't forget to stop the thread here and release the reference
// held by the activity (else you will leak memory)
mLooper = null;
}
private class MyLooper extends Thread {
public void run() {
while (mLooper==Thread.currentThread()) {
// Your code here
}
}
}
}
答案 1 :(得分:1)
为什么要从后台线程触摸UI对象(地图叠加层)?不要这样做,你一定会遇到麻烦。如果你真的必须有一个后台线程,请使用AsyncTask并只触摸onPostExecute()中的UI对象。
但是,通过快速阅读您的代码,我怀疑您根本不需要线程。 UI线程上的一个简单的Handler
有什么问题,你只是postDelayed(5000)
?
编辑添加:
替换此行
private MyLooper mLooper;
有了这个:
private Handler mHandler;
private Runnable updateRunnable = new Runnable() {
@Override public void run() {
itemizedoverlay2.clear();
updateMyPosition();
queueRunnable();
}
};
private void queueRunnable() {
mHandler.postDelayed(updateRunnable, 5000);
}
然后删除这些行:
mLooper = new MyLooper();
mLooper.start();
并将其替换为:
mHandler = new Handler();
queueRunnable();
最后删除你不需要的MyLooper类。
答案 2 :(得分:0)
我使用MarvinLabs方法,但以不同的方式实现while循环:
public class Locate extends MapActivity {
// ...
private MyLooper mLooper;
public void onCreate(Bundle savedInstanceState) {
//...
mLooper = new MyLooper();
mLooper.start();
}
public void onDestroy() {
// Don't forget to stop the thread here and release the reference
// held by the activity (else you will leak memory)
mLooper = null;
}
private class MyLooper extends Thread {
public void run() {
while (true) {
// Your code here
//After executing your code, sleep for 1000ms
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
//Treat the exception
}
}
}
}
}
此外,代替while(true),您可以使用一个变量来提供一个标志来通知while循环何时停止。当停止线程时,这将使事情变得更容易。
这将是以下几点: 修改为使用处理程序
public class Locate extends MapActivity {
// ...
private MyLooper mLooper;
public void onCreate(Bundle savedInstanceState) {
//...
mLooper = new MyLooper(new Handler());
mLooper.start();
//When it's time to stop
mLooper.setKeepRunningFalse();
}
public void onDestroy() {
// Don't forget to stop the thread here and release the reference
// held by the activity (else you will leak memory)
mLooper = null;
}
private class MyLooper extends Thread {
//Your flag
private boolean keepRunning;
private Handler locateHandler;
public MyLooper(Handler locateHandler)
{
this.locateHandler = locateHandler;
}
public void run() {
while (keepRunning) {
//When you want to execute some code that accesses Locate objects do this
locateHandler.post(new Runnable() {
@Override
public void run() {
//Your code here
//This code will be executed by the thread that owns the objects, thus not throwing an exception.
}
});
//After executing your code, sleep for 1000ms
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
//Treat the exception
}
}
}
//Method to change the flag to false
public void setKeepRunningFalse()
{
this.keepRunning = false;
}
}
}
答案 3 :(得分:0)
它正在崩溃,因为您从onClick和计时器调用更新My / Friends位置。你需要在计时器的处理程序上完成它。这是最简单的计时器/处理程序
主要活动有
Thread myRefreshThread = null;
在创建中
this.myRefreshThread = new Thread(new TimerThread());
this.myRefreshThread.start();
有内在的课程
class TimerThread implements Runnable {
// @Override
public void run() {
Message m = new Message();
m.what = YourMainClassName.UNIQUE_IDENTIFIER;
// define this as a constant in your manin class/activity
while (!Thread.currentThread().isInterrupted()) {
// Your processing
// You can put data in a Bundle and send the Bundle
// in the message with m.setData(Bundle b)
YourMainClassName.this.myUpdateHandler.sendMessage(m);
try {
Thread.sleep(1000);// sleeps 1 second
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
和处理程序
Handler myUpdateHandler = new Handler() {
/** Gets called on every message that is received */
// @Override
public void handleMessage(Message msg) {
switch (msg.what) {
case YourMainClassName.UNIQUE_IDENTIFIER:
// get the data out of the bundle
// update the map overlay here and NOWHERE ELSE
break;
}
}