安卓地点自动完成碎片:无法设置文本。

7

谷歌最近更新了他们的 Android Places SDK,因此我也在更新我的代码。我尝试使用 AutocompleteSupportFragment 来允许用户设置他们的地址。

这是我的代码:

mAddressEditText = (AutocompleteSupportFragment) getSupportFragmentManager().findFragmentById(R.id.address);
mAddressEditText.setPlaceFields(Arrays.asList(Place.Field.ADDRESS, Place.Field.LAT_LNG));
mAddressEditText.setHint("Address");
mAddressEditText.setText("Test1");                      // Works fine at the beginning, disappears after selecting a place and shows only the hint
mAddressEditText.setOnPlaceSelectedListener(new PlaceSelectionListener() {
    @Override
    public void onPlaceSelected(Place place) {
        Log.d(TAG, "Place Selected");
        // Other Stuff
        mAddressEditText.setText("Test2");              // Doesn't Work, all I can see is the hint
        mAddressEditText.setText(place.getAddress());   // Doesn't Work, all I can see is the hint
    }

    @Override
    public void onError(Status status) {
        Log.e(TAG, "An error occurred: " + status);
        invalidAddressDialog.show();
    }
});

在之前的SDK中,片段会自动将文本设置为所选地址。但在新的SDK中,这种方法不起作用(不确定是否是有意为之)。因此,我正在尝试手动设置它。正如您在我的代码注释中看到的那样,在侦听器外部使用setText可以正常工作,而在侦听器内部则不能正常工作。
我做错了什么还是这是一个错误?
编辑: 这么长时间过去了,我仍然无法得到一个合适的解决方法。 要完全清楚,我可以从片段中正确获取地址,唯一不能正常工作的是setText。
然而,由于一些答案指出他们没有遇到同样的问题,我开始思考可能与我正在使用的库版本有关?
这些是我在build.gradle中拥有的库:
api 'com.android.support:appcompat-v7:28.0.0'
api 'com.android.support:support-annotations:28.0.0'

api 'com.android.support:multidex:1.0.3'

api 'com.google.firebase:firebase-core:16.0.8'
api 'com.google.firebase:firebase-auth:16.2.1'
api 'com.google.firebase:firebase-firestore:18.2.0'
api 'com.google.firebase:firebase-storage:16.1.0'
api 'com.google.android.libraries.places:places:1.1.0'

我最近实现了它,对我来说运行得很好。 - Kwnstantinos Nikoloutsos
10个回答

8

setText一直给我带来同样的问题-我认为这一定是一个bug。然而,我发现了一个使用提示的小技巧。在您的onPlaceSelected中,可以添加以下内容:

Java

EditText etPlace = (EditText) autocompleteFragment.getView().findViewById(R.id.places_autocomplete_search_input);
etPlace.setHint(place.getAddress())

Kotlin

val etPlace = autocompleteFragment.view?.findViewById(R.id.places_autocomplete_search_input) as EditText
etPlace.hint = place.address

这是目前我解决问题的方法,但我不能将其作为最终解决方案,特别是因为我无法设置提示颜色,它看起来与我拥有的所有其他组件在视觉上都不同。 - mewais
但是 setHint()onPlaceSelected() 内部运作得非常好。问题在于 setText() 并不行。它实际上会将文本设置到字段中,有时你可以看到它持续几秒钟,然后字段又变为空白了。 - Victor K.

4

这是我正在使用的代码,它运行得非常好。

对build.gradle(应用程序级别)进行一些更改

在build.gradle中添加以下内容:

android{
   ...
   ext {
        googlePlayServicesVersion = "15.0.1"
   }
}

添加这些依赖项:
dependencies {
    ...
    //Also if you're using any firebase dependencies make sure that the are up to date
    implementation 'com.google.android.gms:play-services-places:16.0.0'
    implementation 'com.google.android.libraries.places:places:1.1.0'
}
apply plugin: 'com.google.gms.google-services'

在xml布局中:
<fragment
                android:id="@+id/autocomplete_fragment"
                android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

Activity中的代码:

private void initGooglePlacesApi() {
        // Initialize Places.
        Places.initialize(getApplicationContext(), "YOUR_API_KEY");
        // Create a new Places client instance.
        PlacesClient placesClient = Places.createClient(getApplicationContext());

        // Initialize the AutocompleteSupportFragment.
        AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment)
                getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment);

        autocompleteFragment.setHint(getString(R.string.select_location_search_bar));
//        autocompleteFragment.setLocationRestriction(RectangularBounds.newInstance(
//                new LatLng(34.7006096, 19.2477876),
//                new LatLng(41.7488862, 29.7296986))); //Greece bounds
        autocompleteFragment.setCountry("gr");


        // Specify the types of place data to return.
        autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ADDRESS, Place.Field.ADDRESS_COMPONENTS));
        autocompleteFragment.setTypeFilter(TypeFilter.ADDRESS);


        // Set up a PlaceSelectionListener to handle the response.
        autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
            @Override
            public void onPlaceSelected(Place place) {
                if(place.getAddressComponents().asList().get(0).getTypes().get(0).equalsIgnoreCase("route")){
                    binding.textViewLocation.setText(place.getAddress()); //Works well
                    location = place.getAddress();

                }else{ //If user does not choose a specific place.
                    AndroidUtils.vibratePhone(getApplication(), 200);
                    TastyToast.makeText(getApplicationContext(),
                            getString(R.string.choose_an_address), TastyToast.DEFAULT, TastyToast.CONFUSING);
                }

                Log.i(TAG, "Place: " + place.getAddressComponents().asList().get(0).getTypes().get(0) + ", " + place.getId() + ", " + place.getAddress());
            }

            @Override
            public void onError(Status status) {
                Log.i(TAG, "An error occurred: " + status);
            }
        });
    }

这几乎和我做的一样,唯一的区别是onPlaceSelected内部的if语句和绑定。那个绑定是什么?我尝试修改我的代码来使用那个if语句(我不知道它怎么帮助,但我还是试了),但它仍然无法工作。 - mewais
我刚刚发布了我在build.gradle中使用的库,也许这可能是问题的原因?你能否发布你的库? - mewais
1
我从我的一个项目中复制并粘贴了这段代码。因此,这个绑定对象是使用数据绑定创建的(如果您不知道,请查看一下)。 事实上,起初我遇到了一些依赖问题,但现在它们似乎运行得非常好。我已经更新了我的答案。如果有帮助,请告诉我! - Kwnstantinos Nikoloutsos
但是为什么你要使用 com.google.android.gms:play-services-places:16.0.0?那不是用于旧的 API 吗? - mewais
我不是很确定,但它与这些依赖项一起工作! - Kwnstantinos Nikoloutsos

1
通过在setPlaceFields中设置“名称”,所选地址将自动显示在片段中:
AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment)
    getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment);


// Set "Place.Field.NAME" as below here to show the selected item //
autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ID, **Place.Field.NAME**,Place.Field.ADDRESS,Place.Field.LAT_LNG));


autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
    @Override
    public void onPlaceSelected(@NonNull Place place) {
        // TODO: Get info about the selected place. }
 
    @Override
    public void onError(@NonNull Status status) {
        // TODO: Handle the error. }
});

1
我找到了一个相当简单的解决方案,只需稍微延迟在EditText中设置文本的时刻即可。因此,在您的PlaceSelectionListener中,请按照以下方式执行:
Handler().postDelayed({
    mAddressEditText.setText(place.getAddress());
}, 300)

PS:这是Kotlin代码,但在Java中几乎相似


虽然这可能解决问题,但它并不是一个好的解决方案(暂停主线程以希望影响UI更新,似乎很hacky)。https://dev59.com/krHma4cB1Zd3GeqPNpII#55611886 是正确的解决方案。 - barnacle.m
@barnacle.m 感谢你的评论,我不知道 Handler 在阻塞主线程,很高兴你评论了我的答案! - Matthias

0

编辑:这是我的更新答案

# When you are using AutocompleteSupportFragment or AutocompleteActivity
# in Fragments, do this:
public class YourFragment extends Fragment {
/.../
@Override
public void onActivityResult (int requestCode,int resultCode,
 @Nullable Intent data){
 # AUTOCOMPLETE_REQUEST_CODE is just a unique constant, define it
 if (requestCode == AUTOCOMPLETE_REQUEST_CODE) {
   if (resultCode == AutocompleteActivity.RESULT_OK) {
    Place place = Autocomplete.getPlaceFromIntent(data);
    // when resultcode is RESULT_OK
    mAddressEditText.setText(place.getName());
    // Notice this line, update your editText up here
    }else if (resultCode == AutocompleteActivity.RESULT_ERROR) {
    Status status = Autocomplete.getStatusFromIntent(data);
    // Handle error
    } else if (resultCode == AutocompleteActivity.RESULT_CANCELED) {
    // Handle results if canceled
    }
  super.onActivityResult(requestCode, resultCode, data);
 }
}
/.../
}
# If you are extending AppCompatActivity, you might want to do this
# ONLY when you are already doing something in onActivityResult
public class YourActivity extends AppCompatActivity{
/.../
@Override
public void onActivityResult (int requestCode,int resultCode,@Nullable Intent data){
 # your logic here.
 /.../ 
  # if you are already overriding onActivityResult, 
  # do not forget to put this line
  super.onActivityResult(requestCode, resultCode, data);
 }
/.../
}

我也遇到了这个问题。事实证明,无论是使用AutocompleteSupportFragment还是AutocompleteActivity,如果你正在使用Fragments,你都必须覆盖并实现它。

如果你正在使用AppCompatActivity,你不需要实现它,但如果你已经重写了onActivityResult来做一些事情,请不要忘记调用基本方法super.onActivityResult


抱歉,我有点困惑,您的意思是即使我使用地点自动完成片段而不是启动地点自动完成活动,我也应该覆盖onActivityResult吗?! - mewais
如果您正在扩展Fragments而不是AppCompatActivity,则需要覆盖onActivityResult并确保将代码放在其上方。我在使用导航组件的Fragments时遇到了同样的问题,但在覆盖onActivityResult后,我能够设置我的edittext。同时,如果您在Activity中进行工作,这自然意味着您正在使用AppCompatActivity,则除非您已经在其中执行某些操作,否则无需执行任何操作。我将更新我的答案以提供更多信息。 - dogNoob
你有看过 Google Place 的示例吗?它可能会对你有所帮助。https://github.com/googlemaps/android-places-demos - dogNoob

0

我相信这是一个 bug,因为它不能像这样工作是没有意义的。 能够工作的是设置其他自动完成文本而不是它自己的文本。 这一定是一个 bug。


0

0
Matthias的解决方案可行,但它是用Kotlin编写的。下面是Java中相同的实现。
 @Override
 public void onPlaceSelected(Place place) {


                        String name =  place.getName()+", "+place.getAddress();
                      
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                autocompleteFragmentDestination.setText(name);
                            }
                        },300);

                    }

0

我尝试了CacheMeOutside的解决方案,但它根本不起作用。所以,我决定尝试Matthias的解决方案,它确实有效,因为文本实际上会设置然后立即删除,出于某种原因。一个小延迟可以修复它。延迟可以尽可能小,只需1毫秒。

如果我的解决方案对您不起作用,您可以尝试调整延迟时间。它似乎也不会停止视图渲染,因此您可以设置任何时间。

private lateinit var autocomplete: AutocompleteSupportFragment

        override fun onPlaceSelected(place: Place) {
            Timer("SetAddress", false).schedule(1) {
                autocomplete.setText(place.address)
            }
        }

这是一个Kotlin代码片段。如果你的代码是Java,只需找到一些延迟代码执行的工具。


0
简单。使用Spannable字符串设置颜色!
    val autocompleteFragment = childFragmentManager.findFragmentById(R.id.location_filter_autocomplete) as AutocompleteSupportFragment
    val text = SpannableString("Enter a location")
    text.setSpan(ForegroundColorSpan(Color.BLACK), 0, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    autocompleteFragment.setHint(text)

在 onPlaceSelectedListener() 内部执行相同的操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接