中级实训Android学习记录——RecyclerView、Android存储

学习记录 2020/11/26

RecyclerView

  • RecyclerView

RecyclerView在之前就学习过,但用的时候才发现没有学习记录,所以在这里自行总结。

使用RecyclerView建立列表视图的步骤:

  1. 创建一个activity(Android studio会帮你顺便声明并创建layout),在activity的xml文件中建立一个RecyclerView

    // 我们在activity_linear_recycler.xml中声明一个RecyclerView
        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:id="@+id/rv_main"
            android:background="@color/purple_700"/>
    
  2. 建立一个列表的一个小项所用的layout

    // 这里我们建立的是layout_linear_item.xml,里面只有一个简单的TextView
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:textColor="#000"
            android:textSize="20sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
  3. 建立使用小项layout的RecyclerViewAdapter

    public class LinearAdapter extends RecyclerView.Adapter<LinearAdapter.LinearViewHolder> {
    // 自己创建一个ViewHolder并将它传入Adapter的模板参数中
        private Context mContext;
    
        public  LinearAdapter(Context context) {
            this.mContext = context;
        }
    
        
        // 注意这里的返回值也要改成自己的ViewHolder
        @NonNull
        @Override
        public LinearAdapter.LinearViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new LinearViewHolder(LayoutInflater.from(mContext).inflate(R.layout.layout_linear_item, parent, false));
        }
    
        // 注意这里传入的参数也要改成自己的ViewHolder
        @Override
        public void onBindViewHolder(@NonNull LinearAdapter.LinearViewHolder holder, int position) {
            holder.textView.setText("Hello World!");
        }
    
        // 自定义一个列表的小项的个数,一般我们可以使用一个列表来声明
        @Override
        public int getItemCount() {
            return 30;
        }
    
        // 建立一个ViewHolder来自定义小项
        class LinearViewHolder extends  RecyclerView.ViewHolder {
    
            private TextView textView;
    
            public LinearViewHolder(@NonNull View itemView) {
                super(itemView);
                textView = itemView.findViewById(R.id.tv_title);
            }
        }
    
    }
    
  4. 最后就可以在Activity中直接使用RecyclerView

// 先声明一个变量 private RecyclerView mRvMain;
        mRvMain = findViewById(R.id.rv_main);
        mRvMain.setLayoutManager(new LinearLayoutManager(LinearRecyclerActivity.this));
       
        mRvMain.setAdapter(new LinearAdapter(LinearRecyclerActivity.this));
  1. 加每个小项之间的分隔线的方法

    1. 在Activity.java中自定义一个类并继承ItemDecoration

      class myDecoration extends RecyclerView.ItemDecoration {
              @Override
              public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
                  super.getItemOffsets(outRect, view, parent, state);
                  outRect.set(0, 0, 0, getResources().getDimensionPixelOffset(R.dimen.dividerHeight));
              }
          }
      // 这里的set函数的四个参数代表的方向依次是左、上、右、下
      // 所以我们的效果其实是在每个item的下方加一个R.dimen.dividerHeight大小的横线
      
    2. 调用RecyclerView的addItemDecoration方法即可

    mRvMain.addItemDecoration(new myDecoration());
    

Android 存储

  • SharedPreferences 轻量级数据存储

    • 一般存储形式表现为以Key-Value的形式,存储在XML文件中
    • 用SharedPreferences来读取xml文件
    • 用SharedPreferences.Editor来更改xml文件
  • SharedPreferences 用法

    • 获取数据

    • private SharedPreferences mSharedPreferences;
      mSharedPreferences = getSharedPreferences("data", MODE_PRIVATE); // 这里第一个参数表示文件名,第二个参数表示文件打开的模式,一般使用MODE_PRIVATE
      
      // 假设已经使用Editor输入数据,key="name"
      
      String data = mSharedPreferences.getString("name", "");
      
    • 输入数据

    • private SharedPreferences.Editor mEditor;
      mEditor = mSharedPreferences.edit();
      //调用put类型的方法来输入key-value数据
      mEditor.putString("name", "haha")
      // 调用apply或者commit进行数据更新
       // apply是异步
       // commit是同步
      mEditor.apply(); 
      
    • SharedPreferences的存储目录

      • /data/data//shared_prefs
    • SharedPreferences的存储目录的查看方式

    • 命令行下

    • // 使用android的shell
      adb shell
      // 调用run-as 后面加上自己的完整applicaiton的名称
      run-as com.skypan.helloworld
      // 进入目录shared_prefs
      cd shared_prefs
      // 在命令行中列出data.xml的内容
      cat data.xml
      
  • 存储概念

    • Android存储分为
      • 内部存储(Internal Storage)
        • 内部存储会随应用的卸载而删除,如
          • /data/data//shared_prefs
          • /data/data//databases
          • /data/data//files
          • /data/data//cache
        • 利用的方法可以是
          • context.getFilesDir()获得目录/data/data//files
          • context.getCacheDir()获得目录/data/data//cache
      • 外部存储(External Storage)
        • 公有目录
          • 公有目录的获取
            • Environment.getExternalStoragePublicDirectory(int type)
            • type可以是Environment下的已经定义好的变量
        • 私有目录,随应用的卸载而删除,如
          • /mnt/sdcard/Anroid/data/data//cache
          • /mnt/sdcard/Anroid/data/data//files
  • File内部存储

    • 使用的类

    • FileOutputStream,FileInputStream

    • 存储数据

      private void save(String content) {
      	try {
           FileOutputStream fileOutputStream = openFileOutput("test.txt", MODE_PRIVATE); // 第一个参数代表文件名,第二个参数是文件读写方式
           fileOutputStream.write(content.getBytes());
           // 这里调用的write函数接受的是byte[],所以需要将String对象转换成byte
       } catch (IOException e) {
           // 注意,此时其实丢出的不止是IOException,还有FileNotFoundException,不过这个错误继承了IOException,所以都可以被IOException catch到
           e.printStackTrace();
       } finally { // 无论如何,我们都需要关闭一开始打开的文件
           if (fileOutputStream != null) { 
               // 如果已经打开了,就关闭
               try {
                   fileOutputStream.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }
      }
      

      读取数据

      private String read() {
       FileInputStream fileInputStream = null;
       try {
           FileInputStream fileInputStream = openFileInput("test.txt");
           byte[] buff = new byte[1024];
           StringBuilder sb = new StringBuilder("");
           int len = 0;
           while((len = fileInputStream.read(buff)) > 0) {
               sb.append(new String(buff, 0, len));
               // 从buff的0开始,将len长度的byte做成String加到sb的后面
           }
           return sb.toString();
       } catch (IOException e) {
           e.printStackTrace();
       
           // 默认可能发生错误,直接返回空
           return null;
      }
      
  • File外部存储

    • 使用的类

    • FileOutputStream,FileInputStream,Environment

    • 存储数据

      private void save(String content) {
      	try {
           File dir = new File(Environment.getExternalStorageDirectory(), "skypan");
      // 第一个是找到外部存储目录,第二个参数是文件夹的名字
           if (!dir.exists()) {
               dir.mkdirs();
               // 使用mkdirs而非mkdir是因为他会帮我们创建一系列的文件夹(当我们的文件夹路径很复杂的时候)
           }
           File file = new File(dir, "test.txt");
           if (!file.exists()) {
               file.createNewFile();
           }
           FileOutputStream fileOutputStream = new FileOutputStream(file);
           
           fileOutputStream.write(content.getBytes());
           // 这里调用的write函数接受的是byte[],所以需要将String对象转换成byte
       } catch (IOException e) {
           // 注意,此时其实丢出的不止是IOException,还有FileNotFoundException,不过这个错误继承了IOException,所以都可以被IOException catch到
           e.printStackTrace();
       } finally { // 无论如何,我们都需要关闭一开始打开的文件
           if (fileOutputStream != null) { 
               // 如果已经打开了,就关闭
               try {
                   fileOutputStream.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }
      }
      

      读取数据

      private String read() {
       FileInputStream fileInputStream = null;
       try {
           File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator+"skypan", "test.txt");
           // 第一个参数是我们的文件夹的绝对路径,其中File.separator的值="/",第二个参数是我们的文件名
           fileInputStream = new FileInputStream(file);
           byte[] buff = new byte[1024];
           StringBuilder sb = new StringBuilder("");
           int len = 0;
           while((len = fileInputStream.read(buff)) > 0) {
               sb.append(new String(buff, 0, len));
               // 从buff的0开始,将len长度的byte做成String加到sb的后面
           }
           return sb.toString();
       } catch (IOException e) {
           e.printStackTrace();
       
           // 默认可能发生错误,直接返回空
           return null;
      }
      

      注意,并不能直接使用以上代码,在使用外部存储之前,我们需要先获取外部存储的读写权限

      1. 在AndroidManifest.xml中声明以下语句

        <user-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        
      2. 如果在build.gradle中,我们的sdk版本超过了23,我们还需要动态申请权限

        在build.gradle中查看sdk版本

        compileSdkVersion n
        

        如果$ngeq 23$,就需要动态申请权限,在使用外部存储之前:

        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WIRTE_EXTERNAL_STORAGE}, 1);
        // 第一个参数是调用这个函数的activity(context),第二个参数是申请的是什么权限,第三个是权限返回结果的识别码,如果我们需要得到用户是否确认给予权限,我们需要额外调用方法进行判断
        

      在申请了权限之后,就可以正常的运行之前说的使用外部存储的代码了。

原文地址:https://www.cnblogs.com/lwfing/p/14053985.html