【问题标题】:Location is empty at the start位置一开始是空的
【发布时间】:2019-12-18 06:12:35
【问题描述】:

我正在重新构建我的最后一个问题,这个问题没有得到解答,我已经在Google's BasicLocation 之后重写了这个问题。

我的主要活动定义为:

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {
//    private LocationCallback locationCallback;
//     private FusedLocationProviderClient mFusedLocationClient;
    private FusedLocationProviderClient mFusedLocationClient;
    protected Location mLastLocation;
    private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
    private static final String TAG = MainActivity.class.getSimpleName();



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.drawer_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
        ViewPager viewPager = findViewById(R.id.view_pager);
        viewPager.setAdapter(sectionsPagerAdapter);
        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();
        navigationView.setNavigationItemSelectedListener(this);

        ImageButton leftNav = findViewById(R.id.left_nav);
        ImageButton rightNav = findViewById(R.id.right_nav);
        leftNav.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int tab = viewPager.getCurrentItem();
                if (tab > 0) {
                    tab--;
                    viewPager.setCurrentItem(tab);
                } else if (tab == 0) {
                    viewPager.setCurrentItem(tab);
                }
            }
        });

        rightNav.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int tab = viewPager.getCurrentItem();
                tab++;
                viewPager.setCurrentItem(tab);
            }
        });

    }
    @Override
    public void onStart() {
        super.onStart();
        if (!checkPermissions()) {
            requestPermissions();
        } else {
            getLastLocation();
        }
    }

with latlang.[Lat,Lang] 在一个单独的文件中:

public class latlang {
    public static double Lat;
    public static double Lang;
}

定位文件,也就是viewpager中的第一个片段被定义为:

public class SunFragment extends Fragment {

    List<SunSession> sunsList;
    Typeface sunfont;


    //to be called by the MainActivity
    public SunFragment() {
        // Required empty public constructor
    }

    // Keys for storing activity state.
//  private static final String KEY_CAMERA_POSITION = "camera_position";
    private static final String KEY_LOCATION_NAME = "location_name";
    public String location;//="No location name found";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Retrieve location and camera position from saved instance state.
        if (savedInstanceState != null) {
            location = savedInstanceState.getCharSequence(KEY_LOCATION_NAME).toString();
            System.out.println("OnCreate location  "+location);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_sun, container, false);
        onSaveInstanceState(new Bundle());
        //SecondFragment secondFragment = new SecondFragment();
        //secondFragment.getDeviceLocation();

        RecyclerView rv = rootView.findViewById(R.id.rv_recycler_view);
        rv.setNestedScrollingEnabled(false);
        rv.setHasFixedSize(true);
        //MyAdapter adapter = new MyAdapter(new String[]{"Today", "Golden Hour", "Blue Hour", "Civil Twilight", "Nautical Twilight", "Astronomical Twilight", "Hello", "World"});
        //rv.setAdapter(adapter);
        LinearLayoutManager llm = new LinearLayoutManager(getActivity());
        rv.setLayoutManager(llm);
        System.out.println("location  "+location);



   /*
     Reversegeocoding location
     */
        String location="No location name found";
        String errorMessage = "";
        List<Address> addresses = null;

        Geocoder geocoder = new Geocoder(getContext(), Locale.getDefault());
        try {
            addresses = geocoder.getFromLocation(
                    latlang.Lat,
                    latlang.Lang,
                    1);
        } catch (IOException ioException) {
            // Catch network or other I/O problems.
            errorMessage = getString(R.string.service_not_available);
            // Log.e(TAG, errorMessage, ioException);
            if (getView() != null){
                Snackbar.make(getView(), errorMessage, Snackbar.LENGTH_LONG).show();
            }
        } catch (IllegalArgumentException illegalArgumentException) {
            // Catch invalid latitude or longitude values.
            errorMessage = getString(R.string.invalid_lat_long_used);
            if (getView() != null){
                Snackbar.make(getView(),
                        "Illegal Latitude = " + latlang.Lat + ", Longitude = " +
                                latlang.Lang, Snackbar.LENGTH_LONG).show();
            }
        }
        if (addresses == null || addresses.size() == 0) {
            if (errorMessage.isEmpty()) {
                System.out.println("Adress Empty No Address Found");// Snackbar.LENGTH_LONG).show();
                location = "Lat:"+latlang.Lat+" Lang: "+latlang.Lang;
            }
        } else {
            location = addresses.get(0).getAddressLine(0);//+", "+ addresses.get(0).getLocality();
        /* for(int i = 0; i <= addresses.get(0).getMaxAddressLineIndex(); i++) {
          location = addresses.get(0).getAddressLine(i);
        }*/
        }

logcat 可以看出这个问题:

I/System.out: location  null
 I/Google Maps Android API: Google Play services package version: 17785022
 I/Choreographer: Skipped 31 frames!  The application may be doing too much work on its main thread.
 I/System.out: Position:0
 I/System.out: Position:1
 I/System.out: Position:2
 I/zygote: Do full code cache collection, code=202KB, data=177KB
 I/zygote: After code cache collection, code=129KB, data=91KB
 I/zygote: JIT allocated 56KB for compiled code of void android.view.View.<init>(android.content.Context, android.util.AttributeSet, int, int)
 I/zygote: Background concurrent copying GC freed 44415(2MB) AllocSpace objects, 7(136KB) LOS objects, 49% free, 3MB/6MB, paused 294us total 102.458ms
 I/System.out: Position:3
 I/System.out: Position:4
 I/zygote: Do partial code cache collection, code=193KB, data=126KB
 I/zygote: After code cache collection, code=193KB, data=126KB
 I/zygote: Increasing code cache capacity to 1024KB
 I/zygote: JIT allocated 71KB for compiled code of void android.widget.TextView.<init>(android.content.Context, android.util.AttributeSet, int, int)
 I/zygote: Compiler allocated 4MB to compile void android.widget.TextView.<init>(android.content.Context, android.util.AttributeSet, int, int)
 E/MainActivity: Latit: 37.42342342342342

这表明,在开始时,位置为空,

I/System.out:位置为空

然后创建sunfragment的recyclerview

 I/System.out: Position:0
 I/System.out: Position:1
 I/System.out: Position:2

然后我得到了位置:

E/MainActivity: Latit: 37.42342342342342

完整代码链接:https://drive.google.com/file/d/1pMl_3Lf76sy82C0J4b-9ta4jbSHonJ2y/view?usp=sharing

在创建sunfragmentoncreateview 之前,是否可以先获取位置?

【问题讨论】:

  • 你需要延迟片段的创建直到mLastLocationgetLastLocation初始化。或者在mLastLocation初始化后更新片段。
  • 你的意思是像onsuccesslistner这样的东西吗?我对java很陌生,所以你能帮忙多一点吗?
  • 没有完全使用监听器。您只需要添加一个方法来通知 Fragment 有关位置更改的信息。你如何创建片段?是通过你的SectionsPagerAdapter吗?
  • 是的。基本上,我是在android studio->new project->tabbed activity中创建的,只是用sunFragment替换了sectionpageradapter的placeholderFragment。
  • 您好,如果有人感兴趣,我准备上传完整的代码。但是,请帮我解决这个问题。

标签: android android-location


【解决方案1】:

我发现你的代码有问题(我可能错了):

  1. 为什么latlang 的字段是static?看起来他们不应该这样做。

  2. SunFragment.onCreate(),如果savedInstanceState != null,您正在阅读locationsavedInstanceState 仅当持有此片段的活动从已保存状态恢复时才为空。它可能根本不会发生。

  3. 您应该使用片段的arguments (Bundle) 将初始数据传递给片段

  4. 您应该为latlang 实现Parcelable 接口,以便能够通过Bundle 传递自定义类

我认为这还不是全部,但对我来说,这似乎足以让这段代码无法按您的预期工作

【讨论】:

    【解决方案2】:

    如上一个答案所述,您的代码中有很多问题。

    除此之外,了解最后一个已知位置可能并不总是返回一个值。 Gps基本上有两种数据类型:Ephemeris(精确导航数据)和Almanac(粗略数据)。现在当接收器冷启动时,即gps关闭超过8-10分钟后,基本上没有最后一个已知位置(持续时间可能因设备而异,但基本思路是这样的)。

    因此,当您没有获得最后一个已知位置时,请使用融合客户端获取实际的实时位置。此外,由于您将数据保存在共享首选项中并在您的片段中获取它,我相信您的片段将严重依赖这些数据。所以我会建议以下两种方法中的任何一种来获得正确的结果

    1) 根本不获取嵌套活动中的位置。只需在需要的片段中执行即可。如果您的 viewpager 中的其他片段也需要该位置,这将不起作用。

    2) 如果您的活动中必须有位置并且它是容器片段中的依赖项,您也可以在此处使用两种方法。我的方法依赖于事件总线。事件总线、otto 或 rxbus 什么都可以

    2a) 不要向 viewpager 添加任何内容。基本上首先完全获取位置,然后在获得位置回调后将内容添加到视图页面。

    2b) 从一开始就向 viewpager 添加内容。在Activity中一旦你获得了位置,就使用事件总线来通知相同的Fragment,并在Fragment中获得事件后,真正开始你需要做的事情。

    我以前使用过这两种方法并且一切正常。现在,使用适合您的完全取决于您的用例。无论哪种方式,代码都太长而且太复杂,无法在此处发布所有内容。

    【讨论】:

      【解决方案3】:

      现在你是这样使用的:

      @Override
      public void onStart() {
          super.onStart();
          if (!checkPermissions()) {
              requestPermissions();
          } else {
              getLastLocation();
          }
      }
      

      在您的else 语句中检查getLastLocation() 是否不为空。如果不为空,则替换片段。

      @Override
      public void onStart() {
          super.onStart();
          if (!checkPermissions()) {
              requestPermissions();
          } else {
              if(getLastLocation() != null){
                 //replace your fragment
              }else{//Null Location}
          }
      }
      

      【讨论】:

        【解决方案4】:

        使用服务类来精确处理位置服务。在这里,我给你一个自定义的 LocationService 类,我在许多项目中使用它来不断地从后台收集位置数据

        LocationService.kt

        import android.Manifest
        import android.app.NotificationChannel
        import android.app.NotificationManager
        import android.app.Service
        import android.content.Context
        import android.content.Intent
        import android.content.pm.PackageManager
        import android.os.Binder
        import android.os.Build
        import android.os.IBinder
        import android.os.Looper
        import android.util.Log
        import androidx.core.app.ActivityCompat
        import androidx.core.app.NotificationCompat
        
        import com.google.android.gms.location.FusedLocationProviderClient
        import com.google.android.gms.location.LocationCallback
        import com.google.android.gms.location.LocationRequest
        import com.google.android.gms.location.LocationResult
        import com.google.android.gms.location.LocationServices
        
        
        class LocationService : Service() {
        
            //Custom Location Binder class
            inner class LocationBinder : Binder() {
                val locationService: LocationService
                    get() = this@LocationService
            }
        
            companion object {
                val TAG = "LocationService_123"
                private val UPDATE_INTERVAL = (4 * 1000).toLong()  /* 4 secs */
                private val FASTEST_INTERVAL: Long = 2000 /* 2 sec */
        
                private var INSTANCE: LocationService? = null
                fun isInstanceCreated(): Boolean {
                    return (INSTANCE != null)
                }
            }
        
        
            private var mFusedLocationClient: FusedLocationProviderClient? = null
            private var mLocationListener: LocationListener? = null
            private var mLocationBinder = LocationBinder()
        
            fun setLocationListener(locationListener: LocationListener) {
                this.mLocationListener = locationListener
            }
        
            override fun onBind(intent: Intent): IBinder? {
                return mLocationBinder
            }
        
            override fun onCreate() {
                INSTANCE = this
                super.onCreate()
        
                mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
        
                if (Build.VERSION.SDK_INT >= 26) {
                    val CHANNEL_ID = "ostad_gps"
                    val channel = NotificationChannel(
                            CHANNEL_ID,
                            "Ostad GPS",
                            NotificationManager.IMPORTANCE_DEFAULT)
        
                    (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel)
        
                    val notification = NotificationCompat.Builder(this, CHANNEL_ID)
                            .setContentTitle("")
                            .setContentText("").build()
        
                    startForeground(1, notification)
                }
            }
        
            override fun onDestroy() {
                INSTANCE = null
                super.onDestroy()
            }
        
            override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
                Log.d(TAG, "onStartCommand: called.")
                getLocation()
                return Service.START_NOT_STICKY
            }
        
            private fun getLocation() {
        
                // ---------------------------------- LocationRequest ------------------------------------
                // Create the location request to start receiving updates
                val mLocationRequestHighAccuracy = LocationRequest()
                mLocationRequestHighAccuracy.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
                mLocationRequestHighAccuracy.interval = UPDATE_INTERVAL
                mLocationRequestHighAccuracy.fastestInterval = FASTEST_INTERVAL
        
        
                // new Google API SDK v11 uses getFusedLocationProviderClient(this)
                if (ActivityCompat.checkSelfPermission(
                                this,
                                Manifest.permission.ACCESS_FINE_LOCATION
                        ) != PackageManager.PERMISSION_GRANTED
                ) {
                    Log.d(TAG, "getLocation: stopping the location mitchService.")
                    stopSelf()
                    return
                }
                Log.d(TAG, "getLocation: getting location information.")
                mFusedLocationClient!!.requestLocationUpdates(
                        mLocationRequestHighAccuracy, object : LocationCallback() {
                    override fun onLocationResult(locationResult: LocationResult?) {
        
                        val location = locationResult!!.lastLocation
        
                        Log.d(TAG, "onLocationResult: got location result: $location")
        
                        if (location != null) {
                            if (mLocationListener != null)
                                mLocationListener!!.onLocationChanged(location)
                        }
        
                    }
                },
                        Looper.myLooper()
                ) // Looper.myLooper tells this to repeat forever until thread is destroyed
            }
        
        }
        

        将此添加到您的 AndroidManifest 文件中并从您的 MainActivity 启动 LocationService。

        【讨论】:

          【解决方案5】:

          通过查看代码,您似乎不需要非常准确的位置,您可以使用最后一个已知位置。在某些情况下,此值可能为 null,就像您已经经历过的那样。对您的问题的简单回答是否定的,在创建 SunFragment 之前您不能获得非空位置。以下步骤是在后台加载位置并在找到后更新 UI。

          1. 请求 MainActivity 中的最后一个已知位置
          2. 在缓存中保留最后位置的引用,以便于加载和更好的用户 体验
          3. 如果最后一个位置为空,请求位置更新,直到你得到一个好的修复
          4. SunFragment 中有一个监听器来跟踪位置更新

          这是您需要的一些代码(请务必阅读)

          使用LocationUtil 处理与位置相关的事件(我更喜欢LocationManager 而不是FusedLocationProviderClient);

              public class LocationUtil {
          
              public static void updateLastKnownLocation(Context context) {
          
                  LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
          
                  if(hasSelfPermission(context, new String[]{
                          Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION})) {
          
                      try {
          
                          Location currentBestLocation;
          
                          Location gpsLocation = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                          Location lbsLocation = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
          
                          if(isBetterLocation(lbsLocation, gpsLocation)) {
                              currentBestLocation = lbsLocation;
                          } else {
                              currentBestLocation = gpsLocation;
                          }
          
                          if(currentBestLocation == null) {
                              requestLocationUpdates(lm);
                          } else {
                              updateCacheLocation(currentBestLocation);
                          }
          
                      } catch (SecurityException se) {
                          // unlikely as permission checks
                          se.printStackTrace();
                      } catch (Exception e) {
                          // unexpected
                          e.printStackTrace();
                      }
                  }
              }
          
              private static void updateCacheLocation(Location location) {
          
                  if(location == null) return;
          
                  LocationLite temp = new LocationLite();
                  temp.lat = location.getLatitude();
                  temp.lon = location.getLongitude();
          
                  Gson gson = new Gson();
                  String locationString = gson.toJson(temp);
          
                  AppCache.setLastLocation(locationString);
              }
          
              @SuppressLint("MissingPermission")
              private static void requestLocationUpdates(LocationManager lm) {
          
                  try {
          
                      lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0.0F, new LocationListener() {
          
                          @Override
                          public void onLocationChanged(Location location) {
                              updateCacheLocation(location);
                              lm.removeUpdates(this);
                          }
          
                          @Override
                          public void onStatusChanged(String s, int i, Bundle bundle) {
                              // doing nothing
                          }
          
                          @Override
                          public void onProviderEnabled(String s) {
                              // doing nothing
                          }
          
                          @Override
                          public void onProviderDisabled(String s) {
                              // doing nothing
                          }
                      });
                  }catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          
              private static boolean isBetterLocation(Location location, Location currentBestLocation) {
          
                  int TWO_MINUTES  = 1000 * 60 * 2;
          
                  if (currentBestLocation == null) {
                      // A new location is always better than no location
                      return true;
                  }
          
                  if (location == null) {
                      // A new location is always better than no location
                      return false;
                  }
          
                  // Check whether the new location fix is newer or older
                  long timeDelta = location.getTime() - currentBestLocation.getTime();
                  boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
                  boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
                  boolean isNewer = timeDelta > 0;
          
                  // If it's been more than two minutes since the current location, use the new location
                  // because the user has likely moved
                  if (isSignificantlyNewer) {
                      return true;
                      // If the new location is more than two minutes older, it must be worse
                  } else if (isSignificantlyOlder) {
                      return false;
                  }
          
                  // Check whether the new location fix is more or less accurate
                  int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
                  boolean isLessAccurate = accuracyDelta > 0;
                  boolean isMoreAccurate = accuracyDelta < 0;
                  boolean isSignificantlyLessAccurate = accuracyDelta > 200;
          
                  // Check if the old and new location are from the same provider
                  boolean isFromSameProvider = isSameProvider(location.getProvider(), currentBestLocation.getProvider());
          
                  // Determine location quality using a combination of timeliness and accuracy
                  if (isMoreAccurate) {
                      return true;
                  } else if (isNewer && !isLessAccurate) {
                      return true;
                  } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
                      return true;
                  }
          
                  return false;
              }
          
              private static boolean isSameProvider(String provider1, String provider2) {
                  if (provider1 == null) {
                      return provider2 == null;
                  }
                  return provider1.equals(provider2);
              }
          
          
              public static boolean hasSelfPermission(Context context, String[] permissions) {
                  // Below Android M all permissions are granted at install time and are already available.
                  if (!(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)) {
                      return true;
                  }
          
                  // Verify that all required permissions have been granted
                  for (String permission : permissions) {
                      if (context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                          return false;
                      }
                  }
          
                  return true;
              }
          }
          

          使用AppCache 存储最后的位置;

          public class AppCache {
          
              public static final String KEY_LAST_LOCATION = "_key_last_location";
          
              private static SharedPreferences mPreference;
          
              static {
                  mPreference = PreferenceManager.getDefaultSharedPreferences(App.getApp().getApplicationContext());
              }
          
              public static String getLastLocation() {
                  return mPreference.getString(KEY_LAST_LOCATION, null);
              }
          
              public static String getLastLocation(String defaultValue) {
                  return mPreference.getString(KEY_LAST_LOCATION, defaultValue);
              }
          
              public static void setLastLocation(String lastLocation) {
                  mPreference.edit().putString(KEY_LAST_LOCATION, lastLocation).commit();
              }
          
              public static void registerPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) {
                  mPreference.registerOnSharedPreferenceChangeListener(listener);
              }
          
              public static void unregisterPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) {
                  mPreference.unregisterOnSharedPreferenceChangeListener(listener);
              }
          }
          

          将以下代码放入您的 MainActivity onCreate() 这将调用 locationManager 以获取最后一个已知位置并更新应用缓存。

          LocationUtil.updateLastKnownLocation(MainActivity.this);
          

          还将onRequestPermissionsResult方法中的fetchLocation();替换为上面的代码行,看起来像;

          @Override
              public void onRequestPermissionsResult(...){
                  switch (requestCode) {
                      case 101:
                      {
                          ...
                              // permission was granted
                              //fetchLocation();
                              LocationUtil.updateLastKnownLocation(MainActivity.this);
                          } else {
                             // Show some error
                          }
                          return;
                      }
                  }
              }
          

          我没有使用你的 latlang 类。 (请确保所有类名都遵循 Java 编码标准)而是使用 LocationLite 将位置存储在缓存中。我还使用 GSON 谷歌库将 pojo 转换和恢复为 JSON 和向后。

          public class LocationLite {
          
              public double lat;
              public double lon;
              public String address;
          }
          

          SunFragment 的最终更改。

          SunAdapter 设为成员变量,将SharedPreferences.OnSharedPreferenceChangeListener 设为监听位置值的任何变化。

          SunAdapter mAdapter;
          
          SharedPreferences.OnSharedPreferenceChangeListener mPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
                  @Override
                  public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
          
                      if(AppCache.KEY_LAST_LOCATION.equalsIgnoreCase(key)) {
                          // location value has change, update data-set
                          SunSession sunSession = sunsList.get(0);
                          sunSession.setId(sharedPreferences.getString(key, "No Location"));
                          sunsList.add(0, sunSession);
                          mAdapter.notifyDataSetChanged();
                      }
                  }
              };
          

          开始收听onStart() 中的偏好更改并在onStop() 中取消注册

          @Override
          public void onStart() {
              super.onStart();
              AppCache.registerPreferenceChangeListener(mPreferenceChangeListener);
          }
          
          @Override
          public void onStop() {
              super.onStop();
              AppCache.unregisterPreferenceChangeListener(mPreferenceChangeListener);
          }
          

          最后,在填充第一个 SunSession 时,请使用以下 location 局部变量。所以它看起来像下面;

                       sunsList.add(
                          new SunSession(
                                  AppCache.getLastLocation("Searching location..."),
                                  "&#xf051;",
                                  sun_rise,
                                  "&#xf052;",
                                  sun_set,
                                  "&#xf0c9",
                                  moon_rise,
                                  "&#xf0ca",
                                  moon_set));
          

          就是这样。有什么不懂的可以问。

          【讨论】:

            猜你喜欢
            • 2013-01-10
            • 1970-01-01
            • 2017-09-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-08-11
            相关资源
            最近更新 更多