0

「アプリケーションが応答していません」というメッセージが表示されるため、メインの UI スレッドを待機させることは非常に悪い考えであることを理解しています。

しかし、これが私のシナリオです。

私は、サーバーが結果を返すために使用するユーザーの座標を送信している Android アプリケーションからサーバーを呼び出しています。問題は、アプリケーションの最初の実行時に、場所を取得するのに非常に長い時間がかかることです。場所を取得するために GPS と NETWORK プロバイダーの両方を探しています。GPS と NETWORK プロバイダーの両方から場所を取得する前に 20 秒のタイマーを実行します。

これは、ユーザーの場所を見つけるための私のクラスです。

public class MyLocation {
    Timer timer1;
    LocationManager lm;
    LocationResult locationResult;
    boolean gps_enabled=false;
    boolean network_enabled=false;

    public boolean getLocation(Context context, LocationResult result)
    {
        //use LocationResult callback class to pass location value from MyLocation to user code.
        locationResult=result;
        if(lm==null)
            lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

        //exceptions will be thrown if provider is not permitted.
        try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){}
        try{network_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){}

        //don't start listeners if no provider is enabled
        if(!gps_enabled && !network_enabled)
            return false;

        if(gps_enabled)
            lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
        if(network_enabled)
            lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
        timer1=new Timer();
        timer1.schedule(new GetLastLocation(), 20000); 
        return true;
    }

    LocationListener locationListenerGps = new LocationListener() {
        public void onLocationChanged(Location location) {
            timer1.cancel();
            locationResult.gotLocation(location);
            lm.removeUpdates(this);
            lm.removeUpdates(locationListenerNetwork);
        }
        public void onProviderDisabled(String provider) {}
        public void onProviderEnabled(String provider) {}
        public void onStatusChanged(String provider, int status, Bundle extras) {}
    };

    LocationListener locationListenerNetwork = new LocationListener() {
        public void onLocationChanged(Location location) {
            timer1.cancel();
            locationResult.gotLocation(location);
            lm.removeUpdates(this);
            lm.removeUpdates(locationListenerGps);
        }
        public void onProviderDisabled(String provider) {}
        public void onProviderEnabled(String provider) {}
        public void onStatusChanged(String provider, int status, Bundle extras) {}
    };

    class GetLastLocation extends TimerTask {
        @Override
        public void run() {
            lm.removeUpdates(locationListenerGps);
            lm.removeUpdates(locationListenerNetwork);

            Location net_loc=null, gps_loc=null;
            if(gps_enabled)
                gps_loc=lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            if(network_enabled)
                net_loc=lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

            //if there are both values use the latest one
            if(gps_loc!=null && net_loc!=null){
                if(gps_loc.getTime()>net_loc.getTime())
                    locationResult.gotLocation(gps_loc);
                else
                    locationResult.gotLocation(net_loc);
                return;
            }

            if(gps_loc!=null){
                locationResult.gotLocation(gps_loc);
                return;
            }
            if(net_loc!=null){
                locationResult.gotLocation(net_loc);
                return;
            }
            locationResult.gotLocation(null);
        }
    }

    public void cancelTimer() { 
        timer1.cancel();
        lm.removeUpdates(locationListenerGps);
        lm.removeUpdates(locationListenerNetwork); 
    }

    public static abstract class LocationResult{
        public abstract void gotLocation(Location location);
    }
}

そして私のメインアクティビティでは、

onCreate(...)
{
.
.
.
.
myLocation.getLocation(context, locationResult); // my call to the MyLocation class to get the user location

sendRequestToServer(); // calls an AsyncTask which uses the coordinates returned by the MyLocation class

}

getLocation(context, locationResult)はコンテキストを MyLocation クラスに渡し、結果は に格納されますLocationResult callback class

だから、私の主な活動では、私は持っています

LocationResult locationResult = new LocationResult(){
        @Override
        public void gotLocation(Location location){
            if(location != null)
            {
                mUser.setLastKnownLoc(location);
                Log.d("UserLocation", location.getLatitude() + "   "  + location.getLongitude());

            }
        }
    };

そして、サーバーへの私の要求mUser.getLastKnownLoc()は、結果に格納されている場所の値を取得するために使用されます。

私の問題:場所がわかるまでsendRequestToServer()を待機させる

私が試したこと:

  • AsyncTaskのmyLocation.getLocation(..)doInBackground()に入れて onPostExecute() を呼び出しsendRequestToServer()ますが、それでも sendRequestToServer は MyLocation クラスのタイマーが終了するのを待ちません。
  • onCreate 内に別のタイマーを作成mTimer.schedule(RequestToserver,20000)し、sendRequestToServer が 20 秒後にのみ呼び出されるように設定します (MyLocation の他のタイマーが終了するまで)。リクエストが 20 秒後に行われたため、これは少しうまくいったように見えましたが、スレッド処理の問題によりアプリケーションがクラッシュしました。UIThread で timerTask を実行しようとし、Looper.prepare() をアタッチしました。sendRequestToServer()しかし、おそらく独自のバックグラウンド スレッドを持つ AsyncTask を呼び出すという事実が原因で、スレッド処理エラーの悪循環に巻き込まれました。

私はかなり長い間、この仕事を手に入れようとしてきました。20 秒の MyLocation タイマーが切れた後に AsyncTask が呼び出されるようにする必要があります。

あなたの側からの助け/提案は本当に素晴らしいでしょう!!

4

2 に答える 2

1

あなたの onCreate ではProgressDialog、ユーザー入力をブロックする a を表示し、バックグラウンドで getLocation を実行し、場所を取得したら を閉じて、ProgressDialog新しいAsyncTaskデータを送信します。

お気に入り。

ProgressDialog pd = ...;
pd.show();
MyLocation ml = new MyLocation(new LocationResultsCallback(){ 
    public void onLocationRecieved(Location loc){
        //must run on UI thread
        pd.dismiss();
        new SendResultsTask(loc).execute();
    }
});
ml.findLocation(); // start location finding

また、 getLastKnownLocation については、このようなものに切り替える方がよい場合があります。

String bestProvider = locationManager.getBestProvider(new Criteria(), true);
if(bestProvider!=null)
    Location local = locationManager.getLastKnownLocation(bestProvider);

つまり、これが該当する場合、ロケーションプロバイダーにどのような制限があるかわかりません.

また、Timer の代わりに Handler を使用する方が適切ですが、どちらも機能するはずです。

于 2013-03-31T13:38:10.430 に答える