1

这是一直困扰我一些关于线程的东西。等待线程是否会破坏线程的目的? Android线程出现问题

我有一个线程使用LocationManager来查找Android设备的当前位置。然后我更新UI以显示该位置。

事实上,我已经建立了一个名为LocationFinder的整个类来获取我的位置。这样我可以说

String yourLocation = (new LocationFinder).getLocation(); 

但是,LocationFinder中的getLocation()方法在单独的线程上运行。所以我不能实说

String yourLocation = (new LocationFinder).getLocation(); 

,因为返回肯定不会是位置,位置需要一秒钟的几部分的直接价值发现。 getLocation()默认返回“notset”,直到内部方法将返回值设置为实际位置。

无论如何,我很困惑如何解决这个问题。我不想阻止,直到找到位置,因为它非常烦人的应用程序锁定几毫秒。我不想使用AsyncTask,因为在调用getLocation()时已经使用,并且我认为嵌套AsyncTasks是错误的。

下面是这个层次的伪代码:

public class MainActivity extends Activity { 

    Button locationButton = new Button(locationButtonClickListener); 
    LocationFinder locationFinder = new LocationFinder(); 

    OnClickListener locationButtonClickListener = new OnClickListener() { 

     locationButton.setText(locationFinder.getLocation()); 
    } 

} 

public class LocationFinder { 

    String city = "notYetSet"; 

    public String getLastLocation() { 
     (new LastKnownLocationFinder).execute(); 
     return city; 
    } 

    public String getGPSLocation() { 
     (new GPSLocationFinder).execute(); 
     return city; 
    } 

    private class LastKnownLocationFinder extends AsyncTask { 

      protected String doInBackground { 
       city = [lots of code to get last known location]; 
      } 
    } 

    private class GPSLocationFinder extends AsyncTask { 

      protected String doInBackground { 
       city = [lots of code to get location using GPS]; 
      } 
    } 
} 

希望这说明了什么,我在获得。

谢谢。

回答

1

线程在那里分工,且大部分时间运行它平行(异步),也几乎没有其他原因他们。在某些情况下,需要一个线程完成第二个线程处理结果(同步)。

现在,如果你意识到的时候两个线程的工作是连续的100%,那么,从理论上说,没有必要有两个线程。除了有时人们会希望将不同的工作封装在不同的组件中。

至于Android,应用程序从一个线程(UI线程/主线程)开始,该线程旨在控制所有的UI元素更改,并且永远不应该被阻止或进入睡眠状态或长时间运行就可以减少用户经历的任何滞后或无反应(这就是你目前所做的)。

在你的情况下,除了一件事情外,一切看起来都是正确的,从我的psuedocode中可以理解的情况来看,getLocation()在被调用时总是会返回“未设置”,因为没有足够的时间让AsyncTask完全执行并更改该值。

您应该建立一个interfaceLocationFinderMainActivity之间进行通信,以发现一旦找到的位置信号,甚至可能只是立即发送该位置。

public class LocationFinder { 

    private CommunicateLocationFinder mCommunicate; 

    public interface CommunicateLocationFinder { 
     void LocationFinderSendGpsLocation(String location); 
    } 

    public LocationFinder (Activity activity){ 
     // This makes sure that the container activity has implemented 
     // the callback interface. If not, it throws an exception 
     try { 
      mCommunicate = (CommunicateLocationFinder) activity; 
     } catch (ClassCastException e) { 
      throw new ClassCastException(activity.toString() 
        + " must implement CommunicateLocationFinder"); 
     } 
    } 

    private class GpsLocationFinder extends AsyncTask { 
     protected String doInBackground { 
      /* 
      * Your work here 
      */ 
     } 

     protected void onPostExecute (String result){ 
      mCommunicate.LocationFinderSendGpsLocation(result); 
     } 
    } 

    /* 
    * Rest of your code 
    */ 
} 

public class MainActivity extends Activity implements 
     LocationFinder.CommunicateLocationFinder { 

    @Override 
    public void LocationFinderSendGpsLocation(String location){ 
     locationButton.setText(location); 
    } 

    /* 
    * Rest of your code 
    */ 

} 

我希望帮助,让我知道,欢呼声。

+0

谢谢,这是非常有帮助!我还没有实现它,但它很有意义,我非常喜欢这种方式。 – andy

+0

我仍然很喜欢这个解决方案,但我很担心的是与我所有最重要的类(这是活动)实现一个接口。我知道接口的存在是出于这个原因,但我觉得如果我可以在LocationFinder类中包含我需要的所有内容,而不需要接口,它会更干净。也许这是不可能的。 – andy

+0

你可以,你只需要发送一个你想要改变到'LocationFinder'的类的引用,然后在那里做修改。当然,如果你发送的是查看参考,请务必使用做'runOnUiThread(..)的变化'如果你正在做的'doInBackground变化()',否则,只是做了改变。 – LuckyMe

1

我将存储在偏好的应用程序使用的最后一个城市的位置。

每次应用程序启动/重新启动时(或者更确切地说,每当应用程序恢复其UI线程时),我都会在它自己的后台线程中获取最后一个位置()以上。由于该方法不能为天线供电,并且不会耗尽电池,所以我不会经常遇到任何问题。

而在回答您的标题中的原始问题,不,“等待一个线程不会破坏使用线程的目的”。在这方面,“等待”一词可能会令人困惑。在此期间,“等待”结果显示并呈现完美工作的用户界面与用户界面线程“等待”结果不同,因为它可以绘制单个像素并冻结UI中的所有内容,直到结果进来。所以从这个意义上说,如果你使用两个不同的异步后台线程,只要它们从初始UI线程分离出来(而不是嵌套)就没有关系。

然后,我将放置在onclicklistener中的唯一代码将是一个异步任务,它显示一个旋转轮的进度,并在后台执行getgpslocation以将值插入到首选项中,并触发内容刷新。