Android系统的五种数据存储形式

  • A+
所属分类:移动安全

  很多东西在实际工作中碰不到,用不到。慢慢的也就荒废了,学的东西太杂,好多东西都是学到一半就放下了。最后似乎成了一无所精。慢慢的越来越迷茫。

   年前学了一段时间C,还没学会就开始学CTF,依旧是还没入门就开始了红蓝对抗。最近思考的东西越来越多,好像回家放羊,只放一只。


找出了自己16年的笔记,荒废的东西总要先捡起来。

Android系统的五种数据存储形式

  Android系统有五种数据存储形式,分别是文件存储、SP存储、数据库存储、contentprovider 内容提供者、网络存储。其中,前四个是本地存储。存储的类型包括简单文本、窗口状态存储、音频视频数据、XML注册文件的各种数据。各种存储形式的特点不尽相同,因此对于不同的数据类型有着固定的存储形式,本文为演示方便给出的案例基本相同,都是是采用账号登录来演示数据存储,保存账号和密码信息,下次登录时记住账号和密码。重在说明各种存储形式的原理。


    文件存储:

    以I/O流的形式把数据存入手机内存或SD卡,可以存储大数据,如音乐、图片或视频等。对于手机内存来说系统会根据每个应用的包名创建一个/data/data/包名/的文件夹,访问自己包名下的目录是不需要权限的,并且 Android 已经提供了非常简便的 API 可以直接去访问该文件夹。访问时可以用getFilesDir()和getCacheDir(),两个的区别是系统会自动清理后者中的内容。

    SD卡中的文件通常位于mnt/sdcard目录下,不同生产商生产的手机这个路径可能不同。操作sd卡的时通常要判断下sd卡是否可用以及剩余空间是否足够,因为部分手机的SD卡可卸载,SD卡处于非挂载状态时,无法进行读写操作。另外一点,对SD卡的读取和写入操作均需要相应的权限,否则无法完成。获取SD卡路径的方法是Environment.getExternalStorageDirectory(),其余操作与文件存储基本类似。

文件存储位置:

Android系统的五种数据存储形式


  SD卡存储路径:

Android系统的五种数据存储形式

数据存储在手机内存的实现方法:

package com.example.qqload;
import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.InputStreamReader;
import com.example.qqload_sp.R;
import android.os.Bundle;import android.app.Activity;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.text.TextUtils;import android.view.Menu;import android.view.TextureView;import android.view.View;import android.widget.Button;import android.widget.CheckBox;import android.widget.EditText;import android.widget.Toast;
public class MainActivity extends Activity {private EditText et_qq;private EditText et_password;private CheckBox cb_remenber;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_qq = (EditText) findViewById(R.id.et_qq);et_password = (EditText) findViewById(R.id.et_password);cb_remenber = (CheckBox) findViewById(R.id.cb_remenber);File file = new File(getFilesDir(), "info.txt");// File file = new File(getCacheDir(), "info.txt"); 缓存中存放数据if (file.exists() && file.length() > 0) {try {FileInputStream fis = new FileInputStream(file);BufferedReader br = new BufferedReader(new InputStreamReader(fis));String line = br.readLine();String qq = line.split("##")[0];String password = line.split("##")[1];et_qq.setText(qq);et_password.setText(password);fis.close();} catch (Exception e) {// TODO Auto-generated catch block e.printStackTrace();}}}
public void login(View view) {String qq = et_qq.getText().toString().trim();String password = et_password.getText().toString().trim();if (TextUtils.isEmpty(qq) || TextUtils.isEmpty(password)) {Toast.makeText(this, "密码或者用户名不能为空", 0).show();return;}if (cb_remenber.isChecked()) {File file = new File(getFilesDir(), "info.txt");try {FileOutputStream fos = new FileOutputStream(file);fos.write((qq + "##" + password).getBytes());fos.close();Toast.makeText(MainActivity.this, "保存成功", 0).show();} catch (Exception e) {Toast.makeText(MainActivity.this, "保存失败", 0).show();e.printStackTrace();}}}}

数据存储在SD卡中的实现方法:

package com.example.qqload;
import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.InputStreamReader;import java.text.Format;
import com.example.qqload_sp.R;
import android.os.Bundle;import android.os.Environment;import android.app.Activity;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.text.TextUtils;import android.text.format.Formatter;import android.view.Menu;import android.view.TextureView;import android.view.View;import android.widget.Button;import android.widget.CheckBox;import android.widget.EditText;import android.widget.Toast;
public class MainActivity extends Activity { private EditText et_qq; private EditText et_password; private CheckBox cb_remenber;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_qq = (EditText) findViewById(R.id.et_qq); et_password = (EditText) findViewById(R.id.et_password); cb_remenber = (CheckBox) findViewById(R.id.cb_remenber); File file = new File(Environment.getExternalStorageDirectory(), "info.txt"); if (file.exists() && file.length() > 0) { try { FileInputStream fis = new FileInputStream(file); BufferedReader br = new BufferedReader(new InputStreamReader( fis)); String line = br.readLine(); String qq = line.split("##")[0]; String password = line.split("##")[1]; et_qq.setText(qq); et_password.setText(password); fis.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
public void login(View view) { String qq = et_qq.getText().toString().trim(); String password = et_password.getText().toString().trim(); if (TextUtils.isEmpty(qq) || TextUtils.isEmpty(password)) { Toast.makeText(this, "密码或者用户名不能为空", 0).show(); return; } if (cb_remenber.isChecked()) { File file = new File(Environment.getExternalStorageDirectory(), "info.txt"); //判断SD卡是否挂载 if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ Toast.makeText(MainActivity.this, "SD卡不可用", 0).show(); return; } //判断SD卡大小是否充足 long size = Environment.getExternalStorageDirectory().getFreeSpace(); String info = Formatter.formatFileSize(this, size); //此处存储数据较小就不进行判断 Toast.makeText(this, "可用空间" + info, 0).show(); try { FileOutputStream fos = new FileOutputStream(file); fos.write((qq + "##" + password).getBytes()); fos.close(); Toast.makeText(MainActivity.this, "保存成功", 0).show(); } catch (Exception e) { Toast.makeText(MainActivity.this, "保存失败", 0).show(); e.printStackTrace(); } } }}

shared preferences:SP存储:

Android系统的五种数据存储形式


可以看到goatdroid应用的用户名和密码都以明文的形式存储在 shared preferences中

     SP存储本质上是一个XML文件,以键值对的形式存入手机内存中。常用于存储简单的参数设置,如登陆账号密码的存储,窗口功能状态的存储等,该存储文件位于:data/data/包名/shared_prefs文件夹中。使用的时候,首先需要通过context.getSharedPrefrences(String name,int mode)获取SharedPrefrences的实例对象,存储数据时,用SharedPrefrences的实例对象得到SharedPrefrences文件的编辑器,在编辑器中用putXxx()添加数据,之后务必用commit提交数据,否则无法获取数据。取数据时,直接用getXxx()方法。


sp存储自动生成xml文件,其的路径如下:

Android系统的五种数据存储形式

sp存储的实现方法:

package com.example.qqload;import com.example.qqload_sp.R;
import android.os.Bundle;import android.app.Activity;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.text.TextUtils;import android.view.Menu;import android.view.TextureView;import android.view.View;import android.widget.Button;import android.widget.CheckBox;import android.widget.EditText;import android.widget.Toast;public class MainActivity extends Activity { private EditText et_qq; private EditText et_password; private CheckBox cb_remenber; private SharedPreferences sp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_qq = (EditText) findViewById(R.id.et_qq); et_password = (EditText) findViewById(R.id.et_password); cb_remenber = (CheckBox) findViewById(R.id.cb_remenber); sp = this.getSharedPreferences("config", 0); String qq = sp.getString("qq",""); String password = sp.getString("password",""); et_qq.setText(qq); et_password.setText(password); } public void login(View view){ String qq = et_qq.getText().toString().trim(); String password = et_password.getText().toString().trim(); if(TextUtils.isEmpty(qq)||TextUtils.isEmpty(password)){ Toast.makeText(this,"密码或者用户名不能为空",0).show(); return; } if(cb_remenber.isChecked()){ Editor edit = sp.edit(); edit.putString("qq",qq); edit.putString("password",password); edit.commit(); } }}


数据库存储:

      数据库所有信息都存储在单一文件内,占用内存小,并且支持基本SQL语法,是项目中经常被采用的一种数据存储方式,通常用于存储用户信息等,例如在手机上做一个学生信息管理系统。SQLite 是一款内置到移动设备上的轻量型的数据库,SQLiteOpenHelper 是Android 提供的一个抽象工具类,负责管理数据库的创建、升级工作。数据库的路径为:/data/data/应用包名/databases/数据库。如果想创建数据库,就需要自定义一个类继承SQLiteOpenHelper,然后覆写其中的抽象方法,指定数据库名、版本号。在onCreate() 方法中通过执行sql 语句实现表的创建。如果只是创建出来该类并不会真正的去创建数据库,而是需要通过执行helper.getWritableDatabase()或者hepler.getReadableDatabase()。另外想要对创建的数据库进行增删改查的操作可以单独定义一个类实现。增删改查操作有两种方式,一是直接执行sql语句,另一个是Android自身的API实现。用数据库实现账号登录显得有些大材小用,为演示数据库的原理本文给出的案例是用数据库记录多个用户的账号和密码信息,并把最后一个账号信息回显在界面。但实际应用中很少这样做。

     从手机文件中导出数据库文件并不可以直接打开,因此可以用可视化工具和sqlite3操作工具进行查看。这里介绍sqlite3工具的使用。具体需要的步骤如下: 

        1. 执行adb shell命令进入Linuxne内核;

        2. 使用cd进入数据库所在的路径 cd: /data/data/应用包名/databases;

        3. 进入数据库模式: sqlite3 数据库名.db;

        4. 执行SQL语句        


        Sqlite3操作演示:

Android系统的五种数据存储形式

 数据库存储路径:

Android系统的五种数据存储形式

数据库实现方法,先创建一个类继承SqliteOpenHelper,在类中创建数据库和表:

package com.example.qqload.db;
import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.database.sqlite.SQLiteOpenHelper;
public class UserDBOpenhelper extends SQLiteOpenHelper { public UserDBOpenhelper(Context context) { super(context, "user.db", null, 1); // TODO Auto-generated constructor stub } @Override public void onCreate(SQLiteDatabase arg0) { arg0.execSQL("create table user (_id integer primary key autoincrement,name vachar(20),password varchar(20))"); } @Override public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) { // TODO Auto-generated method stub }}

创建一个工具类实现对数据库的操作:

package com.example.qqload.db.dao;
import java.util.ArrayList;import java.util.List;
import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;
import com.example.qqload.db.UserDBOpenhelper;
public class UserDao { private UserDBOpenhelper helper; public UserDao(Context context){ helper = new UserDBOpenhelper(context); } public long add(String name,String password){ SQLiteDatabase db = helper.getWritableDatabase(); //用SQL语句实现增加数据的功能 //db.execSQL("insert into user (name,passeord) values (?,?)", new Object[]{name,password}); //android自身API实现修改功能可以有返回值 ContentValues values =new ContentValues(); values.put("name", name); values.put("password", password); long result = db.insert("user", null, values); //带返回值,表示添加在哪一行 db.close(); return result; } public List<user> findAll(){ List<user> list =new ArrayList<user>(); SQLiteDatabase db = helper.getReadableDatabase(); //Cursor cursor = db.rawQuery("select name, password from user", null); Cursor cursor = db.query("user", new String[]{"name","password"}, null, null, null, null, null); while(cursor.moveToNext()){ String name = cursor.getString(0); String password = cursor.getString(1); user us = new user(); us.setName(name); us.setPassword(password); list.add(us); } cursor.close(); db.close(); return list; }}

在主方法中实现账号登录和记录

package com.example.qqload;
import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.InputStreamReader;import java.util.List;
import com.example.qqload.db.dao.UserDao;import com.example.qqload.db.dao.user;import com.example.qqload.R;
import android.os.Bundle;import android.app.Activity;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.text.TextUtils;import android.view.Menu;import android.view.TextureView;import android.view.View;import android.widget.Button;import android.widget.CheckBox;import android.widget.EditText;import android.widget.Toast;
public class MainActivity extends Activity { private EditText et_qq; private EditText et_password; private CheckBox cb_remenber; private UserDao dao; private List<user> list;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_qq = (EditText) findViewById(R.id.et_qq); et_password = (EditText) findViewById(R.id.et_password); cb_remenber = (CheckBox) findViewById(R.id.cb_remenber); user u = new user(); dao = new UserDao(MainActivity.this); list = dao.findAll(); if (list.size() == 0) { et_qq.setText(""); et_password.setText(""); } else { System.out.println("大小:" + list.size()); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i).getName() + "::::" + list.get(i).getPassword()); } u = list.get(list.size()-1); String qq = u.getName(); String password = u.getPassword(); et_qq.setText(qq); et_password.setText(password); } }
public void login(View view) { String qq = et_qq.getText().toString().trim(); String password = et_password.getText().toString().trim(); if (TextUtils.isEmpty(qq) || TextUtils.isEmpty(password)) { Toast.makeText(this, "密码或者用户名不能为空", 0).show(); return; } if (cb_remenber.isChecked()) { dao.add(qq, password); //在工具类添加增加功能 Toast.makeText(MainActivity.this, "保存成功", 0).show(); } }}

用数据库实现账号登录案例的目录结构如下所示:

Android系统的五种数据存储形式

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,分别表示发送者号码、短信类型(收还是发)、短信内容、日期。对于联系人数据库的三张表一定要按照一定的顺序依次查找才能得到相关的数据,在这不做解释。尽管开发的时候不需要了解短信和手机联系人的数据库路径,但是要明白短信和手机联系人的数据是存在数据库中的,同时数据库对外是不开放的。


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

Android系统的五种数据存储形式

本文给出的案例是短信的备份和还原,从而实现对系统应用数据库的操作。首先利用内容提供者查询到短信数据库里的详细参数,将该数据以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;/** * 短信的备份和还原 * 添加写短信和读短信的权限 *  <uses-permission android:name="android.permission.READ_SMS"/>    <uses-permission android:name="android.permission.WRITE_SMS"/> * @author Huang */  public class MainActivity extends Activity {    private static final String TAG = "MainActivity";    private ListView lv;    private List<Person> 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<Person> getList() {        ContentResolver resolver = getContentResolver();        List<Person> 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;        }    }}

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

Android系统的五种数据存储形式

网络存储:

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


          代码实现:

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(); }}

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

 

本文始发于微信公众号(LemonSec):Android系统的五种数据存储形式

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: