为什么这个线程不起作用?

时间:2010-11-18 16:24:04

标签: android multithreading

我有一个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)

4 个答案:

答案 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;
         }
      }
相关问题