zoukankan      html  css  js  c++  java
  • 20189200余超 2018-2019-2 移动平台应用开发实践第十周作业

    20189200余超 2018-2019-2 移动平台应用开发实践第十周作业

    偏好

    在Android应用中,我们常需要记录用户设置的一些偏好参数,,此时我们就需要用SharedPreferences和Editor将这些信息保存下来,在下次登录时读取。

    SharedPreferences保存的数据主要类似于配置信息格式的数据,因此它保存数据的形式为key-value对,下面我们来看下实例代码。

    首先是界面布局,比较简单,就是一个普通的登陆界面.

    <RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context=".MainActivity" >
    <EditText 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/account"
        />
    <EditText 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/password"
        android:layout_below="@id/account"
        />
    <Button 
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/password"
            android:text="保存参数"
            android:id="@+id/save"
            android:onClick="save"
     />
    </RelativeLayout>
    

    这是自定义的Preferences 类,用来实现数据的保存 ,可在Android的内置存储空间产生一文件。

    import android.R.integer;
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.SharedPreferences.Editor;
    import android.widget.EditText;
    
    public class Preferences {
    
        private Context context;
        public Preferences(Context context)
        {
            this.context=context;
        }
        
        
        public void save(String name, Integer valueOf) 
        {
            //保存文件名字为"shared",保存形式为Context.MODE_PRIVATE即该数据只能被本应用读取
            SharedPreferences preferences=context.getSharedPreferences("shared",Context.MODE_PRIVATE);
            
            Editor editor=preferences.edit();
            editor.putString("name", name);
            editor.putInt("age", valueOf);
            
            editor.commit();//提交数据
        }
    }
    

    下面是Mainactivity的代码。在activity的oncreate阶段我们加载本地的数据。

    import java.util.HashMap;
    import java.util.Map;
    
    import android.R.integer;
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.SharedPreferences;
    import android.view.Menu;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    
        private EditText account,passworad;
        Preferences prefer;//自定义的类
        SharedPreferences preference; 
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            account=(EditText)findViewById(R.id.account);
            passworad=(EditText)findViewById(R.id.password);
            
            //获取本地的数据
           preference=getSharedPreferences("shared", MODE_PRIVATE);
            Map<String, String> map=new HashMap<String, String>();
            map.put("name",preference.getString("name",""));
            map.put("age", String.valueOf(preference.getInt("age", 0)));        
            account.setText(map.get("name"));
            passworad.setText(map.get("age"));
            
        }
    
        //保存文件的方法
        public void save(View v) {
        String name=account.getText().toString();
        String age=passworad.getText().toString();
        prefer=new Preferences(this);
        prefer.save(name,Integer.valueOf(age));
        Toast.makeText(getApplicationContext(), "保存完成", Toast.LENGTH_SHORT).show();
    
        }
        
         @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
    }
    

    我们看一下效果.

    点击保存参数,出现保存完成则说明我们已经保存成功了,在下次登录的时候可以看到这些参数还在。因为记录文件是在内置空间中的,所以我们在SD卡中找不到该文件,

    如果有root权限的手机可以下载个RE文件管理,我们可以再/data/data/的路径找到很多应用程序的内置文件夹,我们可以在这些文件夹中看到一个shared_prefs文件夹,

    里面就有我们刚刚设置而产生的xml文件。

    操作空间

    我们先来考虑这样一个问题:

    打开手机设置,选择应用管理,选择任意一个App,然后你会看到两个按钮,一个是清除缓存,另一个是清除数据,那么当我们点击清除缓存的时候清除的是哪里的数据?当我们点击清除数据的时候又是清除的哪里的数据?读完本文相信你会有答案。

    在android开发中我们常常听到这样几个概念,内存,内部存储,外部存储,很多人常常将这三个东西搞混,那么我们今天就先来详细说说这三个东西是怎么回事?

    内存,我们在英文中称作memory,内部存储,我们称为InternalStorage,外部存储我们称为ExternalStorage,这在英文中本不会产生歧义,但是当我们翻译为中文之后,前两个都简称为内存,于是,混了。

    那么究竟什么是内部存储什么是外部存储呢?

    首先我们打开DDMS,有一个File Explorer,如下:

    彻底理解android中的内部存储与外部存储0

    这里有三个文件夹需要我们重视,一个是data,一个是mnt,一个是storage,我们下面就详细说说这三个文件夹。

    1.内部存储

    data文件夹就是我们常说的内部存储,当我们打开data文件夹之后(没有root的手机不能打开该文件夹),里边有两个文件夹值得我们关注,如下:

    一个文件夹是app文件夹,还有一个文件夹就是data文件夹,app文件夹里存放着我们所有安装的app的apk文件,其实,当我们调试一个app的时候,可以看到控制台输出的内容,有一项是uploading .....就是上传我们的apk到这个文件夹,上传成功之后才开始安装。另一个重要的文件夹就是data文件夹了,这个文件夹里边都是一些包名,打开这些包名之后我们会看到这样的一些文件:

    1.data/data/包名/shared_prefs
    2.data/data/包名/databases
    3.data/data/包名/files

    4.data/data/包名/cache

    如果打开过data文件,应该都知道这些文件夹是干什么用的,我们在使用sharedPreferenced的时候,将数据持久化存储于本地,其实就是存在这个文件中的xml文件里,我们App里边的数据库文件就存储于databases文件夹中,还有我们的普通数据存储在files中,缓存文件存储在cache文件夹中,存储在这里的文件我们都称之为内部存储。

    2.外部存储

    外部存储才是我们平时操作最多的,外部存储一般就是我们上面看到的storage文件夹,当然也有可能是mnt文件夹,这个不同厂家有可能不一样。

    一般来说,在storage文件夹中有一个sdcard文件夹,这个文件夹中的文件又分为两类,一类是公有目录,还有一类是私有目录,其中的公有目录有九大类,比如DCIM、DOWNLOAD等这种系统为我们创建的文件夹,私有目录就是Android这个文件夹,这个文件夹打开之后里边有一个data文件夹,打开这个data文件夹,里边有许多包名组成的文件夹。

    说到这里,我想大家应该已经可以分清楚什么是内部存储什么是外部存储了吧?好,分清楚之后我们就要看看怎么来操作内部存储和外部存储了。

    3.操作存储空间

    首先,经过上面的分析,大家已经明白了,什么是内部存储,什么是外部存储,以及这两种存储方式分别存储在什么位置,一般来说,我们不会自己去操作内部存储空间,没有root权限的话,我们也没法操作内部存储空间,事实上内部存储主要是由系统来维护的。不过在代码中我们是可以访问到这个文件夹的。由于内部存储空间有限,在开发中我们一般都是操作外部存储空间,Google官方建议我们App的数据应该存储在外部存储的私有目录中该App的包名下,这样当用户卸载掉App之后,相关的数据会一并删除,如果你直接在/storage/sdcard目录下创建了一个应用的文件夹,那么当你删除应用的时候,这个文件夹就不会被删除。

    经过以上的介绍,我们可以总结出下面一个表格:

    一目了然,什么是内部存储,什么是外部存储。

    如果按照路径的特征,我们又可以将文件存储的路径分为两大类,一类是路径中含有包名的,一类是路径中不含有包名的,含有包名的路径,因为和某个App有关,所以对这些文件夹的访问都是调用Context里边的方法,而不含有包名的路径,和某一个App无关,我们可以通过Environment中的方法来访问。如下图:

    操作数据库

    public class MainActivity extends AppCompatActivity {
    
        private MyDatabaseHelper dbHelper;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 3); // 执行这句并不会创建数据库文件
            Button btnCreateDatabase = (Button) findViewById(R.id.button);
            btnCreateDatabase.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dbHelper.getWritableDatabase(); // 执行这句才会创建数据库文件
                }
            });
    
        }
    }
    
    public class MyDatabaseHelper extends SQLiteOpenHelper {
    
        public static final String CREATE_BOOK = "create table book (" +
                "id integer primary key autoincrement, " +
                "author text, " +
                "price real," +
                "pages integer, " +
                "name text)";
    
        private Context mContext;
    
        public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
    
            mContext = context;
        }
    
        /**
         * 数据库已经创建过了, 则不会执行到,如果不存在数据库则会执行
         * @param db
         */
        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(CREATE_BOOK); // 执行这句才会创建表
    
            Toast.makeText(mContext, "create succeeded", Toast.LENGTH_SHORT).show();
    
        }
    
        /**
         * 创建数据库时不会执行,增大版本号升级时才会执行到
         * @param db
         * @param oldVersion
         * @param newVersion
         */
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // 在这里面可以把旧的表 drop掉 从新创建新表,
            // 但如果数据比较重要更好的做法还是把旧表的数据迁移到新表上,比如升级qq聊天记录被删掉肯定招骂
            Toast.makeText(mContext, "onUpgrade oldVersion:" + oldVersion + " newVersion:" + newVersion, Toast.LENGTH_SHORT).show();
        }
    }
    

    验证数据库文件是否存在的方法看最后部分

    剩下的工作就是对数据库表的增删改查了

    首先通过下面的代码获得一个引用以便操作数据库

    1 SQLiteDatabase db = dbHelper.getWritableDatabase();

    对于增删改都可以用 db.execSQL(String sql); 来执行sql语句。 例如增加一条记录

    1 db.execSQL("insert into book(name , author, pages, price) values("Android数据库操作指南", "panda fang", 200, 35.5)");

    遇到字符串要转义 有没有觉得很蛋疼, 用下面的方法就好多了

    1 db.execSQL("insert into book(name , author, pages, price) values(?, ? ,? ,? )", new String[]{"Android数据库操作指南", "panda fang", "200", "35.5"});

    sql 中用 ? 占位 后面传入真正的参数, 由于在创建表的时候已经约定pages 和 price字段的数据类型为integer和real, 虽然代码中写的是字符串并不影响,存入数据库会自动处理的。数组嘛,必须与其他的元素类型一致。 这第二个方式是 execSQL(String sql)的重载方法 api是 public void execSQL(String sql, Object[] bindArgs) throws SQLException

    对于查询则要使用 rawQuery(String sql, String[] selectionArgs) , 因为 execSQL返回void ,而查询需要访问查询结果。方法如下:

    Cursor cursor =  db.rawQuery("select * from book", null);
    while (cursor.moveToNext())
    {
        String name = cursor.getString(cursor.getColumnIndex("name"));
        String author =  cursor.getString(cursor.getColumnIndex("author"));
        Log.i(TAG, "name:" + name + " author:" + author);
    }
    cursor.close();
    

    如何检查数据库文件是否存在,以及检查表中的数据呢。

    前提是使用模拟器或者root过的真机。从 android studio 菜单中 Tools -> Android -> Android Device Monitor -> File Explorer 找到 data/data/程序包名/databases 目录

    查看是否存在数据库文件。如果存在可以导出到电脑上, 用 以下工具查看数据库中的表

    获取图片

    import java.io.FileNotFoundException;
    
    import android.content.ContentResolver;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.ImageView;
    
    import com.maikefengchao.daixu.R;
    
    public class WriteArticle_CompeterelayActivity extends BaseActivity {
        private ImageView im_upload_img;
    
        @Override
        public void initView(Bundle savedInstanceState){
            setContentView(R.layout.view_write_competerelay);
    
            im_upload_img = (ImageView)findViewById(R.id.write_competerelay_cover_iv);
        }
    
        @Override
        protected void setListener() {
            im_upload_img.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent();
                    /* 开启Pictures画面Type设定为image */
                    intent.setType("image/*");
                    /* 使用Intent.ACTION_GET_CONTENT这个Action */
                    intent.setAction(Intent.ACTION_GET_CONTENT);
                    /* 取得相片后返回本画面 */
                    startActivityForResult(intent, 1);
                }
            });
        }
    
        @Override
        protected void processLogic(Bundle saveInstanceState) {
    
        }
    
    
        //获取本地图片
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (resultCode == RESULT_OK) {
                Uri uri = data.getData();
                String img_url = uri.getPath();//这是本机的图片路径
                ContentResolver cr = this.getContentResolver();
                try {
                    Bitmap bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));
                    ImageView imageView = (ImageView) findViewById(R.id.write_competerelay_cover_iv);
                    /* 将Bitmap设定到ImageView */
                    imageView.setImageBitmap(bitmap);
                } catch (FileNotFoundException e) {
                    Log.e("Exception", e.getMessage(),e);
                }
            }
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
    

    statistics.sh

  • 相关阅读:
    关于编码的问题(转)
    XML巩固
    浏览器兼容问题的解决方案
    JavaScript 全局变量命名空间生成函数
    表格的使用(转)
    post上传文件
    安装cocoapods
    UILabel内容模糊
    动态获取键盘高度
    iOS多线程同步锁
  • 原文地址:https://www.cnblogs.com/yuchao123/p/10808757.html
Copyright © 2011-2022 走看看