博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android-网络与数据存储
阅读量:3942 次
发布时间:2019-05-24

本文共 19254 字,大约阅读时间需要 64 分钟。

五种数据存储方式

  • 文件存储是一种较常用的方法,与 Java的文件存储类似,都是通过 I/O 流的形式存储数据。
  • SharedPreferences 时 Android提供的用来存储一些简单的配置信息的一种机制。
  • SQLite数据库是 Android自带的一个轻量级数据库,支持基本 SQL语法。
  • ContentProvider是 Android四大组件之一,可以将自己的数据共享给其他应用程序。
  • 网络存储是通过网络提供的存储空间来存储 / 获取数据信息。

读取各目录下的文件

  • 操作sd卡文件、读写文件
  • 操作assets目录下的文件
  • 操作raw目录下的文件
  • 操作res目录下的文件
void testAssets() throws IOException {
// 第一种,直接读取路径 WebView webView = new WebView(this); webView.loadUrl("file:///android_asset/test.html"); try {
// open的只能是文件,不能是文件夹 InputStream inputStream = getResources().getAssets().open("test.html"); } catch (IOException e) {
e.printStackTrace(); } // 读列表 String[] filenames = getAssets().list("images"); // 读图片 InputStream inputStream = getAssets().open("images/test.jpg"); Bitmap bitmap = BitmapFactory.decodeStream(inputStream); // 读音乐 AssetFileDescriptor assetFileDescriptor = getAssets().openFd("test.mp3"); MediaPlayer player = new MediaPlayer(); player.reset(); player.setDataSource( assetFileDescriptor.getFileDescriptor(), assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength()); player.prepare(); player.start();}void testResFile() {
InputStream inputStream = getResources().openRawResource(R.id.文件名); getResources().getColor(R.color.); getResources().getString(R.string.); getResources().getDrawable(R.drawable.);}void testSDCard() {
File file = new File("/sdcard/test/a.txt"); String filePath = Environment.getExternalStorageDirectory().getAbsolutePath(); Environment.getDataDirectory(); // 获取Android中的data数据目录 Environment.getDownloadCacheDirectory(); // 获取下载的缓存}

1、文件存储

  • 文件存储是Android中最基本的一种数据存储方式,Android中的文件存储分为内部存储和外部存储。

    • 内部存储:将应用程序中的数据以文件方式存储到设备的内部(位于data/data//files/目录),当创建的应用程序被卸载时,其内部存储文件也随之被删除。
  • 外部存储:是将文件存储到一些外部设备上,例如SD卡或者设备内嵌的存储卡(通常位于mnt/sdcard目录下,不同厂商生产的手机路径可能不同)。属于永久性存储方式。

    — 获取外部存储的权限:android.permission.WRITE_EXTERNAL_STORAGE

  • 1.1 首先创建一个Module,然后在 activity_main.xml文件中添加组件

  • 1.2 在MainActivity中实现View.OnClickListener接口,并为组件实例化和设置监听事件

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView mTextView; // 声明 TextView private Button mSaveButton; private Button mReadButton; @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = findViewById(R.id.tv_hello); mSaveButton = findViewById(R.id.btn_save); mReadButton = findViewById(R.id.btn_read); // 设置保存和读取按钮的点击事件 mSaveButton.setOnClickListener(this); mReadButton.setOnClickListener(this); } // 保存文件 public void saveFileInApplication() {
    String fileName = "data.txt"; String content = "这是我们演示的文件存储示例"; FileOutputStream fos; try {
    // 以追加模式创建 data.txt文件,并写入内容保存文件到应用程序下 // openFileOutput(文件名, 操作模式),MODE_PRIVATE:私有覆盖模式,后写入的内容会覆盖前面写入的内容 fos = openFileOutput(fileName, MODE_PRIVATE); // 写入获取字的符串的字节流 fos.write(content.getBytes()); fos.close(); Toast.makeText(this, "文件保存成功", Toast.LENGTH_SHORT).show(); } catch (Exception e) {
    e.printStackTrace(); Toast.makeText(this, "文件保存失败", Toast.LENGTH_SHORT).show(); } } // 读取文件 public void readFileInApplication() {
    String content = ""; FileInputStream fis; try {
    // 读取"data.txt"文件中的字节流,并将返回的文件输入流赋值给 fis fis = openFileInput("data.txt"); // 创建字节数组,通过 fis.available()方法获取 fis的可读取字节数,并作为字节数组的最大长度 byte[] buffer = new byte[fis.available()]; // 将读取的内容存储到字节数组当中 fis.read(buffer); content = new String(buffer); fis.close(); // 将读取的内容设置给TextView显示出来 mTextView.setText(content); Toast.makeText(this, "读取成功", Toast.LENGTH_SHORT).show(); } catch (Exception e) {
    e.printStackTrace(); Toast.makeText(this, "读取失败", Toast.LENGTH_SHORT).show(); } } @Override public void onClick(View v) {
    switch (v.getId()) {
    case R.id.btn_save: saveFileInApplication(); break; case R.id.btn_read: readFileInApplication(); break; } }}

    File存储核心语句:

    • openFileOutput(String name, int mode) : 保存文件内容,打开指定的私有文件输出流;
    • 返回参数类型为FileOutputStream;
    • name : 为要打开的文件名,不包含路径分隔符;
    • mode : 为文件操作模式。

    Mode的取值:

    • Environment.MODE_PRIVATE: 为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下写入的内容会覆盖原文件的内容;
    • Environment.MODE_APPEND: 检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
  • 1.3 运行Module,在Android Studio的右下角Device File Explorer中的data/data/文件夹下可以找到我们新创建的data.txt文件,同样也可以打开DDMS查看,

    android-FileStorage.gif


2、使用 SharedPreferences 方便的存储数据

  • SharedPreferences 是什么?

    SharedPreferences 是 Android平台上一个轻量级的存储类。

    SharedPreferences 中存储的数据是以 key/value 键值对的形式保存在XML文件中,该文件位于“data/data//shared_prefs”文件夹中。

  • SharedPreferences 适用于哪些地方?

    存储一些简单的值,应用程序的配置参数,如用户名、密码等。

  • 2.1 使用SharedPreferences 保存数据的方法 :

    • 1、使用Activity类的getSharedPreferences (String name, int mode) 方法获得SharedPreferences 对象,其中参数 name 指定存储键值对的文件名称,mode 则指定文件操作模式。
    • 2、使用SharedPreferences 的edit() 方法获得SharedPreferences.Editor对象。
    • 3、通过SharedPreferences.Editor的putXxx(String key, Xxx value) 方法写入键值对。
    • 4、通过SharedPreferences.Editor的commit()方法提交要保存的键值对。
  • 2.2 首先创建一个Module,并在activity_main.xml文件中通过约束布局快速搭建界面

    image.png

  • 2.3 创建一个SPSaveQQ类,并在该类中创建两个方法用于保存和读取账号密码

    public class SPSaveQQ {
    public static final String ACCOUNT = "account"; public static final String PASSWORD = "password"; // 保存QQ账号和密码到 data.xml文件中 public static boolean saveUserInfo(Context context, String account, String password) {
    // 创建 SharedPreferences对象。参数 data是文件名,Context.MODE_PRIVATE是文件操作模式 SharedPreferences sp = context.getSharedPreferences("data", Context.MODE_PRIVATE); // 创建 Editor对象 SharedPreferences.Editor editor = sp.edit(); // 保存用户名和密码 editor.putString(ACCOUNT, account); editor.putString(PASSWORD, password); // 编辑结束,调用该方法提交// editor.commit(); // 和网络相关,IO操作相关的,都要用异步 // 后台写数据,另开线程 editor.apply(); return true; } // 从 data.xml文件中获取存储的QQ账号和密码 public static Map
    getUserInfo(Context context) {
    SharedPreferences sp = context.getSharedPreferences("data", Context.MODE_PRIVATE); // 使用getString()方法读取用户名和密码。第一个参数为 key,第二个参数为 defValue String account = sp.getString(ACCOUNT, null); String password = sp.getString(PASSWORD, null); // 创建 HashMap用来存储用户登录信息 Map
    userMap = new HashMap<>(); // 将刚才读取的用户名和密码值添加到 userMap中 userMap.put(ACCOUNT, account); userMap.put(PASSWORD, password); return userMap; }}
  • 2.4 在MainActivity中初始化EditView和Button组件,并为登录按钮设置点击事件

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText mAccount; private EditText mPassword; private Button mLogin; @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化界面 initView(); // 调用SPSaveQQ.getUserInfo()方法获取保存在SharedPreferences文件当中的账号和密码 Map
    userInfo = SPSaveQQ.getUserInfo(this); if (userInfo != null) {
    mAccount.setText(userInfo.get(SPSaveQQ.ACCOUNT)); mPassword.setText(userInfo.get(SPSaveQQ.PASSWORD)); } } public void initView() {
    mAccount = findViewById(R.id.et_account); mPassword = findViewById(R.id.et_password); mLogin = findViewById(R.id.btn_login); // 为登录按钮设置点击事件 mLogin.setOnClickListener(this); } @Override public void onClick(View v) {
    // 点击登录按钮时,获取文本框中的账号和密码 String account = mAccount.getText().toString(); String password = mPassword.getText().toString(); // 校验用户是否输入账号和密码 if (TextUtils.isEmpty(account)) {
    Toast.makeText(this, "请输入QQ账号", Toast.LENGTH_SHORT).show(); return; } if (TextUtils.isEmpty(password)) {
    Toast.makeText(this, "请输入密码", Toast.LENGTH_SHORT).show(); return; } // 登录成功 Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show(); // 保存用户输入的QQ账号和密码 boolean isSaveSuccess = SPSaveQQ.saveUserInfo(this, account, password); if (isSaveSuccess) {
    Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show(); } else {
    Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show(); } }}
  • 2.5 运行Module,在Android Studio的右下角Device File Explorer中的data/data//shared_prefs文件夹下可以看到我们创建的data.xml

    android-SharedPreferences.gif


3、SQLite数据库简介

SQLite 是一个轻量级数据库,占用资源非常低,在内存中只需占用几百KB的存储空间。
SQLite 是遵守ACID的关系型数据库管理系统,ACID是指数据库事务正确执行的四个基本要素,即原子性(Atomicity)、一致性(Consistency)、隔离性(lsolation)、持久性(Durability)。
  • 特色:轻量级、独立、隔离、跨平台、多语言接口、安全性

增删改查示例

  • 3.1 新建一个Module,并添加一个DatabaseHelper类

    /** * DatabaseHelper作为一个访问 SQLite的助手类,提供两个方面的功能: * 第一:getReadableDatabase(), getWritableDatabase()可以获得 SQLiteDatabase对象,通过该对象可以对数据库进行操作 * 第二:提供了 onCreate()和 onUpgrade()两个回调函数,允许我们在创建和升级数据库时,进行自己的操作 */public class DatabaseHelper extends SQLiteOpenHelper {
    public static final String DATABASE_NAME = "test.db"; public DatabaseHelper(@Nullable Context context) {
    super(context, DATABASE_NAME, null, 1); } @Override public void onCreate(SQLiteDatabase db) {
    db.execSQL("create table tb_user(id INTEGER primary key autoincrement," + "username varchar(20) not null, password varchar(20) not null)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // 当数据库的版本号增加时调用 }}
  • 3.2 在activity_main.xml中添加一个Button按钮并设置点击事件

    • 点击按钮跳转到DatabaseButtonActivity界面

      public class MainActivity extends AppCompatActivity {
      @Override protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = findViewById(R.id.btn_index_main); button.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View v) {
      Intent intent = new Intent(); intent.setClass(MainActivity.this, DatabaseButtonActivity.class); startActivity(intent); } }); }}
  • 3.2 创建activity_database.xml和DatabaseButtonActivity,并在布局文件中添加组件

    image.png

  • 在DatabaseButtonActivity中为四个按钮设置点击事件【别忘了加入AndroidManifest.xml中

    public class DatabaseButtonActivity extends AppCompatActivity {
    private static final String TAG = "MySQLite"; @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); setContentView(R.layout.activity_database); initView(); } public void initView() {
    Button insertButton = findViewById(R.id.btn_insert); Button deleteButton = findViewById(R.id.btn_delete); Button updateButton = findViewById(R.id.btn_update); Button selectButton = findViewById(R.id.btn_select); insertButton.setOnClickListener(new InsertListener()); deleteButton.setOnClickListener(new DeleteListener()); updateButton.setOnClickListener(new UpdateListener()); selectButton.setOnClickListener(new SelectListener()); } /** * 插入数据按钮的监听器 */ public class InsertListener implements View.OnClickListener {
    @Override public void onClick(View v) {
    // 1、创建 DatabaseHelper助手类对象 DatabaseHelper databaseHelper = new DatabaseHelper(DatabaseButtonActivity.this); // 2、创建 SQLiteDatabase对象 SQLiteDatabase db = databaseHelper.getWritableDatabase(); // 3、创建 ContentValues对象 ContentValues values = new ContentValues(); // ContentValues类似于 Map类,通过键值对的形式存储数据 values.put("username", "admin"); values.put("password", "admin123"); // 插入数据 long id = db.insert("tb_user", null, values); db.close(); if (id != -1) {
    Log.i(TAG, "插入成功"); } } } /** * 删除数据按钮的监听器 */ public class DeleteListener implements View.OnClickListener {
    @Override public void onClick(View v) {
    DatabaseHelper databaseHelper = new DatabaseHelper(DatabaseButtonActivity.this); SQLiteDatabase db = databaseHelper.getWritableDatabase(); String whereClause = "id=?"; String[] whereArgs = {
    "1"}; int number = db.delete("tb_user", whereClause, whereArgs); db.close(); Log.i(TAG, "删除:" + number + "行受影响"); } } /** * 修改数据按钮的监听器 */ public class UpdateListener implements View.OnClickListener {
    @Override public void onClick(View v) {
    DatabaseHelper databaseHelper = new DatabaseHelper(DatabaseButtonActivity.this); SQLiteDatabase db = databaseHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("username", "zhangsan"); String whereClause = "id=?"; String[] whereArgs = {
    "1"}; int number = db.update("tb_user", values, whereClause, whereArgs); db.close(); Log.i(TAG, "修改:" + number + "行受影响"); } } /** * 查询数据按钮的监听器 */ public class SelectListener implements View.OnClickListener {
    @Override public void onClick(View v) {
    DatabaseHelper databaseHelper = new DatabaseHelper(DatabaseButtonActivity.this); SQLiteDatabase db = databaseHelper.getWritableDatabase(); String whereClause = "id=?"; String[] whereArgs = {
    "1"}; // Cursor是一个游标接口,提供了遍历查询结果的方法。query()方法返回的是一个行数集合 Cursor Cursor cursor = db.query("tb_user", null, whereClause, whereArgs, null, null, null); boolean result = cursor.moveToNext(); if (result) {
    // 根据列名获得列索引 // getString()方法获取记录值,getColumnIndex()方法获取列的索引 String username = cursor.getString(cursor.getColumnIndex("username")); String password = cursor.getString(cursor.getColumnIndex("password")); cursor.close(); db.close(); Log.i(TAG, "查询记录----用户名:" + username + ", 密码:" + password); } else {
    Log.i(TAG, "查询记录为空"); } } }}
  • 3.3 运行效果预览【】

    android-SQLite.gif


4、ContentProvider

什么是Content Provider

  • 应用程序间共享数据的一种方式
  • 为存储和获取数据提供了统一的接口
  • Android为常见的一些数据提供了默认的ContentProvider
  • 四大组件之一

Google是怎么定义Content Provider的?

  • 内容提供者将一些特定的应用程序提供给其他应用程序使用。
  • 数据可以存储于文件系统、SQLite数据库或其他方式
  • 内容提供者继承于ContentProvider基类,为其他应用程序取用和存储它管理的数据实现了一套标准方法
  • 应用程序并不直接调用这些方法,而是使用ContentResolver对象,调用它的方法作为替代。
  • ContentResolver可以与任意内容提供者进行会话,与其合作来对所有相关交互通讯进行管理。

ContentProvider的实现过程

  • Database
  • Uri
  • UriMatcher
  • ContentProvider
  • query/insert/update/delete
  • AndroidManifest.xml

5、网络编程数据处理

5.1 如何请求网络数据

  • 在AndroidManifest.xml中申请权限

  • 需要异步的获取数据,否则会直接闪退,因为不能在主线程中获取数据

5.2 请求百度数据,并把数据显示出来

  • 5.2.1 我们新建一个项目,在activity_main.xml中添加按钮,并在MainActivity中设置点击事件

    @Overrideprotected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = findViewById(R.id.btn_index_main); button.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
    Intent intent = new Intent(); intent.setClass(MainActivity.this, NetWorkActivity.class); startActivity(intent); } });}
  • 5.2.2 创建一个NetWorkActivity和activity_network.xml布局文件,并添加到AndroidManifest中

    image.png

    public class NetWorkActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText mHttpEditText; private TextView mShowResultTextView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); setContentView(R.layout.activity_network); initView(); } public void initView() {
    mHttpEditText = findViewById(R.id.et_http); Button mGetDataButton = findViewById(R.id.btn_getData); mShowResultTextView =findViewById(R.id.tv_showResult); mGetDataButton.setOnClickListener(this); } @Override public void onClick(View v) {
    switch (v.getId()) {
    case R.id.btn_getData: String url = getEditTextUrl(); // 请求网络数据,需要在 AndroidManifest中注册网络权限 new RequestNetworkDataTask().execute(url); //String content = requestData(url); //mShowResultTextView.setText(content); break; } } // 获取 Url地址 public String getEditTextUrl() {
    return mHttpEditText != null ? mHttpEditText.getText().toString() : ""; } // 返回请求数据 public String requestData(String urlString) {
    try {
    URL url = new URL(urlString); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // 设置连接超时 connection.setConnectTimeout(30000); // 设置请求方法 connection.setRequestMethod("GET"); // 建立连接 connection.connect(); int responseCode = connection.getResponseCode(); String responseMessage = connection.getResponseMessage(); InputStream inputStream = connection.getInputStream(); Reader reader = new InputStreamReader(inputStream); char[] buffer = new char[1024]; reader.read(buffer); String content = new String(buffer); return content; } catch (MalformedURLException e) {
    e.printStackTrace(); } catch (IOException e) {
    e.printStackTrace(); } return null; } // 异步任务处理 public class RequestNetworkDataTask extends AsyncTask
    {
    @Override protected void onPreExecute() {
    // 在后台 work之前,在主线程中 super.onPreExecute(); Toast.makeText(NetWorkActivity.this, "加载中...", Toast.LENGTH_SHORT).show(); } @Override protected String doInBackground(String... strings) {
    String result = requestData(strings[0]); return result; } @Override protected void onPostExecute(String s) {
    // 执行完之后再主线程中 super.onPostExecute(s); mShowResultTextView.setText(s); System.out.println(s); Toast.makeText(NetWorkActivity.this, "加载完成", Toast.LENGTH_SHORT).show(); } }}
  • 5.2.3 效果预览

    image.png

注意:Genymotion需要进行网络连接哦!

5.3 数据解析

  • XML

    • SAX : 基于事件驱动的
    • PULL : android系统本身自适用的
    • DOM : 文件流的形式,会把整个文件加载出来
  • JSON

    • JSONObject

    • JSONArray

    • other…

    • GSON

    • fastjson

网络状态处理及常用网络开源库

  • 网络状态处理
    • ConnectivityManager
    • NetworkInfo
  • 常用网络开源库
    • android-async-http
    • Volley
    • OKHttp
    • Retrofit

转载地址:http://bkiwi.baihongyu.com/

你可能感兴趣的文章
猴子排队算法
查看>>
查询系统负载信息&nbsp;Linux&nbsp;命令详解
查看>>
增强&nbsp;SSH&nbsp;安全性的&nbsp;7&nbsp;条技巧
查看>>
this作用域、javascript面向…
查看>>
提高网页在IE和Firefox上的…
查看>>
提高网页在IE和Firefox上的…
查看>>
php的正则表达式&nbsp;&#039;/\b\w…
查看>>
ThinkPHP的标签制作及标签调用解析…
查看>>
jQuery.proxy()代理、回调方法
查看>>
php操作memcache的使用测试总结
查看>>
JS创建类和对象
查看>>
完整ASCII字符表(转)
查看>>
jquery事件重复绑定解决办法
查看>>
jQuery.extend&nbsp;函数详解
查看>>
mysqli_query和mysql_query有何区…
查看>>
mysqli-&gt;multi_query()多条语句的…
查看>>
php引用(&amp;)变量引用,函数引用,对…
查看>>
[转]yii执行流程(一&nbsp;目录文…
查看>>
无需重启服务器让系统环境变量生效…
查看>>
配置CakePHP
查看>>