听说点赞关注的人,身体健康,万事如意,工作顺利,爱情甜蜜,一夜暴富,升职加薪……最终迎娶白富美!!!
微信公众号:炜煜gzs
题目:安卓开发-基础知识补习3
内容简介:本文通过学习安卓零基础开发到入门的书籍,介绍了安卓的两种数据存储的方式,一种是内部存储空间文件的存取,另一种是SD卡空间的文件的存取。通过简单的介绍实现了不同方式的功能实现,使用java代码进行开发,如果有问题的地方请不吝指教,如果对文内内容有不理解的地方,也希望能积极主动的联系博主进行深刻的探讨,以便于更好的让博主记住这篇博文的内容,好让博主在发光发热的道路上越走越远。[手动狗头]努力,奋斗!
标题一:安卓中的数据存储
安卓中数据存储的方式大致分为以下五种
- 文件存储:安卓提供了openFileOutput()和openFileInput()方法读取设备上的文件,本是上是以java的I/O流方式读取数据,文件存储的关键是获取相应的输入流和输出流。
- SharedPreferces:是安卓提供的用来存储简单配置信息的一种方式,它采用键值对的形式以XML格式将数据存储到设备中。通常使用SharedPeferences存储一些应用该程序的配置信息,如用户名,密码等。
- SQLite数据库:SQLite是安卓自带的一个轻量级的数据库,它没有后台进程,整个数据库对应于一个文件。安卓为访问SQLite数据库提供了大量的边界的API,并且支持基本SQL语法,一般使用它作为负责数据的存储引擎,把相对复杂的结构化数据存储在本地。
- ContentProvider(内容提供者):安卓的四大组件之一,用于在应用程序之间进行数据交换的标准API。
- 网络数据读取:通过网络向服务器发送请求,获取相应数据或者将数据存储到服务器上。
内部存储控件文件的存取
内部存储是指将数据以文件的形式存储到应用程序中。对于安卓应用来说,内部存储的数据属于应用程序的私有数据,如果其他应用程序想要操作本应用程序的文件,需要获取权限。当应用写在之后,内部存储的数据也就清空了,为了保证内存数据的安全,不让用户直接定位访问,安卓中对内部存储控件中文件的读取进行封装,用户不需要知道具体的存储路径就可以打开相应的文件输入/输出流。在Context类中提供了两个方法来打开I/O流。
FileInputStream openFi了Input(String name):获取应用程序中名为name的文件的对应的文件输入流。
FileOutputStream openFileOutput(String name,int node):获取应用程序名为name的文件对应的文件输出流。
name参数表示读取或者存入指定文件的文件名,不能包含路径分隔符“\”,如果文件不存在安卓胡i自动创建该文件。mode参数用于指定操作模式,Context类中定义了四种操作模式常量,如下
-
Context.MODE_PRIVATE :为默认操作模式,代表该文件是私有的,只能被应用本身访问,在该模式下写入的内容会被覆盖原文件的内容。
-
Context.MODE_APPEND:附加模式,会检查文件是否存在,存在就往文件后追加内容,否则创建新文件再写入新内容。
-
Context.MODE_WORLD_READABLE:表示当i请安文件可以被其他应用读取。
-
Context.MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
提示:如果希望文件技能被其他应用读也能写,可以传入:Context.MODE_WORLD_READABLE+Context.MODE_WORLD_READABLE或者直接传入数值3,四种模式中除了APPEND模式会将内容追加到文件末尾,其他模式都会覆盖掉源文件的内容。
高版本安卓中建议采用更好的机制,例如通过ContentProvider暴露访问接口,或者通过服务广播,已经废弃了两个读写
在手机上创建文件和像文件中追加内容的步骤如下:
- 调用openFileOutput()方法传入文件的名称和操作的模式,该方法将会返回一个文件输出流。
- 调用文件输出流的write()方法,像文件写入内容。
- 调用文件输出流的close()方法,关闭文件输出流。
读取手机上文件的一般步骤如下:
- 调用openFileInput()方法传入读取数据的文件名,该方法返回一个文件输入流对象。
- 调用文件输入流对象的read()方法读取文件的内容。
- 调用文件输入流对象的close()方法关闭文件输入流。
布局文件如下:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edit_content"
android:hint="请输入内容:"></EditText>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_save"
android:text="保存到手机内部存储空间"></Button>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tv_content"
android:lines="3"
android:text="读取的内容:"
android:textSize="15dp"></TextView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_read"
android:text="读取文件"></Button>
</LinearLayout>
java代码如下
private EditText editText;
private TextView textView;
private Button buttonSave;
private Button buttonRead;
private String fileName="content.txt";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
editText = findViewById(R.id.edit_content);
textView = findViewById(R.id.tv_content);
buttonRead = findViewById(R.id.btn_read);
buttonSave = findViewById(R.id.btn_save);
buttonSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = editText.getText().toString();
try {
FileOutputStream fos = openFileOutput(fileName,MODE_PRIVATE);
fos.write(content.getBytes(StandardCharsets.UTF_8));
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
buttonRead.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
FileInputStream fis = openFileInput(fileName);
byte[] bytes = new byte[fis.available()];
fis.read(bytes);
String content = new String(bytes);
//textView.setText(content);
textView.setText("nihaohifdsajf");
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
读取SD卡上的文件
内存中存放文件会直接影响软件的运行效率。因为SD卡的可移动性,可能被移除或者丢失,并且不是所有的手机都有SD卡,还有可能SD卡损坏或者安装不正确等。在访问之前需要验证手机端的SD卡状态,安卓提供了Envionment类完成这一操作,当外部设备可用并且具有读写权限是,就可以通过FileInputStream和FileOutputStream对象来读写外部设备中的文件。
SD卡中的数据涉及用户的隐私,访问是需要盛情相关的权限,需要使用到运行权限,即在程序运行时,提示用户进行给授权,因此,读写SD卡上的文件的主要步骤如下:
- 掉哦那个Ecvioronment的getExternalStorageState()方法判断手机是否存在SD卡,并且SD卡是否正常读写。Environment.getExternalStorageState()方法用于获取SD卡的状态,如果手机装有SD卡,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA_MOUNTED
- 判断用户是否授权,如果没有授权,请求授权,如果授权了则下一步。
- 调用Enciroment的getExternalStorageDirectory()方法来获取外部存储器的目录,也就是SD卡的目录(如果知道SD卡目录,可以使用绝对路径表示,但不提倡,因为不同版本可能路径不同。)
- 使用FileInputStream或者FileOutputStream等读写SD卡文件。
提示:为了保证引用程序的安全性,安卓系统规定访问系统的一些关键信息时,必须申请权限,否则程序运行时会因为没有访问系统信息的权限而直接奔溃。根据程序适配的安卓SDK版本的不同,申请权限分为静态申请权限和动态申请权限两种方式。
-
静态申请权限
-
静态申请权限的方式使用与安卓SDK6.0以下的版本。该方式是在清单文件(AndroidManifest.xml)的结点中声明需要申请的权限。以申请SD卡的读权限为例:
<user-permission android:name="android.permission.READ_EXTERANAL_STORAGE"></user-permission>
-
-
动态申请权限
-
当程序适配的安卓SDK为6.0及以上时,安卓改变了权限的管理模式,权限被分为正常权限和危险权限,具体如下
-
正常权限:表示不会直接给用户隐私带来风险的权限,如请求网络的权限。
-
危险权限:表示涉及用户隐私的权限,申请了该权限的应用可能涉及用户隐私信息的数据或资源,也可能对用户存储的数据或者其他应用的操作产生影响。危险权限一共有九组,分别为:
- 位置(LOCATION)、日历(CALENDAR)、照相机(CAMERA)、联系人(CONTACTS)、存储卡(STORAGE)、传感器(SENSORS)、麦克风(MICROPHONE)、电话(PHONE)、短信(SMS)。
-
申请正常权限时使用静态申请权限的方式即可,但是对于一些涉及用户隐私的危险的权限,需要用户的授权才可以使用给,因此危险全年不仅需要在清单文件(AndroidManifest.xml)的结点中添加权限,还需要再代码中动态申请权限,以动态申请SD卡的读权限为例:
ActivityCompat.requestPermissions(MainActivity.this,new String[] {Mainifest.permission.READ_EXTERNAL_STORAGE},1);
requestPermissions()方法中包含3个参数,第一个参数为Context上下文,第二个参数为需要申请的权限,第三个参数为请求码。添加完动态申请权限后,运行程序,界面上会弹出是否允许申请权限的对话框,由用户进行授权。
布局文件同上,java代码如下:
private EditText editText; private TextView textView; private Button buttonSave; private Button buttonRead; private String fileName="content.txt"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1){ for (int i = 0; i < permissions.length; i++) { if (permissions[i].equals("android.permission.READ_EXTERNAL_STORAGE") && grantResults[i] == PackageManager.PERMISSION_GRANTED){ Toast.makeText(this,"授权成功",Toast.LENGTH_LONG).show(); }else { Toast.makeText(this,"获取授权失败,请稍后再试!", Toast.LENGTH_LONG).show(); } } } } private void initView() { editText = findViewById(R.id.edit_content); textView = findViewById(R.id.tv_content); buttonRead = findViewById(R.id.btn_read); buttonSave = findViewById(R.id.btn_save); buttonSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String content = editText.getText().toString(); try { FileOutputStream fos = openFileOutput(fileName,MODE_PRIVATE); fos.write(content.getBytes(StandardCharsets.UTF_8)); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); buttonRead.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { FileInputStream fis = openFileInput(fileName); byte[] bytes = new byte[fis.available()]; fis.read(bytes); String content = new String(bytes); //textView.setText(content); textView.setText("nihaohifdsajf"); fis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } });
-
此处说明一点,在安卓8.0的环境下可以完美运行,能够正常保存读取文件,但是高版本安卓13就不能正常流畅的运行,只能保存,但是读取就会出错。
SharedPreferences保存用户名和密码
-
- 这个类主要可以通过保存一个xml文件到安卓内存中,可以实现简单的登录等操作。保证了运行的流程性。
MainActivity.java代码
package com.example.administrator.chart0704;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
private TextView tvRegister;
private TextView tvFindPwd;
private EditText editName;
private EditText editPwd;
private Button btnLogin;
private String userName;
private String psw;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
Map<String, String> uerInfo = SPSaveInfo.getInfoFromSP(this);
if (uerInfo != null) {
editName.setText(uerInfo.get("userName"));
editPwd.setText(uerInfo.get("userPwd"));
}
}
private void initView() {
tvRegister = (TextView) findViewById(R.id.tv_register);
editName = (EditText) findViewById(R.id.et_user_name);
editPwd = (EditText) findViewById(R.id.et_psw);
tvRegister = (TextView) findViewById(R.id.tv_register);
tvFindPwd = (TextView) findViewById(R.id.tv_find_psw);
btnLogin = (Button) findViewById(R.id.btn_login);
}
private void initListener() {
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
userName = editName.getText().toString().trim();
psw = editPwd.getText().toString();
if (userName.isEmpty() || psw.isEmpty()) {
Toast.makeText(MainActivity.this, "用户名或密码不能为空", Toast.LENGTH_SHORT).show();
return;
} else {
Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
boolean isSave = SPSaveInfo.saveInfoToSP(MainActivity.this, userName, psw);
if (isSave) {
Toast.makeText(MainActivity.this, "保存成功", Toast.LENGTH_SHORT).show();
}
}
}
});
}
}
MainActivityLayout.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<ImageView
android:id="@+id/iv_head"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="70dp"
android:background="@drawable/defaultuser_icon" />
<EditText
android:id="@+id/et_user_name"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:layout_marginTop="35dp"
android:background="@drawable/textview_borders"
android:drawableLeft="@drawable/user_name_icon"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:hint="请输入用户名"
android:paddingLeft="8dp"
android:singleLine="true"
android:textColor="#000000"
android:textColorHint="#a3a3a3"
android:textSize="14sp" />
<EditText
android:id="@+id/et_psw"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:background="@drawable/textview_borders"
android:layout_marginTop="5dp"
android:drawableLeft="@drawable/psw_icon"
android:drawablePadding="10dp"
android:hint="请输入密码"
android:inputType="textPassword"
android:paddingLeft="8dp"
android:singleLine="true"
android:textColor="#000000"
android:textColorHint="#a3a3a3"
android:textSize="14sp" />
<Button
android:id="@+id/btn_login"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:layout_marginTop="15dp"
android:background="@color/colorPrimary"
android:text="登 录"
android:textColor="@android:color/white"
android:textSize="18sp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="35dp"
android:layout_marginRight="35dp"
android:layout_marginTop="8dp"
android:gravity="center_horizontal"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_register"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:padding="8dp"
android:text="立即注册"
android:textColor="@color/colorPrimary"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_find_psw"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:padding="8dp"
android:text="找回密码?"
android:textColor="@color/colorPrimary"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
SPSaceInfo.java文件
public class SPSaveInfo {
public static boolean saveInfoToSP(Context context, String userName, String userPwd) {
SharedPreferences preferences = context.getSharedPreferences("data", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("userName", userName);
editor.putString("userPwd", userPwd);
editor.commit();
return true;
}
public static Map<String, String> getInfoFromSP(Context context) {
HashMap<String, String> hashMap = new HashMap<>();
SharedPreferences preferences = context.getSharedPreferences("data", Context.MODE_PRIVATE);
String userName = preferences.getString("userName", "");
String userPwd = preferences.getString("userPwd", "");
hashMap.put("userName", userName);
hashMap.put("userPwd", userPwd);
return hashMap;
}
}
执行后可以发现点击登录之后会在文件管理器中发现有保存了xml文件。