等待线程是否会破坏线程的目的? Android线程问题

时间:2013-07-07 23:30:59

标签: android multithreading concurrency android-asynctask blocking

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

我有一个使用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];
          }
    }
}

希望这说明了我的目标。

谢谢。

3 个答案:

答案 0 :(得分:1)

您可以使用LocationListener。通过这种方式,只要新位置可用,您的代码就会立即运行,并且您不必阻止线程。

了解详情:http://developer.android.com/reference/android/location/LocationListener.html

答案 1 :(得分:1)

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

每次应用程序启动/重新启动时,我都会在自己的后台线程中获取LastLocation()(或者更准确地说,每次应用程序恢复其ui线程时),我会将生成的城市存储在我上面提到的首选项中。由于该方法不会启动天线并且不会耗尽电池,因此我不会经常这样做。

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

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

答案 2 :(得分:1)

线程可以将工作分开,并且大部分时间都是并行运行(异步),它们几乎没有其他原因。在某些情况下,需要一个线程来完成第二个线程处理结果的事情(同步)。

现在,如果您意识到两个线程的工作在100%的时间是顺序的,那么理论上,不需要有两个线程。除非有时人们想要将不同的工作封装在不同的组件中。

对于Android,应用程序以一个线程(UI线程/主线程)开始,该线程用于控制所有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
     */

}

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