Android 为什么这个线程不';不行?

Android 为什么这个线程不';不行?,android,multithreading,Android,Multithreading,我有一个android应用程序,有一个活动,显示一张地图,还有一个位置。使用服务在SharedReferences上更新此位置。。。好的,很好用 我需要我的活动实现runnable,使之成为一个线程,每1000毫秒读取一次SharedReferences的位置,然后更新地图上的项目位置。。。但它不起作用 正如我在调试模式中看到的,我的线程工作不正常,只输入一次运行()方法。。。我的意思是不再进入RUN()方法,只进入一次,因为这样,地图上的位置不会更新 怎么了?为什么这根线不好用 公共类定位扩展

我有一个android应用程序,有一个活动,显示一张地图,还有一个位置。使用服务在SharedReferences上更新此位置。。。好的,很好用

我需要我的活动实现runnable,使之成为一个线程,每1000毫秒读取一次SharedReferences的位置,然后更新地图上的项目位置。。。但它不起作用

正如我在调试模式中看到的,我的线程工作不正常,只输入一次运行()方法。。。我的意思是不再进入RUN()方法,只进入一次,因为这样,地图上的位置不会更新

怎么了?为什么这根线不好用

公共类定位扩展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;         
            }
        }
    }


}

与其让活动实现可运行,不如为活动创建一个私有类:

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
            }
        }
    }
}

我会使用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;
            }
    }


}

为什么要从后台线程触摸UI对象(映射覆盖)?否则,您肯定会遇到麻烦。如果确实必须有后台线程,请使用AsyncTask并仅从onPostExecute()触摸UI对象

但是,通过快速阅读您的代码,我怀疑您根本不需要线程。您只需将
postDelayed(5000)
添加到UI线程上的简单
Handler
有什么问题

编辑以添加:

更换这条线

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类。

它会崩溃,因为您正在从onClick和计时器调用更新我的/朋友位置。您只需要在计时器的处理程序上执行此操作。下面是最简单的计时器/处理程序

主要活动有

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;
         }
      }


我在这里得到一个错误:mLooper=newmylooper(this);error:构造函数Locate.MyLooper(Locate)是未定义的而且,如果查找implementews Runnable,我必须实现run…你确定你的代码正常吗?我修复你的代码,删除第一行的implements Runnable,并从新的Mylooper行中删除它…并且不工作…相同的OCURR,线程只运行一次方法,你的活动没有实现如果您想向MyLooper传递一个上下文或一个活动(代码已更正),您还需要为它定义一个构造函数.wich是我需要的处理程序吗?Android.os?还是java.util?嗨,伙计,这种方式,就像MarvinLabs的方式,给我一个异常并使我的应用程序崩溃,你有第一个问题的logcat,阅读它。你有没有试着把整个onCreate和run方法放在try-catch块中?只是为了看看是否捕获了异常以及它是什么类型的异常例外是关于第一个问题,请仔细阅读。当我移动地图或缩放地图时,它会出现,这只会发生在这种线程上…之前我在谷歌上读到的meAs不会发生:这个例外可能是由检测到对象并发修改的方法引发的,而这种修改是不允许的。我把5000毫秒的睡眠时间,它似乎可以工作10秒或15秒,但随后再次崩溃…你能给我一个代码示例,说明如何在没有线程的情况下完成此操作吗?我仍然可以按Buton键并与此ui进行交互?而且我正在检索信息以从SharedReferences更新我的地图,但我正在更新此ui上的地图,而不是其他ui和al上的地图所以这个用户界面有另外一个按钮和其他功能是的。我要抓紧时间10分钟,但当我回来时,我会用代码更新我的答案。它可以工作!!!!!不会让我崩溃!!!!!谢谢伙计!!!!!哇,但是现在我有另一个问题,当我移动或缩放地图时,这些项目的新位置只能在地图上重新绘制:这就是我如何做到的lve it?P.S.可以通过首选项将数据从服务传递到应用程序,但这不是最好的方式。如果是远程服务,则可以通过aidl和远程接口发送。如果是本地服务,则可能可以以更简单的方式进行传递,但我只使用了远程服务,因此不确定如何从不使用onclick,因为我从未按过b乌顿,那它就不是坠机的原因了。。。
 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;
         }
      }