热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android定位

android定位参考:android.location:https:developer.android.comreferenceandroidlocationpack

android 定位

参考:
android.location:https://developer.android.com/reference/android/location/package-summary.html
Location and Maps:https://developer.android.com/guide/topics/location/index.html#location
Location Strategies:https://developer.android.com/guide/topics/location/strategies.html
Location:https://developer.android.com/reference/android/location/Location.html


下面介绍基于android框架APIs - android.location的定位。



android定位框架 - android.location

有两种定位的方式:
1.基于GPS定位;
2.基于网络定位。

GPS定位的 好处 :精确度高; 坏处 :仅能在户外使用,获取定位信息速度慢,耗费电池。
网络定位的 好处 :户内户外都能使用,定位速度快,电量耗费低; 坏处 :精确度不太高。

我们可以综合使用两种定位方式,也可以单独使用其中一种


关键组件

LocationManager

android原生定位框架的核心组件是
LocationManager
系统服务,获取这个组件并不需要实例化,通常是通过函数
getSystemService(Context.LOCATION_SERVICE)
获得,该函数会返回一个LocationManager的实例,示例代码如下:

// Acquire a reference to the system Location Manager

LocationManager locatiOnManager= (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

LocationListener

通过回调(callback)来获取用户定位信息,首先我们需要通过新建一个
LocationListener
类,并实现其中的几个回调方法,示例代码如下:

// Define a listener that responds to location updates
LocationListener locatiOnListener= new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
// 这个函数中的location就是获取到的位置信息
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};

同时我们需要调用函数 requestLocationUpdates 绑定

LocationManager和LocationListener,示例代码如下:
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);

参数介绍:
第一个参数表示定位提供商的类型(the type of location provider),可以是
GPS_PROVIDER
或者
NETWORK_PROVIDER;
第二个参数表示更新定位信息的最短时间间隔;
第三个参数表示更新定位信息的最短改变距离;
第四个参数就是LocationListener实例。
注:如果第二个和第三个参数均为0表示尽可能快的更新定位信息

如果你想要获取同时使用两种定位方式,那么需要使用两次 requestLocationUpdate 函数,示例代码如下:

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);

Location

这是一个数据类,保存了定位的信息,在

public void onLocationChanged(Location location)

中得到的location就是最新的定位信息,其中包括了维度(latitude),经度(longitude)等位置信息。

定位权限

定位功能的使用需要获取定位权限
如果使用 NETWORK_PROVIDER ,那么需要请求

android.permission.ACCESS_COARSE_LOCATION

如果使用 GPS_PROVIDER 或者同时使用上述两种定位方式,那么需要请求

android.permission.ACCESS_FINE_LOCATION

同时,如果你的app的运行环境是Android 5.0(API Level 21)或更高(If your app targets Android 5.0 (API level 21) or higher),那么你还需要显式请求

android.hardware.location.network
或者
android.hardware.location.gps

示例代码如下:




...



...

同时当你的运行环境大于等于Android 6.0(API Level 23),你还需要在代码中显式进行权限检查,本次示例代码如下:

if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_DENIED) {
return ;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED) {
return ;
}

示例

下面展示一个简单的应用示例:

新建一个工程LocationTest,使用默认Activity

MainActivity.java代码如下:

package com.zj.location;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private LocationManager locationManager;
private LocationListener locationListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locatiOnManager= (LocationManager)getSystemService(Context.LOCATION_SERVICE);
locatiOnListener= new LocationListener() {
@Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged: ");
Log.d(TAG, "onLocationChanged: latitude = "+location.getLatitude());
Log.d(TAG, "onLocationChanged: lOngitude= "+location.getLongitude());
Log.d(TAG, "onLocationChanged: provider = "+location.getProvider());
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
};
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_DENIED) {
return ;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED) {
return ;
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
}
}

同时请求GPS定位信息以及Network定位信息,在 AndroidManifest.xml 中加入:





运行结果如下:

01-26 21:20:16.234 24056-24099/com.zj.location I/OpenGLRenderer: Initialized EGL, version 1.4
01-26 21:20:16.375 24056-24056/com.zj.location D/MainActivity: onLocationChanged:
01-26 21:20:16.376 24056-24056/com.zj.location D/MainActivity: onLocationChanged: latitude = 28.991173
01-26 21:20:16.376 24056-24056/com.zj.location D/MainActivity: onLocationChanged: lOngitude= 120.254411
01-26 21:20:16.376 24056-24056/com.zj.location D/MainActivity: onLocationChanged: provider = network
01-26 21:20:46.471 24056-24056/com.zj.location D/MainActivity: onLocationChanged:
01-26 21:20:46.471 24056-24056/com.zj.location D/MainActivity: onLocationChanged: latitude = 28.991173
01-26 21:20:46.472 24056-24056/com.zj.location D/MainActivity: onLocationChanged: lOngitude= 120.254411
01-26 21:20:46.472 24056-24056/com.zj.location D/MainActivity: onLocationChanged: provider = network

在logcat中显示出了手机的经纬度以及信息提供方


获取定位信息过程中遇到的问题

在android的官方文档中提到,获取到的定位信息可能包含错误或者存在精度问题

Challenges in Determining User Location

里面提到了3种原因:


  • 多个定位源(Multitude of location sources)

  • 手机的移动(User movement)

  • 定位信息的精度问题(Varying accuracy)


创建最佳体验的定位模型

需要考虑下面几个问题

什么时候开始

长时间的监听定位更新会耗费大量的电量,但是,如果监听时间太短可能会导致定位精度问题。
开始监听定位更新是通过调用函数 requestLocationUpdates ,示例代码如下:

String locatiOnProvider= LocationManager.NETWORK_PROVIDER;
// Or, use GPS location data:
// String locatiOnProvider= LocationManager.GPS_PROVIDER;
locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);

获取最后已知的定位信息

在开始监听定位到获取到第一个定位信息可能会需要一段较长的时间,你可以利用函数 getLastKnownLocation 先获取一个缓存的定位信息,示例代码如下:

String locatiOnProvider= LocationManager.NETWORK_PROVIDER;
// Or use LocationManager.GPS_PROVIDER
Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);

注:这个定位信息有可能并不准确,也有可能和真正的位置一致

什么时候结束监听

因为长时间的监听定位会耗费大量的电量,所以当使用完定位功能后,可以手动移除定位监听,示例代码如下:

// Remove the listener you previously added
locationManager.removeUpdates(locationListener);

获取最佳定位

并不是最新得到的定位信息就是最好的,因为存在精度问题,可能最新获取的定位信息在精度和时间上并不是最好的,官方文档提到了几种方法来获取最佳的定位信息:


  • 判断获取到的定位信息是否比当前定位信息更新(Check if the location retrieved is significantly newer than the previous estimate.)

  • 判断获取到的定位信息的精度是否比当前定位信息更好(Check if the accuracy claimed by the location is better or worse than the previous estimate.)

  • 判断获取到的定位信息的提供商是否是你更加信任的(Check which provider the new location is from and determine if you trust it more.)

官方的示例代码如下:

private static final int TWO_MINUTES = 1000 * 60 * 2;
/** Determines whether one Location reading is better than the current Location fix
* @param location The new Location that you want to evaluate
* @param currentBestLocation The current Location fix, to which you want to compare the new one
*/
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
}
// 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;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}

示例2

利用上面提到的策略,修改代码

MainActivity.java代码如下:

package com.zj.location;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int TWO_MINUTES = 1000 * 60 * 2;
private final String NetworkProvider = LocationManager.NETWORK_PROVIDER;
private final String GpsProvider = LocationManager.GPS_PROVIDER;
private Location currentLocation;
private LocationManager locationManager;
private LocationListener locationListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locatiOnManager= (LocationManager)getSystemService(Context.LOCATION_SERVICE);
locatiOnListener= new LocationListener() {
@Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged: ");
if (isBetterLocation(location, currentLocation)) {
currentLocation = location;
showLocation(currentLocation);
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
};
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_DENIED) {
return ;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED) {
return ;
}
Location lastKnownGpsLocation = locationManager.getLastKnownLocation(GpsProvider);
Location lastKnownNetworkLocation = locationManager.getLastKnownLocation(NetworkProvider);
showLocation(lastKnownGpsLocation);
showLocation(lastKnownNetworkLocation);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
}
private void showLocation(Location location) {
if (location == null) {
Log.e(TAG, "showLocation: location == null");
return ;
}
Log.d(TAG, "latitude = "+location.getLatitude());
Log.d(TAG, "lOngitude= "+location.getLongitude());
Log.d(TAG, "provider = "+location.getProvider());
}
/** Determines whether one Location reading is better than the current Location fix
* @param location The new Location that you want to evaluate
* @param currentBestLocation The current Location fix, to which you want to compare the new one
*/
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
}
// 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;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
}

logcat 信息显示如下:

1-27 13:12:03.714 31281-31281/? V/BoostFramework: mReleaseFunc method = public int com.qualcomm.qti.Performance.perfLockRelease()
01-27 13:12:03.714 31281-31281/? V/BoostFramework: mAcquireTouchFunc method = public int com.qualcomm.qti.Performance.perfLockAcquireTouch(android.view.MotionEvent,android.util.DisplayMetrics,int,int[])
01-27 13:12:03.714 31281-31281/? V/BoostFramework: mIOPStart method = public int com.qualcomm.qti.Performance.perfIOPrefetchStart(int,java.lang.String)
01-27 13:12:03.714 31281-31281/? V/BoostFramework: mIOPStop method = public int com.qualcomm.qti.Performance.perfIOPrefetchStop()
01-27 13:12:03.716 31281-31281/? V/BoostFramework: BoostFramework() : mPerf = com.qualcomm.qti.Performance@71e6aaa
01-27 13:12:03.753 31281-31281/com.zj.location W/System: ClassLoader referenced unknown path: /data/app/com.zj.location-1/lib/arm64
01-27 13:12:03.768 31281-31281/com.zj.location W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
01-27 13:12:03.790 31281-31281/com.zj.location V/BoostFramework: BoostFramework() : mPerf = com.qualcomm.qti.Performance@be3f850
01-27 13:12:03.790 31281-31281/com.zj.location V/BoostFramework: BoostFramework() : mPerf = com.qualcomm.qti.Performance@3994a49
01-27 13:12:03.812 31281-31281/com.zj.location E/MainActivity: showLocation: location == null
01-27 13:12:03.812 31281-31281/com.zj.location D/MainActivity: latitude = 28.991141
01-27 13:12:03.812 31281-31281/com.zj.location D/MainActivity: lOngitude= 120.25443
01-27 13:12:03.812 31281-31281/com.zj.location D/MainActivity: provider = network
01-27 13:12:03.839 31281-31301/com.zj.location D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
01-27 13:12:03.850 31281-31281/com.zj.location D/ActivityThreadInjector: clearCachedDrawables.
01-27 13:12:03.897 31281-31301/com.zj.location I/Adreno: QUALCOMM build : 0a3bdfc, Ifb508eebcd
Build Date : 08/04/16
OpenGL ES Shader Compiler Version: XE031.09.00.03
Local Branch :
Remote Branch :
Remote Branch :
Reconstruct Branch :
01-27 13:12:03.902 31281-31301/com.zj.location I/OpenGLRenderer: Initialized EGL, version 1.4
01-27 13:12:04.056 31281-31281/com.zj.location D/MainActivity: onLocationChanged:
01-27 13:12:04.057 31281-31281/com.zj.location D/MainActivity: latitude = 28.991141
01-27 13:12:04.057 31281-31281/com.zj.location D/MainActivity: lOngitude= 120.254431
01-27 13:12:04.057 31281-31281/com.zj.location D/MainActivity: provider = network
01-27 13:12:12.144 31281-31281/com.zj.location V/BoostFramework: BoostFramework() : mPerf = com.qualcomm.qti.Performance@288f8d6
01-27 13:12:34.255 31281-31281/com.zj.location D/MainActivity: onLocationChanged:
01-27 13:12:34.255 31281-31281/com.zj.location D/MainActivity: latitude = 28.991141
01-27 13:12:34.256 31281-31281/com.zj.location D/MainActivity: lOngitude= 120.254431
01-27 13:12:34.256 31281-31281/com.zj.location D/MainActivity: provider = network
01-27 13:13:04.323 31281-31281/com.zj.location D/MainActivity: onLocationChanged:
01-27 13:13:04.324 31281-31281/com.zj.location D/MainActivity: latitude = 28.991141
01-27 13:13:04.324 31281-31281/com.zj.location D/MainActivity: lOngitude= 120.254431
01-27 13:13:04.324 31281-31281/com.zj.location D/MainActivity: provider = network
01-27 13:13:34.401 31281-31281/com.zj.location D/MainActivity: onLocationChanged:
01-27 13:13:34.401 31281-31281/com.zj.location D/MainActivity: latitude = 28.991141
01-27 13:13:34.401 31281-31281/com.zj.location D/MainActivity: lOngitude= 120.254431
01-27 13:13:34.402 31281-31281/com.zj.location D/MainActivity: provider = network

提供模拟定位数据

当你使用模拟设备时,Android Studio可以提供模拟定位数据

Providing Mock Location Data



推荐阅读
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
author-avatar
不是一点都不很帅_973
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有