河南理工大学Android开发课程:共40学时(24理论学时、16实践学时),学分2.5。

Android四层结构

404

  • 应用层(System Apps)
    系统内置的应用程序以及非系统级的应用程序都属于应用层,负责与用户进行交互,一般使用Java或者Kotlin开发,也就是我们所说的应用层开发。

  • 应用框架层(Java API Framework)
    这一层为应用层开发提供所需要的Java API,也就是常说的Android系统的Java源码,这一层由Java代码编写,所以叫JavaFramework。

  • 系统运行库层(Native)
    从图中可以看出这里分为了两个部分,分别是C/C++程序库和Android运行时库。

    1. C/C++库
      这些C/C++库程序可以被应用框架层所使用,至于为什么Android系统要使用C/C++库,而不都用Java库,原因主要是C/C++代码执行效率更高,而且很多功能有成熟的C++代码,不用重新写

    2. Android运行时库

分为核心库和ART。*(Android运行时环境(ART)自Android 4.4版本引入,并在后续版本中逐步取代了原有的Dalvik作为Android平台的默认运行时环境。)*其中核心库提供了Java语言核心库的大多数功能,这样开发者可以使用Java语言来编写Android应用。而ART则是专门为移动设备定制的Java虚拟机,在之前还有被淘汰的Dalvik虚拟机。ART和JVM还是有很大的区别,它是由C++编写,用来运行Java程序,所以非常关键。而且Android系统还允许同时允许多个ART实例,所以在Android系统中,每个进程都有一个虚拟机,一个APP发生崩溃不会影响其他APP。

  • Linux内核层(Linux Kernel)
    Android的核心服务是基于Linux内核,同时在该基础上添加了Android专用的驱动,比如Binder。由于Linux系统的优秀性,Android在基于Linux于安全性、内存管理、进程管理等都有很大优势。

Android四大组件

404

Activity(活动)

  • 作用:

用户交互的界面,负责展示UI并处理用户操作(如点击、滑动)。

  • 特点:

一个应用通常由多个Activity组成,通过栈管理(任务栈)。
通过Intent跳转或传递数据。
生命周期回调(如onCreate()、onDestroy())用于管理资源。

Service(服务)

  • 作用:

在后台执行长时间运行的操作(如下载、播放音乐),无界面。

  • 特点:

启动服务:通过startService()启动,需手动停止。
绑定服务:通过bindService()与组件绑定,可跨进程通信(IPC)。
典型场景:后台网络请求、定时任务等。

BroadcastReceiver(广播接收器)

  • 作用:监听系统或应用发出的广播(如电量不足、网络变化),并触发响应。

  • 特点:

可启用Activity、Notification通知

ContentProvider(内容提供者)

  • 作用:管理应用间数据共享,提供统一的访问接口(如通讯录、数据库)。

  • 特点:

通过ContentResolver操作数据(增删改查)。
支持权限控制,保障数据安全。

知识点

Intent(意图):四大组件间通信的纽带,可显式/隐式指定目标组件。

AndroidManifest.xml:所有组件需在此文件中声明(注册),否则无法使用。

四大组件各司其职,共同构成Android应用的基石:Activity管界面、Service管后台、BroadcastReceiver管事件、ContentProvider管数据共享。

activity的生命周期

  1. 过程

404

  1. 全生命周期
    函数的调用顺序:onCreate() →onStart()→onResume()→ onPause()→ onStop()→ onDestroy()

调用onCreate()函数分配资源、调用onStart()将Activity显示在屏幕上、调用onResume()获取屏幕焦点、调用onPause()、onStop()和onDestroy(),释放资源并销毁进程

onStart()(显示在屏幕上):仅表示 Activity 已可见,但尚未完全准备好接收用户交互(如界面元素可能还在加载);
onResume()(获取屏幕焦点):是 Activity 可见性的进一步确认,此时界面元素已就绪,可真正响应用户操作;
onPause()这里分两路,分为完全遮挡和不完全遮挡。

Log类

Android 的 Log 类提供了不同级别的日志输出方法,用于不同场景的调试和问题追踪。以下是它们的含义和典型使用场景:


1. Log.v() - Verbose(详细日志)

  • 级别:最低,输出最详细的日志信息
  • 使用场景
    • 开发阶段的详细流程跟踪
    • 需要记录大量调试信息时(如循环、高频事件)
    • 生产环境应关闭
  • 示例
    1
    2
    Log.v("TAG", "onCreate() called"); 
    // 输出:V/TAG: onCreate() called

2. Log.d() - Debug(调试日志)

  • 级别:调试信息
  • 使用场景
    • 开发时检查变量值、方法调用流程
    • 临时调试问题(完成后建议删除)
    • 生产环境建议关闭
  • 示例
    1
    2
    Log.d("TAG", "User ID: " + userId); 
    // 输出:D/TAG: User ID: 123

3. Log.i() - Info(信息日志)

  • 级别:重要运行时信息
  • 使用场景
    • 记录关键业务流程(如用户登录、支付成功)
    • 需要长期保留的运行时状态
    • 生产环境可保留
  • 示例
    1
    2
    Log.i("TAG", "App started, version: 1.2.0"); 
    // 输出:I/TAG: App started, version: 1.2.0

4. Log.w() - Warning(警告日志)

  • 级别:潜在问题
  • 使用场景
    • 捕获非预期但可恢复的情况(如低内存、网络超时重试)
    • 标记需要关注的边界条件
    • 生产环境必须监控
  • 示例
    1
    2
    Log.w("TAG", "Low memory, cache cleared"); 
    // 输出:W/TAG: Low memory, cache cleared

5. Log.e() - Error(错误日志)

  • 级别:严重错误
  • 使用场景
    • 记录崩溃前的错误(如异常捕获)
    • 关键功能失败(如数据库写入失败)
    • 生产环境必须紧急处理
  • 示例
    1
    2
    3
    4
    5
    6
    try {
    // 危险操作
    } catch (Exception e) {
    Log.e("TAG", "Failed to save data", e);
    // 输出:E/TAG: Failed to save data [附带异常堆栈]
    }

创建一个跳转按钮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Button btn=findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() { // 这里是匿名类的实例化
@Override
public void onClick(View v) {
Log.d(TAG, "btn");
/*TAG是日志标签,一般为类名,借助它能够对日志进行过滤。
"btn"是日志的具体信息,一般用来标记某个事件,在此处或许表示按钮(Button)被点击了。*/
Intent intent = new Intent(MainActivity2.this,MainActivity.class);
/*Intent是负责在不同组件间进行通信的载体。*/
startActivity(intent);
/*startActivity(intent);执行意图*/
}
});


// 直接通过 new 接口名() { ... } 的方式实现接口,没有显式定义类名。

源码:

1
2
3
public interface OnClickListener {
void onClick(View v); // 唯一的抽象方法
}

线性布局的权重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<LinearLayout
android:orientation="vertical"
android:layout_weight="1" //该行为权重
android:layout_width="match_parent"
android:layout_height="0dp"> //vertical时,高为0
<TextView
android:layout_weight="2"
android:layout_width="match_parent"
android:layout_height="0dp"></TextView>
<TextView
android:layout_weight="2"
android:layout_width="match_parent"
android:layout_height="0dp"></TextView>
<TextView
android:layout_weight="2"
android:layout_width="match_parent"
android:layout_height="0dp"></TextView>
<TextView
android:layout_weight="2"
android:layout_width="match_parent"
android:layout_height="0dp"></TextView>
</LinearLayout>


<LinearLayout
android:orientation="horizontal"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp">
<TextView
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="match_parent"></TextView>
<TextView
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="match_parent"></TextView>
<TextView
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="match_parent"></TextView>
<TextView
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="match_parent"></TextView>

<TextView
android:autoLink="phone" //可设置不同的值对应的部分会成为超链接
android:text="http://www.baidu.com 13312345678 test@163.com"
android:layout_width="match_parent"
android:layout_height="wrap_content"></TextView>
</LinearLayout>

做一个登录界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class MainActivity extends AppCompatActivity {

private EditText usernameEditText;
private EditText passwordEditText;
private Button loginButton;
private Button registerButton;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
//实现全面屏,例如挖孔屏可以覆盖孔
setContentView(R.layout.activity_main);
//它将指定的 XML 布局文件加载到当前 Activity 的窗口中
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});

//init
usernameEditText = findViewById(R.id.usernameEditText);
//通过资源 ID 查找并初始化用户界面组件
passwordEditText = findViewById(R.id.passwordEditText);
loginButton = findViewById(R.id.loginButton);
registerButton = findViewById(R.id.registerButton);


// logic
loginButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
if("".equals(usernameEditText.getText().toString().trim())
|| "".equals(passwordEditText.getText().toString().trim())){
Toast.makeText(MainActivity.this, "用户名/密码不能为空", Toast.LENGTH_SHORT).show();
return ;
}
//否则
SharedPreferences sp = getSharedPreferences("user",MODE_PRIVATE);
/*参数 1:"user" 是共享偏好文件的名称,系统会在应用内部存储中创建名为 user.xml 的文件。
参数 2:MODE_PRIVATE 指定该文件仅能被当前应用访问,其他应用无法读取或修改。
数据以 键值对(Key-Value) 形式保存在 XML 文件中。
常用于存储轻量级应用数据(如用户设置、登录状态等)。
数据存储在 /data/data/应用包名/shared_prefs/user.xml,root 设备可查看。
线程安全。 */
if(sp.getString("username","1").equals(usernameEditText.getText().toString())
&& sp.getString("password","2").equals(passwordEditText.getText().toString())){
Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
}
/*String getString(String key, String defaultValue)
key:要获取数据的键(String 类型)。
defaultValue:如果指定的 key 不存在(意思是数据库中就没有这个键)时返回的默认值。 */
}
});

registerButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,MainActivity2.class);
startActivity(intent);
}
});
}
}

做一个注册界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class MainActivity2 extends AppCompatActivity {


private EditText registerUsernameEditText;
private EditText registerPasswordEditText;
private EditText confirmPasswordEditText;
private Button registerSubmitButton;



private static final String PREFS_NAME="user";
private static final String USERNAME_KEY="username";
private static final String PASSWORD_KEY="password";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main2);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});

registerUsernameEditText = findViewById(R.id.registerUsernameEditText);
registerPasswordEditText = findViewById(R.id.registerPasswordEditText);
confirmPasswordEditText = findViewById(R.id.confirmPasswordEditText);
registerSubmitButton = findViewById(R.id.registerSubmitButton);

registerSubmitButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String username = registerUsernameEditText.getText().toString();
String password = registerPasswordEditText.getText().toString();
String confirmPassword = confirmPasswordEditText.getText().toString();

if (username.isEmpty() || password.isEmpty() || !password.equals(confirmPassword)){
Toast.makeText(MainActivity2.this, "用户名与密码都不能为空,而且两次密码的输入都需要一致", Toast.LENGTH_SHORT).show();
return ;
}

SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME,MODE_PRIVATE);
/*共享偏好
*/
SharedPreferences.Editor editor = sharedPreferences.edit();
/*要对共享偏好文件进行写入操作,得先获取编辑器对象。
SharedPreferences.Editor 是 Android 中用于修改共享偏好文件(SharedPreferences)的接口。
Editor putString(String key, String value);
Editor putInt(String key, int value);
Editor putBoolean(String key, boolean value);等
*/
editor.putString(USERNAME_KEY,username);
editor.putString(PASSWORD_KEY,password);
/*把用户输入的 username 和 password 以字符串形式存进共享偏好文件
USERNAME_KEY 和 PASSWORD_KEY 是自定义的键名。 */
editor.apply();
//apply() 方法会异步地把修改内容写入磁盘。


Toast.makeText(MainActivity2.this, "注册成功", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(MainActivity2.this,MainActivity.class);
startActivity(intent);
finish();
//用于关闭当前 Activity
}
});


}
}

做一个可进行明/暗文切换的输入框

1
2
3
4
5
6
7
8
9
10
11
12
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:endIconMode="password_toggle">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/passwordEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="密码"
android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>

密码格式的限制

1
2
3
4
if (!password.matches(".*\\d.*") || !password.matches(".*[a-zA-Z].*") || !password.matches(".*[^a-zA-Z0-9].*")){
Toast.makeText(MainActivity2.this, "必须包含一个数字、一个字母、一个特殊字符", Toast.LENGTH_SHORT).show();
return ;
}

匿名内部类,以Handler为例

1
2
3
new 父类/接口() {
// 重写父类的方法或实现接口的方法
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 1. 先定义一个 Handler 的子类
private class MyHandler extends Handler {
public MyHandler() {
super(Looper.getMainLooper());
}

@Override
public void handleMessage(@NonNull Message msg) {
textView.setText((String) msg.obj);
}
}

// 2. 在 Activity 中使用
private Handler handler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);

// 创建子类的实例
handler = new MyHandler();

// 启动子线程...
}

子线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class MainActivity extends AppCompatActivity {

private TextView textView;
private Handler handler;
private int counter = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});

textView = findViewById(R.id.textView);

handler = new Handler(Looper.getMainLooper()){
//Handler:是一个 “桥梁”,负责把消息从子线程传递到主线程。
//创建一个线程,并指定他的工作地点是主线程(Looper.getMainLooper())。
@Override
//重写 handleMessage() 方法,指定操作
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
String result = (String)msg.obj;
textView.setText(result);

}
};
/*将消息从子线程传递到主线程,确保 UI 更新操作在主线程执行。
匿名内部类
*/

new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

Message message= Message.obtain();
//Message.obtain():从消息池中获取一个消息对象(Coder拿一张便签纸)。
message.obj = "后台任务完成";
//Coder在便签纸上写 “后台任务完成”
handler.sendMessage(message);
//把便签纸交给Handler
}
}).start();
//匿名对象
}
}

布局、组件及其属性

LinearLayout(线性布局)

  • 必备属性 android:orientation=”vertical”

RelativeLayout(相对布局)

-

TextView(文本框)

  • android:text=”我是第二个页面”
  • android:textColor=”#FF0000”
  • android:background=”#FF0000”
  • android:layout_width=”match_parent” //和父容器一样
  • android:layout_height=”wrap_content” //合适,不大不小,默认规定的值
  • android:gravity=”right” //靠右显示
  • android:layout_width=”60dp” //单位为dp
  • android:layout_alignBaseline=”@id/etid”
  • android:layout_alignBaseline=”@id/etid” //是一个在 RelativeLayout 中使用的属性,用于将一个视图的基线(baseline)与另一个视图的基线对齐。这个属性通常用于对齐文本控件(如 TextView 或 EditText)的文本基线,使它们在视觉上对齐。$仅适用于 RelativeLayout
  • android:layout_toRightOf //用于将当前视图的左边缘放置在指定视图的右边缘的右侧。$仅适用于 RelativeLayout
  • android:layout_below=”@id/etid” //是一个在 RelativeLayout 中使用的属性,用于将当前视图的顶部放置在etid视图的底部的下方。这个属性通常用于控制视图之间的垂直布局关系。 $仅适用于 RelativeLayout
    作用
  • android:layout_alignRight=”@id/etpwd” //是 Android 布局文件中的一种属性,用于指定当前视图的右边缘与另一个视图(这里是 etpwd)的右边缘对齐。$仅适用于 RelativeLayout
  • android:layout_toLeftOf=”@id/btncancel” //用于将一个视图的右边缘放置在另一个视图的左边缘的左侧 $仅适用于 RelativeLayout

Button(按钮)

  • android:id=”@+id/btn”
  • android:text=”跳转”
  • android:layout_width=”match_parent”
  • android:layout_height=”wrap_content”
  • android:layout_marginRight=”10dp” //是一个用于设置视图(View)在父布局中右侧外边距的属性。它定义了视图与父布局右侧之间的空间距离。

EditText(文本编辑框)

小知识点

颜色表示

#RGB:分别表示红、绿、蓝三原色的值(该表示方法只支持0F这16级的颜色)来表示颜色。
#ARGB:分别表示透明度(只支持0
F这16级的透明度)、红、绿、蓝的三原色的值该表示方法只支持0F这16级的颜色)
#RRGGBB:分别表示红、绿、蓝三原色的值(该表示方法只支持00
FF这256级的颜色)来表示颜色。
#AARRGGBB:分别表示透明度(只支持00FF这256级的透明度)、红、绿、蓝三原色的值(该表示方法只支持00FF这256级的颜色)来表示颜色。

dp与sp

SP 是一种缩放独立的像素单位,主要用于定义字体大小

padding和layout_margin

属性 作用对象 效果 类比(CSS)
padding 视图内部的内容与边界之间的距离 缩小视图内部内容的显示区域 padding
layout_margin 视图外部与其他视图之间的距离 扩大视图占据的空间,推开周围视图 margin

如何创建一个—menu菜单

  1. 先按照如图所示建立文件夹
    404
    404
    404

  2. 编写option.xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<item android:title="保存"
android:id="@+id/save"
app:showAsAction="always"/>
<!-- always意思是不缩进三个点里 -->
<item android:title="设置"
android:id="@+id/setting"/>
<item android:title="更多操作" >
<menu >
<item android:title="退出"
android:id="@+id/exit"/>
<item android:title="操作1" />
<item android:title="操作2" />
</menu>
<!-- menu中的三个item放在更多操作里 -->
</item>
  1. 让其在模拟器中显示,编写java文件
1
2
3
4
5
6
//添加以下这即可
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.option, menu);
return true;
}

首选项

  1. 在Android中,首选项(Preferences) 是一种用于存储和管理应用程序配置或用户设置的机制,通常以键值对形式保存

  2. SharedPreferences

轻量级键值存储,数据以XML文件形式保存在/data/data/<package_name>/shared_prefs/目录。

1
2
3
4
5
6
7
8
// 写入数据
SharedPreferences prefs = getSharedPreferences("MyPrefs", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("username", "John");
editor.apply();

// 读取数据
String name = prefs.getString("username", "default");

JSON

  1. 在Android开发中,JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式

  2. 实例

1
2
3
4
5
6
{
"name": "Android",
"version": 13,
"features": ["Jetpack", "Kotlin"],
"isOpenSource": true
}
  1. JSON处理库

原生org.json。特点:Android内置,无需额外依赖,但功能较基础。

1
2
3
4
5
6
7
8
// 解析JSON字符串
String jsonStr = "{\"name\":\"Android\"}";
JSONObject json = new JSONObject(jsonStr);
String name = json.getString("name"); // 输出: Android

// 生成JSON
JSONObject newJson = new JSONObject();
newJson.put("version", 13);

工具

  1. launcher:启动器
  2. gradle:编译代码、处理资源、管理第三方库依赖、生成APK/AAB文件,以及配置不同构建变体(如Debug/Release)。
  3. ctrl+O:快速添加重写方法

课程设计-基于GIS的Android地图开发

序章

基于位置的服务所围绕的核心就是要先确定出用户所在的位置。通常有两种技术方式可以实现:一种是通过GPS定位,一种是通过网络定位。
GPS定位的工作原理是基于手机内置的GPS硬件直接和卫星交互来获取当前的经纬度信息,这种定位方式精确度非常高,但缺点是只能在室外使用,室内基本无法接收到卫星的信号。网络定位的工作原理是根据手机当前网络附近的三个基站进行测速,以此计算出手机和每个基站之间的距离,再通过三角定位确定出一个大概的位置,这种定位方式精确度一般,但优点是在室内室外都可以使用。

Android 对这两种定位方式都提供了相应的API支持,但是由于一些特殊原因,Google的网络服务在中国不可访问,从而导致网络定位方式的API失效。而GPS定位虽然不需要网络,但是必须要在室外才可以使用,因此在室内开发的时候很有可能会遇到不管使用哪种定位方式都无法成功定位的情况。

基于以上原因,放弃Android原生定位 API的用法了,而是使用一些国内第三方公司的 SDK。

404

  1. SHA1

SHA1(Secure Hash Algorithm 1)是一种加密哈希函数,可将任意长度的数据生成唯一的160位(20字节)固定长度哈希值,常用于数据完整性校验和数字签名,但因其安全性漏洞(如碰撞攻击)已被逐步淘汰。

  1. android studio如何连接夜神模拟器

在夜神的bin目录下D:\yeshen\data\Nox\bin打开cmd,执行命令nox_adb.exe connect 127.0.0.1:62001

在Android Studio中访问谷歌虚拟手机(Android Emulator)的内部资源

  • 访问普通资源
  1. 打开Android Studio的终端或命令提示符
  2. 使用以下adb命令:adb shell
  3. 进入shell后,使用Linux命令浏览文件系统
  • 访问root资源
  1. 如果 adb root 不可用,可以尝试临时修改权限:
1
2
3
adb shell
su
chmod 777 /data/data/应用包名
  • 注意事项
    Google Play 镜像默认无 root:如果你使用的是 “Google Play” 镜像,可能无法获取 root 权限,建议改用 “Google APIs” 镜像。

论文伴侣——NoteExpress的使用说明

点击这里

Word中的交叉引用

点击这里

百度学术

点击这里

随感

I prefer to mark a number of sentiment that will show itself underneath.

  • lay hands on approaches to dispose of errors:

there are little information useful on the internet nowadays,either one copy another,or opppsitely.Repeat oneself agine and agine only find you are reaing the same article which cite the same photograph.It is hard to change this despairing situation.Because of that , my ambition is to manufacture high-class academic article for example:$1what the problem is? $2what caused this problem? $3how to slove this problem.while texting,lay picture aside of it ,only words seems stupid and reads hardly.Compared to official or authorized technology files,I squint towards texts made by personal blogs while occupy approachable statement.

404

课设设计思路

// 1. 创建定位客户端
mLocationClient = new LocationClient(getApplicationContext());

// 2. 创建并配置定位选项
LocationClientOption option = new LocationClientOption();
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy); // 高精度模式
option.setScanSpan(5000); // 5秒更新一次
option.setIsNeedAddress(true); // 需要地址信息

// 3. 将配置应用到客户端(关键步骤)
mLocationClient.setLocOption(option);

// 4. 注册位置监听器(监听定位结果)
mLocationClient.registerLocationListener(myListener);

// 5. 启动定位
mLocationClient.start();