热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Android系统的五种数据存储形式实例(二)

Android系统有五种数据存储形式,分别是文件存储、SP存储、数据库存储、contentprovider内容提供者、网络存储。本文介绍了Android系统的五种数据存储形式,有兴趣的可以了解一下。

之前介绍了Android系统下三种数据存储形式,https://www.jb51.net/article/99468.htm。今天补充介绍另外两种,分别是内容提供者和网络存储。有些人可能认为内存提供者和网络存储更偏向于对数据的操作而不是数据的存储,但这两种方式确实与数据有关,所以这里还是将这两种形式简要的说明一下。

 Content Provider:

Content Provider,中文名是内存提供者,Android四大组件之一,内容提供者是应用程序之间共享数据的接口,以数据库形式存入手机内存,可以共享自己的数据给其他应用使用。之所以需要设计一个单独的控件来操作数据,是为了实现应用程序之间的数据传递。通过查看DDMS中的目录结构可以看出,数据库文件对于其他应用来说是不可读、不可写,而日常生活中又需要获取其他应用的数据,尤其是系统自带软件的数据。比如打开QQ或者微信时会提示是否同步联系人,又比如备份短信的时候,这些都需要访问和操作其他应用的数据库。因此谷歌工程师在底层软件中集成了大量的方法利用内存提供者的原理,类似于在数据库中提供一个对外访问的路径,供其他应用访问。

为了更好的理解内存提供者的工作原理,可以自定义一个内容提示者来帮助理解。首先写一个类继承ContentProvider,实现该类中的方法,包括一些增删改查和数据初始化的方法,可以在方法中实现对数据库的增删改查操作。数据库本来是不对外开放的,所以为保护数据,类中的方法原始返回数据均是空类型。为保证数据的安全性,可以创建一个UriMatcher对象,利用addURIf方法添加Uri的路径规则,在每一次进行数据操作时先判断传入的路径是否符合命名规则。使用内存提供者需要在配置文件中添加provider标签,指定主机名。只有当访问者与内容提供者的主机名一致时,才可以建立数据连接。在另一个应用中实现对内存提供者的访问。具体操作是:创建内容提供者解析器,定义要访问的Uri的路径。Uri路径有着固定的格式:”content://主机名/匹配字符”。 利用内容提供者解析器进行增删改查,和要操作的数据库之间建立联系。以上内容通常用来理解内容提供者的工作原理,实际工作中很少用到自定义的内容提示者。实际中用的比较多的是用内容提供者操作系统联系人、系统短信等系统应用的数据库。

内容提供者操作系统应用时相对简单,需要用到的大部分程序已经在底层实现,要做的是调用各种方法和相关的参数。需要关注的参数有Uri路径、数据库的表单结构。可以通过查看底层的代码获取相应的参数。其中有些常用的参数可以记下来,方便调用。比如获取全部短信的Uri路径是: content://sms。与联系人有关的数据库表单有三个raw_contacts、data、mimetypes。操作raw_contacts 表的Uri是: content://com.android.contacts/raw_contacts,操作data 表的Uri是:content://com.android.contacts/data。本文以短信的备份、还原来演示利用内容提供者访问短信数据库。

 先看一下短信和手机联系人有关的数据库所在的路径。短信在Android 模拟器下存放在的路径是:/data/data/com.android.providers.telephony/databases/目录,联系人在Android 模拟器下存放在的路径是:/data/data/com.android.providers.contacts/databases/目录。对于短信数据库我们关心的表数据有:address、type、body、date,分别表示发送者号码、短信类型(收还是发)、短信内容、日期。对于联系人数据库的三张表一定要按照一定的顺序依次查找才能得到相关的数据,在这不做解释。尽管开发的时候不需要了解短信和手机联系人的数据库路径,但是要明白短信和手机联系人的数据是存在数据库中的,同时数据库对外是不开放的。

与短信有关的数据库的目录结构:

本文给出的案例是短信的备份和还原,从而实现对系统应用数据库的操作。首先利用内容提供者查询到短信数据库里的详细参数,将该数据以Xml文件的形式存入到指定的文件夹。利用xml解析得到数据,将获取的数据存在一个工具类中,这样就能用ListView将数据显示在界面上。具体实现如下。

package com.example.contentprovider; 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.util.ArrayList;

import java.util.List;

 

import org.xmlpull.v1.XmlPullParser;

import org.xmlpull.v1.XmlSerializer;

 

import android.app.Activity;

import android.content.ContentResolver;

import android.database.Cursor;

import android.net.Uri;

import android.os.Bundle;

import android.util.Log;

import android.util.Xml;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.ListView;

import android.widget.TextView;

import android.widget.Toast;

/**

 * 短信的备份和还原

 * 添加写短信和读短信的权限

 * 

  

 * @author Huang

 */

 public class MainActivity extends Activity {

  private static final String TAG = "MainActivity";

  private ListView lv;

  private List mlist;

  private Myadpter adapter;

  @Override

  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    lv = (ListView) findViewById(R.id.lv);

    datafresh();

  }

  //数据刷新,一般用到ListView时最好记得刷新数据否则不显示

  public void datafresh(){

    mlist = getList();

    if(adapter == null){

      adapter = new Myadpter();

    }else {

      adapter.notifyDataSetChanged();

    }

  }

  //用ListView显示短信内容

  public class Myadpter extends BaseAdapter{

    public int getCount() {

      // TODO Auto-generated method stub

      return mlist.size();

    }

    public Object getItem(int position) {

      // TODO Auto-generated method stub

      return null;

    }

    public long getItemId(int position) {

      // TODO Auto-generated method stub

      return 0;

    }

    public View getView(int position, View convertView, ViewGroup parent) {

      TextView tv = new TextView(MainActivity.this);

      tv.setText(mlist.get(position).toString());

      return tv;

    }

  }

  //短信备份 

  public void bankup(View view){

    ContentResolver resolver = getContentResolver();

    Uri uri = Uri.parse("content://sms");

    Cursor cursor = resolver.query(uri, new String[]{"address","body","type","date"}, null, null, null);

    while(cursor.moveToNext()){

      String address = cursor.getString(0);

      String body = cursor.getString(1);

      String type = cursor.getString(2);

      String date = cursor.getString(3);

      //序列化,把短信以Xml文件的形式存储

      XmlSerializer serializer = Xml.newSerializer();

      File file = new File(getFilesDir(),"info.xml");

      try {

        FileOutputStream fos = new FileOutputStream(file);

        serializer.setOutput(fos, "utf-8");

        serializer.startDocument("utf-8", true);

        serializer.startTag(null, "person");

         

        serializer.startTag(null, "address");

        serializer.text(address);

        serializer.endTag(null, "address");

         

        serializer.startTag(null, "body");

        serializer.text(body);

        serializer.endTag(null, "body");

         

        serializer.startTag(null, "type");

        serializer.text(type);

        serializer.endTag(null, "type");

         

        serializer.startTag(null, "date");

        serializer.text(date);

        serializer.endTag(null, "date");

         

        serializer.endTag(null, "person");

        serializer.endDocument();

        fos.close();

//       Toast.makeText(this, "数据保存成功", 0).show();

      } catch (Exception e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

      }

    }

  }

 

  public void restore(View view){

    datafresh();

    lv.setAdapter(adapter);

  }

  //利用Xml解析得到短信内容

  private List getList() {

    ContentResolver resolver = getContentResolver();

    List list = new ArrayList();//创建一个Person类存储标签内容

    Person p = new Person();

    File file = new File(getFilesDir(),"info.xml");

    XmlPullParser pullParser = Xml.newPullParser();

    try {

      FileInputStream fis = new FileInputStream(file);

      pullParser.setInput(fis, "utf-8");

      int mtype = pullParser.getEventType();

      while(mtype != XmlPullParser.END_DOCUMENT){

        String name = pullParser.getName();

        switch (mtype){

        case XmlPullParser.START_TAG:

          if("address".equals(name)){

            String address = pullParser.nextText();

            p.setAddress(address);

          }else if("body".equals(name)){

            String body = pullParser.nextText();

            p.setBody(body);

          }else if("type".equals(name)){

            String type = pullParser.nextText();

            p.setType(type);

          }else if("date".equals(name)){

            String date = pullParser.nextText();

            p.setDate(date);

          }

          break;

        case XmlPullParser.END_TAG:

          if("person".equals(name)){

            list.add(p);

          }

          break;

        }

        mtype = pullParser.next();

      }

      Log.i(TAG, list.toString());

      return list;

    } catch (Exception e) {

      // TODO Auto-generated catch block

      e.printStackTrace();

      return null;

    }

  }

} 

效果演示,我的虚拟机中只存了一条短信:

网络存储:

网络存储是最容易理解的一种存储方式了。其实说简单点就是文件的上传和下载。经常听到的云备份就是这种形式。优势也很明显,即把数据存储到服务器,不存储在本地,使用的时候直接从网络获取,避免了手机端信息丢失以及其他的安全隐患。因此,对于这种形式就不作多的解释,直接给出一个文件的上传和下载的实例来演示网络存储。

代码实现:

package com.example.upload;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.http.Header;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity {
  protected static final int SUCCESS = 1;
  protected static final int ERORR = 2;
  private EditText et_path;
  private ImageView iv;
  //访问网络操作耗时,需要在子线程中加一个代理
  private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
      case SUCCESS:
        Bitmap bm = (Bitmap) msg.obj;
        iv.setImageBitmap(bm);
        break;
      case ERORR:
        Toast.makeText(MainActivity.this, "图片获取失败", 0).show();
        break;
      }
      super.handleMessage(msg);
    }};
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    et_path = (EditText) findViewById(R.id.et_path);
    iv = (ImageView) findViewById(R.id.iv);
  }
  //上传程序
  public void upload(View view){
//    String path = et_path.getText().toString().trim();
//    这里为方便把路径写死,这种方式不太正规,一般可以读et_path来访问
    String path = "/mnt/sdcard/info.txt";
    if(TextUtils.isEmpty(path)){
      Toast.makeText(this, "路径不能为空", 0).show();
      return;
    }
    File file = new File(path);
    AsyncHttpClient client = new AsyncHttpClient();
    RequestParams param = new RequestParams();
    try {
      param.put("file", file);
    } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    client.post("http://192.168.1.114:8080/",param, new AsyncHttpResponseHandler() {
      
      @Override
      public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
        // TODO Auto-generated method stub
        Toast.makeText(MainActivity.this, "提交成功", 0).show();
      }
      
      @Override
      public void onFailure(int statusCode, Header[] headers,
          byte[] responseBody, Throwable error) {
        // TODO Auto-generated method stub
        Toast.makeText(MainActivity.this, "提交失败", 0).show();
      }
    });
  }

  //下载程序  
  public void download(View view){
    new Thread(){
      public void run() {
        try {
          //这里为方便把路径写死,可以读et_path来访问,两者结果一样
          URL url = new URL("http://192.168.1.114:8080/demo1.png");
          HttpURLConnection cOnn= (HttpURLConnection) url.openConnection();
          conn.setConnectTimeout(5000);
          conn.setRequestMethod("GET");
          int code = conn.getResponseCode();
          if(code == 200){
            InputStream is = conn.getInputStream();
            Bitmap bitmap = BitmapFactory.decodeStream(is);
            Message msg = Message.obtain();
            msg.what = SUCCESS;
            msg.obj = bitmap;
            handler.sendMessage(msg);
            is.close();
          }
        } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
           Message msg = Message.obtain();
           msg.what = ERORR;
           handler.sendMessage(msg);
        }
      };
    }.start();
  }
}

至此五种数据存储全部实现。当然,实际开发中可能比这更复杂,会嵌入到别的知识点中,但数据操作无疑是最为基本的一步,是整体项目开发的基础。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
author-avatar
jelly62_736
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有