安卓day26数据存储和界面展现 layout logcat 读写 剩余容量 访问权限 openFileOutput SharedPreference xml文件读写 Preferenece...

一、排坑

android:showAsAction报错

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        app:showAsAction="never"
        android:title="@string/action_settings"/>
</menu>

捕获异常

            catch (Exception e) {
                // TODO Auto-generated catch block
                Log.e(TAG, e.getMessage());
            }

 No such file or directory

private String path= Environment.getExternalStorageDirectory()+"/ahmk/";
private String filename=path+"info.txt";
File dir = new File(path);
File file = new File(filename);
if(!dir.exists()){ 
  dir.mkdirs();
}

java.lang.SecurityException: MODE_WORLD_READABLE no longer supported

Starting from N(N is for Nougat), attempting to use this mode will throw a SecurityException.

Assets文件夹

InputStream is = getAssets().open("weather.xml");

二、常见布局

相对布局

RelativeLayout
  • 组件默认左对齐、顶部对齐
  • 设置组件在指定组件的右边

     android:layout_toRightOf="@id/tv1"
  • 设置在指定组件的下边

     android:layout_below="@id/tv1"
  • 设置右对齐父元素

     android:layout_alignParentRight="true"
  • 设置与指定组件右对齐

     android:layout_alignRight="@id/tv1"

线性布局

LinearLayout
  • 指定各个节点的排列方向

     android:layout_alignRight="@id/tv1"
  • 设置右对齐

     android:layout_gravity="right"
  • 当竖直布局时,只能左右对齐和水平居中,顶部底部对齐竖直居中无效
  • 当水平布局时,只能顶部底部对齐和竖直居中
  • 使用match_parent时注意不要把其他组件顶出去
  • 线性布局非常重要的一个属性:权重

     android:layout_gravity="right"
  • 权重设置的是按比例分配剩余的空间

帧布局

FrameLayout
  • 默认组件都是左对齐和顶部对齐,每个组件相当于一个div
  • 可以更改对齐方式

     android:layout_gravity="right"
  • 不能相对于其他组件布局

表格布局

TableLayout
  • 每个节点是一行,它的每个子节点是一列
  • 表格布局中的节点可以不设置宽高,因为设置了也无效

    • 根节点的子节点宽为匹配父元素,高为包裹内容
    • 节点的子节点宽为包裹内容,高为包裹内容
    • 以上默认属性无法修改
  • 根节点中可以设置以下属性,表示让第1列拉伸填满屏幕宽度的剩余空间

     android:layout_gravity="right"

绝对布局

AbsoluteLayout
  • 直接指定组件的x、y坐标

     android:layout_x="144dp"
     android:layout_y="154dp"

 

三、logcat

  • 日志信息总共分为5个等级
    • verbose
    • debug
    • info
    • warn
    • error
  • 定义过滤器方便查看
  • System.out.print输出的日志级别是info,tag是System.out
  • Android提供的日志输出api

      Log.v(TAG, "加油吧,童鞋们");
      Log.d(TAG, "加油吧,童鞋们");
      Log.i(TAG, "加油吧,童鞋们");
      Log.w(TAG, "加油吧,童鞋们");
      Log.e(TAG, "加油吧,童鞋们");

 

四、内部存储空间中读写文件

  • Ram内存:运行内存,相当于电脑的内存
  • Rom内存:内部存储空间,相当于电脑的硬盘
  • sd卡:外部存储空间,相当于电脑的移动硬盘
  • 应用只能在自己的包名目录下创建文件,不能到别人家去创建

使用路径api读写文件

  • getFilesDir()得到的file对象的路径是data/data/com.itheima.rwinrom2/files
    • 存放在这个路径下的文件,只要你不删,它就一直在
  • getCacheDir()得到的file对象的路径是data/data/com.itheima.rwinrom2/cache

    • 存放在这个路径下的文件,当内存不足时,有可能被删除
  • 系统管理应用界面的清除缓存,会清除cache文件夹下的东西,清除数据,会清除整个包名目录下的东西

public class MainActivity extends Activity {

    private EditText et_name;
    private EditText et_pass;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        et_name = (EditText) findViewById(R.id.et_name);
        et_pass = (EditText) findViewById(R.id.et_pass);
        
        readAccount();
    }

    public void readAccount(){
        File file = new File(getCacheDir(), "info.txt");
        //File file = new File("data/data/com.example.index42.rwinrom/info.txt");
        if(file.exists()){
            try {
                FileInputStream fis = new FileInputStream(file);
                //把字节流转换成字符流
                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                //读取txt文件里的用户名和密码
                String text = br.readLine();
                String[] s = text.split("##");
                
                et_name.setText(s[0]);
                et_pass.setText(s[1]);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void login(View v){
        String name = et_name.getText().toString();
        String pass = et_pass.getText().toString();
        
        CheckBox cb = (CheckBox) findViewById(R.id.cb);
        //判断选框是否被勾选
        if(cb.isChecked()){
            //data/data/com.itheima.rwinrom:这就是内部存储空间的路径
            File file = new File(getCacheDir(), "info.txt");
            //File file = new File("data/data/com.example.index42.rwinrom/info.txt");
            FileOutputStream fos;
            try {
                fos = new FileOutputStream(file);
                fos.write((name + "##" + pass).getBytes());
                fos.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        //创建并显示吐司对话框
        Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
    }
}

 

查看data/data内文件

五、外部存储读写数据

4.4系统及以上的手机将机身存储存储(手机自身带的存储叫做机身存储)在概念上分成了”内部存储internal” 和”外部存储external” 两部分。

public class MainActivity extends Activity {

    private EditText et_name;
    private EditText et_pass;
    private static final String TAG = "MainActivity";
    private String path= Environment.getExternalStorageDirectory()+"/ahmk/";
    private String filename=path+"info.txt";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        et_name = (EditText) findViewById(R.id.et_name);
        et_pass = (EditText) findViewById(R.id.et_pass);

        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED  ){
            //申请权限
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},1);
        }else {
            //把动作告诉系统
            readAccount();
        }
    }

    public void readAccount(){
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            File file = new File(filename);
            if(file.exists()){
                try {
                    FileInputStream fis = new FileInputStream(file);
                    //把字节流转换成字符流
                    BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                    //读取txt文件里的用户名和密码
                    String text = br.readLine();
                    String[] s = text.split("##");
                    
                    et_name.setText(s[0]);
                    et_pass.setText(s[1]);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    public void login(View v){
        CheckBox cb = (CheckBox) findViewById(R.id.cb);
        //判断选框是否被勾选
        if(cb.isChecked()){
            if (ContextCompat.checkSelfPermission(MainActivity.this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
                //申请权限
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},2);
            }else {
                //把动作告诉系统
                writeAccount();
            }
        }
        
        //创建并显示吐司对话框
        Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
    }
    public void writeAccount(){
        //MEDIA_UNKNOWN:不能识别sd卡
        //MEDIA_REMOVED:没有sd卡
        //MEDIA_UNMOUNTED:sd卡存在但是没有挂载
        //MEDIA_CHECKING:sd卡正在准备
        //MEDIA_MOUNTED:sd卡已经挂载,可用
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            //返回一个File对象,其路径是sd卡的真实路径
            //File file = new File(Environment.getExternalStorageDirectory(), "ahmk/info.txt");
            File dir = new File(path);
            File file = new File(filename);
            try {
                if(!dir.exists()){
                    dir.mkdirs();
                }
//                if (!file.exists()) {
//                    file.createNewFile();
//                }
//                FileWriter fw = new FileWriter(file);
//                BufferedWriter output = new BufferedWriter(fw);
//                String name = et_name.getText().toString();
//                String pass = et_pass.getText().toString();
//                output.write(name + "##" + pass);
//                output.close();
                FileOutputStream fos = new FileOutputStream(file);
                String name = et_name.getText().toString();
                String pass = et_pass.getText().toString();
                fos.write((name + "##" + pass).getBytes());
                fos.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                Log.e(TAG, e.getMessage());
            }
        }
        else{
            Toast.makeText(this, "sd卡不可用哟亲么么哒", Toast.LENGTH_SHORT).show();
        }
    }
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode){
            case 1:
                //权限回调
                if (grantResults[0]==PackageManager.PERMISSION_GRANTED&&grantResults[1]==PackageManager.PERMISSION_GRANTED){
                    readAccount();
                }else {
                    //提示用户权限未被授予
                    Log.e("MainActivity","未授予权限");
                }
                break;
            case 2:
                if (grantResults[0]==PackageManager.PERMISSION_GRANTED&&grantResults[1]==PackageManager.PERMISSION_GRANTED){
                    writeAccount();
                }else {
                    //提示用户权限未被授予
                    Log.e("MainActivity","未授予权限");
                }
                break;

        }
    }
}

使用FileOutputStream:

File foutput = new File(file_location_string);
FileOutputStream fos = new FileOutputStream(foutput);
BufferedWriter output = new BufferedWriter(new OutputStreamWriter(fos));
output.write("Buffered Content");
output.close();

使用FileWriter:

FileWriter fstream = new FileWriter(file_location_string);
BufferedWriter output = new BufferedWriter(fstream);
output.write("Buffered Content");
output.close();

根据Java的接口规范:
FileOutputStream是用于写入原始字节流比如图片流数据。如果是要写入字符流,则应该考虑使用FileWriter。

六、获取sd卡剩余容量

public class MainActivity extends Activity {

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        File path = Environment.getExternalStorageDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize;
        long totalBlocks;
        long availableBlocks;
        
        //获取当前系统版本的等级
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){
             blockSize = stat.getBlockSizeLong();
             totalBlocks = stat.getBlockCountLong();
             availableBlocks = stat.getAvailableBlocksLong();
        }
        else{
            blockSize = stat.getBlockSize();
            totalBlocks = stat.getBlockCount();
            availableBlocks = stat.getAvailableBlocks();
        }
        
        TextView tv = (TextView) findViewById(R.id.tv);
        tv.setText(formatSize(availableBlocks * blockSize));
    }

    private String formatSize(long size) {
        return Formatter.formatFileSize(this, size);
    }

}

七、文件的访问权限

  • 在Android中,每一个应用是一个独立的用户
  • drwxrwxrwx
  • 第1位:d表示文件夹,-表示文件
  • 第2-4位:rwx,表示这个文件的拥有者用户(owner)对该文件的权限
    • r:读
    • w:写
    • x:执行
  • 第5-7位:rwx,表示跟文件拥有者用户同组的用户(grouper)对该文件的权限
  • 第8-10位:rwx,表示其他用户组的用户(other)对该文件的权限

openFileOutput的四种模式

Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND
Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。

八、SharedPreference

Android的四大数据存储方式之一“SharedPreference”,其他三个分别是SQLite、Content Provider 和 File

一般使用SharedPreference来存储应用程序的配置信息。它一般存储在应用程序的私有存储区,文件权限是私有的。也就是说只能供写入者读取。它使用键/值(NVP机制)来存储数据。支持的数据类型(boolean、int、float、long和String)。它存储在应用程序的私有目录下(data/data/包名 /shared_prefs/)自定义的XML文件中。

取数据

    public void readAccount2(){
        SharedPreferences sp = getSharedPreferences("info", MODE_PRIVATE);
        String name = sp.getString("name", "");
        String pass = sp.getString("pass", "");

        et_name.setText(name);
        et_pass.setText(pass);
    }

写数据

    public void login2(View v){

        String name = et_name.getText().toString();
        String pass = et_pass.getText().toString();

        CheckBox cb = (CheckBox) findViewById(R.id.cb);
        //判断选框是否被勾选
        if(cb.isChecked()){
            //使用sharedPreference来保存用户名和密码
            //路径在data/data/com.itheima.sharedpreference/share_
            SharedPreferences sp = getSharedPreferences("info", MODE_PRIVATE);
            //拿到sp的编辑器
            SharedPreferences.Editor ed = sp.edit();
            ed.putString("name", name);
            ed.putString("pass", pass);
            //提交
            ed.commit();
        }

        //创建并显示吐司对话框
        Toast.makeText(this, "登录成功", 0).show();
    }

 

 九、生成XML文件备份短信

public class MainActivity extends Activity {

    List<Message> smsList;
    private String path= Environment.getExternalStorageDirectory()+"/ahmk/";
    private String filename=path+"sms.xml";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //虚拟10条短信
        smsList = new ArrayList<Message>();
        for(int i = 0; i < 10; i++){
            Message sms = new Message("小志好棒" + i, System.currentTimeMillis() + "", "138"+i+i, "1");
            smsList.add(sms);
        }
    }

    public void click(View v){
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
            //申请权限
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
        }else {
            //把动作告诉系统
            save();
        }
    }
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode){
            case 1:
                //发短信权限回调
                if (grantResults[0]==PackageManager.PERMISSION_GRANTED){
                    save();
                }else {
                    //提示用户权限未被授予
                    Log.d("MainActivity","未授予发短信权限");
                }
                break;
        }
    }
    public void save(){
        //在内存中把xml备份短信的格式拼接出来
        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>");
        sb.append("<messages>");
        for (Message sms : smsList) {
            sb.append("<sms>");
            
            sb.append("<body>");
            sb.append(sms.getBody());
            sb.append("</body>");
            
            sb.append("<date>");
            sb.append(sms.getDate());
            sb.append("</date>");
            
            sb.append("<type>");
            sb.append(sms.getType());
            sb.append("</type>");
            
            sb.append("<address>");
            sb.append(sms.getAddress());
            sb.append("</address>");
            
            sb.append("</sms>");
        }
        sb.append("</messages>");
        
        File file = new File(filename);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(sb.toString().getBytes());
            fos.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
public class Message {

    private String body;
    private String date;
    private String address;
    private String type;
    public String getBody() {
        return body;
    }
    public void setBody(String body) {
        this.body = body;
    }
    public String getDate() {
        return date;
    }
    public void setDate(String date) {
        this.date = date;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public Message(String body, String date, String address, String type) {
        super();
        this.body = body;
        this.date = date;
        this.address = address;
        this.type = type;
    }
}

使用XMl序列化器生成xml文件

    public void save2(){
        //使用xml序列化器生成xml文件
        //1.拿到序列化器对象
        XmlSerializer xs = Xml.newSerializer();
        //2.初始化
        File file = new File(filename);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            //enconding:指定用什么编码生成xml文件
            xs.setOutput(fos, "utf-8");

            //3.开始生成xml文件
            //enconding:指定头结点中的enconding属性的值
            xs.startDocument("utf-8", true);

            xs.startTag(null, "message");

            for (Message sms : smsList) {
                xs.startTag(null, "sms");

                xs.startTag(null, "body");
                xs.text(sms.getBody() + "<body>");
                xs.endTag(null, "body");

                xs.startTag(null, "date");
                xs.text(sms.getDate());
                xs.endTag(null, "date");

                xs.startTag(null, "type");
                xs.text(sms.getType());
                xs.endTag(null, "type");

                xs.startTag(null, "address");
                xs.text(sms.getAddress());
                xs.endTag(null, "address");

                xs.endTag(null, "sms");
            }

            xs.endTag(null, "message");

            //告诉序列化器,文件生成完毕
            xs.endDocument();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

十、pull解析xml文件

事件类型主要有五种

  • START_DOCUMENT:xml头的事件类型
  • END_DOCUMENT:xml尾的事件类型
  • START_TAG:开始节点的事件类型
  • END_TAG:结束节点的事件类型
  • TEXT:文本节点的事件类型
public class MainActivity extends Activity {

    List<City> cityList;
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void click(View v){
        //拿到pull解析器对象
        XmlPullParser xp = Xml.newPullParser();
        //初始化
        try {
            //获取到src文件夹下的资源文件
            InputStream is = getAssets().open("weather.xml");
            //InputStream is = getClassLoader().getResourceAsStream("weather.xml");
            xp.setInput(is, "utf-8");
            //获取当前节点的事件类型,通过事件类型的判断,我们可以知道当前节点是什么节点,从而确定我们应该做什么操作
            int type = xp.getEventType();
            City city = null;
            while(type != XmlPullParser.END_DOCUMENT){
                //根据节点的类型,要做不同的操作
                switch (type) {
                case XmlPullParser.START_TAG:
                    //                    获取当前节点的名字
                    if("weather".equals(xp.getName())){
                        //创建city集合对象,用于存放city的javabean
                        cityList = new ArrayList<City>();
                    }
                    else if("city".equals(xp.getName())){
                        //创建city的javabean对象
                        city = new City();
                    }
                    else if("name".equals(xp.getName())){
                        //                获取当前节点的下一个节点的文本
                        String name = xp.nextText();
                        city.setName(name);
                    }
                    else if("temp".equals(xp.getName())){
                        //                获取当前节点的下一个节点的文本
                        String temp = xp.nextText();
                        city.setTemp(temp);
                    }
                    else if("pm".equals(xp.getName())){
                        //                获取当前节点的下一个节点的文本
                        String pm = xp.nextText();
                        city.setPm(pm);
                    }
                    break;
                case XmlPullParser.END_TAG:
                    if("city".equals(xp.getName())){
                        //把city的javabean放入集合中
                        cityList.add(city);
                    }
                    break;

                }
                //把指针移动到下一个节点,并返回该节点的事件类型
                type = xp.next();
            }
            for (City c : cityList) {
                Log.e(TAG, c.toString());
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
public class City {
    private String name;
    private String temp;
    private String pm;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getTemp() {
        return temp;
    }
    public void setTemp(String temp) {
        this.temp = temp;
    }
    public String getPm() {
        return pm;
    }
    public void setPm(String pm) {
        this.pm = pm;
    }
    @Override
    public String toString() {
        return "City [name=" + name + ", temp=" + temp + ", pm=" + pm + "]";
    }
}

十一、Preferenece

Preference直译为偏好,博友建议翻译为首选项。一些配置数据,一些我们上次点击选择的内容,我们希望在下次应用调起的时候依旧有效,无须用户再一次进行配置或选择。Android提供preference这个键值对的方式来处理这样的情况,自己主动保存这些数据,并立时生效,Android提供一种类似layout的方式来进行Prefernce的布局。

 

public class MainActivity extends PreferenceActivity {
    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
        //通过资源id指定要把哪个preference的内容显示至界面
        addPreferencesFromResource(R.xml.pref);
        Preference pf = findPreference("pre");
        pf.setSummary("这是修改过后的摘要:小志和b哥不能说的故事");
    }
}
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    <Preference 
        android:key="pre"
        android:title="这是大标题"
        android:summary="这是摘要"
        />

</PreferenceScreen>

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/index42/p/10438061.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值