1

这一直让我对线程感到有些困惑。

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

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

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

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

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

因为返回的立即值肯定不是位置,因为位置需要几分之一秒才能找到。getLocation() 默认返回“notset”,直到内部方法将返回值设置为实际位置。

无论如何,我对如何处理这个问题感到困惑。在找到位置之前我不想阻止,因为应用程序锁定那几毫秒是非常烦人的。我不想使用 AsyncTask,因为在我调用 getLocation() 时已经使用了它,而且我觉得嵌套 AsyncTask 是错误的。

这是此层次结构的伪代码:

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

希望这能说明我的意思。

谢谢你。

4

3 回答 3

1

您可以使用 LocationListener。这样,您的代码将在新位置可用时立即运行,而您不必阻塞线程。

阅读更多:http: //developer.android.com/reference/android/location/LocationListener.html

于 2013-07-08T00:17:53.860 回答
1

我会将应用程序使用的最后一个城市位置存储在首选项中。

每次应用程序启动/重新启动时(或者更准确地说,每次应用程序恢复其 ui 线程时)我都会在它自己的后台线程中 getLastLocation(),并且我会将生成的城市存储在我上面提到的首选项中。由于这种方法不会给天线加电,也不会耗尽电池,所以我经常这样做不会有任何问题。

在回答您标题中的原始问题时,不,“等待线程不会破坏使用线程的目的”。在这种情况下,术语“等待”可能会令人困惑。“等待”结果显示并同时渲染完美工作的 UI 与 UI 线程“等待”结果在它可以绘制单个像素并将所有内容从 UI 中冻结直到该结果出现之前是不同的进来。所以从这个意义上说,如果您使用两个不同的异步后台线程并不重要,只要它们是从初始 UI 线程分叉出来的(而不是嵌套的)。

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

于 2013-07-08T00:19:38.953 回答
1

线程用于划分工作并且大部分时间并行运行(异步),几乎没有其他原因。在某些情况下,需要一个线程来完成某些事情,而第二个线程来处理结果(同步)。

现在,如果您知道 100% 的时间两个线程的工作都是顺序的,那么理论上,没有必要有两个线程。除了有时人们希望将不同的工作封装在不同的组件中。

对于 Android,应用程序从一个线程(UI-thread / Main-thread)开始,该线程旨在控制所有 UI 元素的更改,并且永远不应被阻塞或休眠或长时间操作对其生效,并且那是为了减少用户经历的任何滞后或反应迟钝(这就是你目前正在做的事情)。

在您的情况下,一切似乎都做对了,除了一件事,根据我在您的伪代码中的理解,在调用时getLocation()将始终返回“notset”,因为没有足够的时间让 AsyncTask 完全执行并更改值.

您应该建立一个在和interface之间进行通信,一旦找到就发送位置信号,甚至可能只是立即发送位置。LocationFinderMainActivity

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
     */

}

希望对你有帮助,让我知道,干杯。

于 2013-07-08T00:22:31.053 回答