4.数据持久化->SharedPreference 内部空间 外部空间
安卓手机只能读写在/data/data 或者sdcard中
SharedPreference
四大组件之学习contentProvider之前要学习数据持久化->SharedPreference
SharedPreference轻量级数据存储,一般存储app设置的一些信息,例如用户设置的一些是否自动推送等功能
xml文件 K-V形式
SharedPreferences 对文件"读"的操作
SharedPreferences.Editor 对文件"写"的操作
我们通过这种形式存储的文件全部存储在这个路径下:
/data/data/<applicationId>/shared_prefs 要root权限才能打开
例子:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <EditText android:id="@+id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入内容"/> <Button android:id="@+id/storeBtn" android:text="保存" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <Button android:id="@+id/showBtn" android:text="显示" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:id="@+id/TextView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text=""/> </LinearLayout>
package com.example.datasave1; import androidx.appcompat.app.AppCompatActivity; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity { Button storeBtn; Button showBtn; EditText editText; TextView textView; SharedPreferences msharedPreferences; SharedPreferences.Editor meditor; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); storeBtn = findViewById(R.id.storeBtn); showBtn = findViewById(R.id.showBtn); textView = findViewById(R.id.TextView1); editText = findViewById(R.id.text1); //第一个参数是文件名,第二个参数是文件的操作模式 msharedPreferences = getSharedPreferences("data",MODE_PRIVATE); meditor = msharedPreferences.edit(); //存储 storeBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { meditor.putString("namehhh",editText.getText().toString()); meditor.apply(); } }); //显示 showBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) {
//取的时候值缺省就行了 textView.setText(msharedPreferences.getString("namehhh","")); } }); } }
Android存储概念
Android存储有内部存储和外部存储(公有目录 私有目录(随应用卸载而被删除))
内部存储:随应用卸载被删除
/data/data/<applicationId>/shared_prefs
/data/data/<applicationId>/databases
/data/data/<applicationId>/files
/data/data/<applicationId>/cache
外部存储:
公有目录:Environment.getExternalStoragePublicDirectory(int type)
私有目录:/mnt/sdcard/Android/data/data/<application>/cache
/mnt/sdcard/Android/data/data/<application>/files
File 内部存储
FileOutputStream FileInputStream

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/img" android:layout_width="100dp" android:layout_height="100dp" android:paddingTop="50dp" android:src="@drawable/ic_baseline_ac_unit_24"/> <TextView android:text="QQ" android:paddingTop="37dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="50dp" android:layout_toRightOf="@+id/img"/> <EditText android:id="@+id/edit1" android:layout_width="250dp" android:layout_height="wrap_content" android:hint="QQ号码" android:textSize="20dp" android:padding="30dp" android:inputType="number" android:layout_below="@+id/img"/> <EditText android:id="@+id/edit2" android:layout_width="250dp" android:layout_height="wrap_content" android:hint="密码" android:textSize="20dp" android:padding="30dp" android:inputType="textPassword" android:layout_below="@+id/edit1"/> <Button android:id="@+id/loginBtn" android:layout_width="250dp" android:layout_height="wrap_content" android:layout_below="@+id/edit2" android:text="保存数据"/> <Button android:id="@+id/showBtn" android:layout_marginTop="50dp" android:layout_width="250dp" android:layout_height="wrap_content" android:layout_below="@+id/loginBtn" android:text="显示数据" tools:ignore="OnClick" /> <TextView android:id="@+id/showText" android:paddingTop="37dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="50dp" android:layout_below="@+id/showBtn"/> </RelativeLayout> </LinearLayout>
package com.example.qqlogindemo; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; /* * 为什么我们直接写一个文件名的时候,去写文件,报出的异常是read——only * 其实呢,在Android系统中,每一个应用呢就是一个用户,每个用户它的权限是特定的,不可操作其他应用的内容 * 以“/”为根目录,它跟windows不一样 * */ public class MainActivity extends AppCompatActivity { EditText account; EditText password; Button button; TextView showText; Button showBtn; File file; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //第一步找到控件 initView(); //设置点击事件 initListener(); //回显数据 showAccountAndPassword(); } //第一步找到控件 private void initView(){ account = findViewById(R.id.edit1); password = findViewById(R.id.edit2); button = findViewById(R.id.loginBtn); showBtn = findViewById(R.id.showBtn); showText = findViewById(R.id.showText); } //设置点击事件 处理登录事件 private void initListener(){ button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //拿到账号和密码 String accountNum = String.valueOf(account.getText()); String myPassword = String.valueOf(password.getText()); //判空 以及提示用户 if (TextUtils.isEmpty(accountNum) || TextUtils.isEmpty(myPassword)){ Toast.makeText(getApplicationContext(),"账号或密码输入为空",Toast.LENGTH_SHORT).show(); }else { //保存账号和密码 saveAccountAndPawword(accountNum,myPassword); } } }); } //保存账号和密码 void saveAccountAndPawword(String accountNum,String myPassword){ try { //在SD卡下新建一个文件夹 //在Android开发时,一般我们使用以下代码获取储存路径. //"/data/data/com.example.qqlogindemo"当前app路径咋获取?? this.getFilesDir() //getFilesDir拿到的路径是 /data/user/0/com.example.qqlogindemo/files //获取缓存文件的路径 getCacheDir() Log.e("getFilesDir******", String.valueOf(this.getFilesDir())); File dir = new File(this.getFilesDir(),"bagabaga"); if (!dir.exists()){ dir.mkdirs(); } //创建文件 file = new File(dir,"hello.txt"); if (!file.exists()){ file.createNewFile(); } FileOutputStream fos = new FileOutputStream(file); //以特定的格式存储 fos.write((accountNum+"***"+myPassword).getBytes()); Toast.makeText(getApplicationContext(),"数据保存成功",Toast.LENGTH_SHORT).show(); Log.e("TAG****: ","保存用户信息"); //fos.close(); } catch (Exception e) { e.printStackTrace(); } } //显示已保存的账号密码 void showAccountAndPassword(){ showBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { //输入流 FileInputStream ips = new FileInputStream(file.getPath()); Log.e("file.getPath()*****",file.getPath()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(ips)); //读一行 String line = bufferedReader.readLine(); //fos.write((accountNum+"***"+myPassword).getBytes()); //上面这行代码是我们之前保存的数据形式,也就是说,我们拿到数据以后要对数据进行切割 String[] split = line.split("\\*\\*\\*"); String account = split[0]; String password = split[1]; Toast.makeText(getApplicationContext(),"账号是: "+account+"密码是: "+password,Toast.LENGTH_SHORT).show(); showText.setText("账号是: "+account+"密码是: "+password); } catch (Exception e) { e.printStackTrace(); } } }); } }
File 外部存储(SD卡)
package com.example.qqlogindemo; import static com.google.android.material.internal.ContextUtils.getActivity; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.storage.StorageManager; import android.os.storage.StorageVolume; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class SDCardDemoActivity extends AppCompatActivity { Button loginBtn1; EditText edit3; //不光要在AndroidMainfest.xml中申请权限还要在这动态申请权限 //**************************动态申请权限************************************************* private static final int REQUEST_EXTERNAL_STORAGE = 1; private static String[] PERMISSIONS_STORAGE = { "android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE" }; //************************动态申请权限的方法 写完之后直接在onCreate方法中直接使用就行了********* public static void verifyStoragePermissions(Activity activity) { try { //检测是否有写的权限 int permission = ActivityCompat.checkSelfPermission(activity, "android.permission.WRITE_EXTERNAL_STORAGE"); if (permission != PackageManager.PERMISSION_GRANTED) { // 没有写的权限,去申请写的权限,会弹出对话框 ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE); } } catch (Exception e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sdcard_demo); loginBtn1 = findViewById(R.id.loginBtn1); edit3 = findViewById(R.id.edit3); verifyStoragePermissions(this); loginBtn1.setOnClickListener(new View.OnClickListener() { @SuppressLint("NewApi") @RequiresApi(api = Build.VERSION_CODES.M) @Override public void onClick(View view) { //要在AndroidMainfest.xml的application标签头顶上中赋予读写权限 //<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> //<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> File filePath = new File("/sdcard"); File file = new File(filePath, "hello.txt"); try { if (!file.exists()) { //创建文件 file.createNewFile(); } FileOutputStream fos = new FileOutputStream(file); //以特定形式存储数据 String s = edit3.getText().toString(); fos.write(s.getBytes()); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); } }

不同的手机厂商以及车载平台的sd卡文件夹名不一样,那我们咋整?
File filePath = new File(String.valueOf(Environment.getExternalStorageDirectory()));
判断SD卡是否挂载
if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { // sd card 可用 Log.e("sd是否挂载?: ","可用!"); }else { // 当前不可用 Log.e("sd是否挂载?: ","不可用!"); }
获取SD卡剩余空间
//获取SD卡路径 File path = Environment.getExternalStorageDirectory(); //获取外部存储空间的所有信息 StatFs stat = new StatFs(path.getPath()); long blockSize; long totalBlocks; long availableBlocks; blockSize = stat.getBlockSize(); //获取空间块大小 totalBlocks = stat.getBlockCount(); //获取空间块数量 availableBlocks = stat.getAvailableBlocks(); //获取可用空间

浙公网安备 33010602011771号