Android网络操作与数据存储(二):Android本地数据操作

目录

第一节:Android本地文件操作

一、SharedPreferences

二、外部存储

三、内部存储

第二节:Android数据库操作

SQLite数据库

应用:

关系型数据库

SQLiteOpenHelper

SQLiteDatabase

SQLiteDatabase对象的操作

1、使用SQL语句操作

2、使用API操作

第三节:手风琴特效

第四节:ContentProvider初体验

ContentProvider

ContentResolver

ContentUris类

实例1:获取短信息

实例2:读取联系人

实例3:添加联系人

实例4:自定义ContentProvider


第一节:Android本地文件操作

一、SharedPreferences

存储信息

//获取SharedPreferences对象(参数1:文件名,参数2:模式)
SharedPreferences share=getSharedPreferences("myshare",MODE_PRIVATE);
//获取Editor对象
SharedPreferences.Editor edt=share.edit();
//存储信息
edt.putString("account","admin");
edt.putString("password","123");
//提交操作
edt.commit();

获取信息

SharedPreferences share=getSharedPreferences("myshare",MODE_PRIVATE);
//根据key获取内容(参数1:key,参数2:当key不存在,返回参数2的值作为默认值)
String accStr=share.getString("account","");
string pwdstr=share.getString("password","");

操作模式

MODE_APPEND:追加模式

MODE_PRIVATE:私有方式存储,其他应用无法访问(常用)

MODE_WORLD_READABLE:可被其他应用读取

MODE_WORLD_WRITEABLE:可被其他应用写入

二、外部存储

外部存储ExternalStorage,通常指sdcard文件夹,位置一般在storage或者mnt文件夹,在mnt文件夹可以直接找到sdcard文件夹,而在storage中emulated/0才是真实的外部存储(可能无法直接打开),通常映射到storage/sdcard0文件夹。

  • Environment.getExternalStorageDirectory()获取外部存储的路径
  • Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)获取外部存储共有目录路径

公有目录(DCIM、DOWNLOAD等九大公有目录)

私有目录(Android/data/应用包名)

访问外部存储需要获取权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

动态权限:Android6.0及以后版本中只在Manifest文件中设置权限是不够的,还需要动态申请。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int permission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if(permission!= PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1001);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode==1001){
            //todo
        }
    }

获取外部公有存储目录

File dir=Environment.getExternalStorageDirectory();//.getAbsolutePath()

三、内部存储

内部存储位于应用程序包路径下,不需要获取权限就可以存储,卸载应用程序时所有数据都会删除。内部存储分为内部存储和外部存储两部分。

获取外部私有存储路径

File dir1=getExternalFilesDir(null);//.getAbsolutePath()
File dir2=getExternalCacheDir();//.getAbsolutePath()

获取内部存储路径

File dir1=getFilesDir();
File dir2=getCacheDir();

读文件操作

                try {
                    InputStream inputStream=new FileInputStream(file);//file要读取的文件
                    byte[] bytes=new byte[1024];
                    int len=0;
                    StringBuilder builder=new StringBuilder();
                    while((len=inputStream.read(bytes))!=-1){
                        String str=new String(bytes,0,len);
                        builder.append(str);
                    }
                    mTxtShow.setText(builder.toString());//结果显示在mTxtshow中
                    inputStream.close();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

写文件操作

                try {
                    OutputStream outputStream=new FileOutputStream(file);//写入文件file
                    String datas=mEdtInput.getText().toString();//从mEdtInput中读入
                    outputStream.write(datas.getBytes());
                    outputStream.close();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

第二节:Android数据库操作

SQLite数据库

SQLite 是一个开源的关系型数据库,实现自包容、零配置、支持事务的SQL数据库引擎。 其特点是高度便携、使用方便、结构紧凑、高效、可靠。

SQLite数据库是个轻量级的数据库,本质上是个二进制文件。

应用:

对数量要求不高的本地查询。如:个人博客、本地应用程序(skype、火狐、chrome、Photoshop等)、嵌入式系统程序。

关系型数据库

以行和列的形式存储数据、以便于用户理解。这一系列的行和列被称为表,一组表组成了数据库。

SQL语言包括四种主要程序设计语言类别的语句:数据定义语言(DDL),数据操作语言(DML),数据控制语言(DCL)和事务控制语言(TCL)。

数据定义语言(DDL):

CREATE TABLE <表名>

(<列名1> <数据类型> [列级完整性约束条件] [,<列名2> <数据类型> [列级完整性约束条件]] [<表级完整性约束条件>]);

String sql="create table tb_info (_id integer primary key autoincrement,"+
                        "name varchar(30) not null,"+
                        "age integer,"+
                        "gender varchar(2) not null"+
                        ")";

数据操作语言(DML):

添加:

  • INSERT INTO 表名(列1,列2) VALUES (值1,值2)
  • INSERT INTO 表名 VALUES (值1,值2,值3)

删除:

  • DELETE FROM 表名 [WHERE <删除条件>]

修改:

  • UPDATE 表名 SET 列名1 = 更新值1,列名2=更新值2,… 列名n=更新值n [WHERE <更新条件>]

查询:

  • SELECT * FROM 表名 [WHERE <查询条件>]

SQLiteOpenHelper

  • Android平台里一个数据库辅助类,用于创建或打开数据库,并且对数据库的创建和版本进行管理。
        SQLiteOpenHelper helper=new SQLiteOpenHelper(context,"stu.db",null,1) {
            @Override
            public void onCreate(SQLiteDatabase sqLiteDatabase) {
                String sql="create table if not exists tb_stuinfo ( _id integer primary key,"+
                        "name varchar(50) not null,"+
                        "gender varchar(2) not null,"+
                        "age integer)";
                sqLiteDatabase.execSQL(sql);
            }

            @Override
            public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

            }
        };

SQLiteDatabase

  • 用于管理和操作SQLite数据库,几乎所有的数据库操作,最终都将由这个类完成。
//用于获取数据库对象
//1、如果数据库存在,则直接打开数据库
//2、如果数据库不存在,则调用数据库创建方法,再打开数据库
//3、如果数据库存在,但版本升高了,则调用数据库升级方法,再打开数据库
mDatabase=helper.getReadableDatabase();

SQLiteDatabase对象的操作

1、使用SQL语句操作

                String sql="select * from tb_stuinfo where _id=?";
                Cursor cursor = mDatabase.rawQuery(sql, new String[]{id});
                SimpleCursorAdapter adapter=new SimpleCursorAdapter(this,
                        R.layout.item_stu,
                        cursor,
                        new String[]{"_id","name","gender","age"},
                        new int[]{R.id.item_stu_id,R.id.item_stu_name,R.id.item_stu_gender,R.id.item_stu_age},
                        CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
                mLvStuInfo.setAdapter(adapter);
        //添加
        String sql="insert into tb_stuinfo values(null,?,?,?)";
        mDatabase.execSQL(sql,new String[]{stu.getName(),stu.getGender(),stu.getAge()+""});
        //删除
        String sql="delete from tb_stuinfo where _id=?";
        mDatabase.execSQL(sql,new String[]{id});
        //修改
        String sql="update tb_stuinfo set name=?,gender=?,age=? where _id=?";
        mDatabase.execSQL(sql,new String[]{stu.getName(),stu.getGender(),stu.getAge()+"",stu.getId()+""});

2、使用API操作

参数1:表名
参数2:所要查询的列。{”name","age","gender"},查询所有传入null/{“*”}
参数3:条件(针对列)。"_id=?"
参数4:条件参数。new String[]{id}
参数5:分组
参数6:当 group by对数据进行分组后,可以通过having来去除不符合条件的组
参数7:排序

mDatabase.query("tb_stuinfo",null,null,null,null,null,null);

补充:聚合函数,用于统计数据的函数。

select count(*),age from tb_stuinfo group by age having age>23 order by age desc;//按年龄段分组统计,只统计年龄大于23的结果,按年龄降序排列。

Cursor使用

SimpleCursorAdapter adapter = new SimpleCursorAdapter(
                        this,
                        R.layout.item,
                        cursor,
                        new String[]{"_id", "name", "age", "gender",},
                        new int[]{R.id.id_item_tv, R.id.name_item_tv, R.id.age_item_tv, R.id.gender_item_tv},
                        CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

 1、SimpleCursorAdapter 定义时要求必须要有_id列,如果没有就会报错;
 2、SimpleCursorAdapter第六个参数是保证数据库发生变化时页面也产生更新
    FLAG_REGISTER_CONTENT_OBSERVER:3.0版本以后使用
    FLAG_AUTO_REQUERY:3.0版本以前使用,已经废弃

参数1:所要操作的数据库表的名称

参数2:可以为空的列。如果第三个参数是null或者说里面没有数据,那么我们的sql语句就会变为insert into info_tb () values ()  ,在语法上就是错误的,此时通过参数2指定一个可以为空的列,语句就变成了insert into info_tb (可空列) values (null)

返回值:long类型,新插入行的id

 

ContentValues value=new ContentValues();
value.put("name","张三");
value.put("age",18);
value.put("gender","男");
long newId=mDatabase.insert("tb_stuinfo",null,value);
int count=mDatabase.delete("tb_stuinfo","_id=?",new String[]{"12"});
ContentValues value=new ContentValues();
value.put("name","张三");
value.put("age",18);
value.put("gender","男");
mDatabase.update("tb_stuinfo",value,"_id=?",new String[]{"12"});

 

第三节:手风琴特效

ExpandableListView:一个可以垂直滚动的两级列表。它与ListView的区别是包含可以独立展开的二级分组。它使用ExpandableListAdapter关联数据。

XML Attributes:

Public Methods:

案例:

从网络获取分组列表数据并显示在ExpandableListView中。

思路:

1、创建ExpandableListView,使用ExpandableListAdapter加载本地模拟数据。

2、异步获取网络数据替换ExpandableListAdapter中数据,并刷新。

3、创建本地数据库缓存网络数据,优先加载本地数据,获取失败再从网络读取。

关键代码:

public class ChapterAdapter extends BaseExpandableListAdapter {

    private Context mContext;
    private List<Chapter> mDatas;
    private LayoutInflater mInflater;

    public ChapterAdapter(Context context, List<Chapter> chapters) {
        mContext = context;
        mDatas = chapters;
        mInflater = LayoutInflater.from(context);
    }


    @Override
    public int getGroupCount() {
        return mDatas.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return mDatas.get(groupPosition).getChildren().size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return mDatas.get(groupPosition);
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return mDatas.get(groupPosition).getChildren().get(childPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }


    // TODO
    @Override
    public boolean hasStableIds() {
        return false;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {


        ParentViewHolder vh;
        if (convertView == null) {
            // 修改item height即可演示,第二个参数作用
            convertView = mInflater.inflate(R.layout.item_parent_chapter, parent, false);
            vh = new ParentViewHolder();
            vh.tv = convertView.findViewById(R.id.id_tv_parent);
            vh.iv = convertView.findViewById(R.id.id_indicator_group);
            convertView.setTag(vh);

        } else {
            vh = (ParentViewHolder) convertView.getTag();
        }
        vh.tv.setText(mDatas.get(groupPosition).getName());
        vh.iv.setSelected(isExpanded);

        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {


        ChildViewHolder vh;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.item_child_chapter, parent, false);
            vh = new ChildViewHolder();
            vh.tv = convertView.findViewById(R.id.id_tv_child);

            convertView.setTag(vh);

        } else {
            vh = (ChildViewHolder) convertView.getTag();
        }
        vh.tv.setText(mDatas.get(groupPosition).getChildren().get(childPosition).getName());
        return convertView;
    }

    // 控制child item不可点击
    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {

        return true;
    }

    public static class ParentViewHolder {
        TextView tv;
        ImageView iv;
    }

    public static class ChildViewHolder {
        TextView tv;
    }

}

源码:点击下载

 

第四节:ContentProvider初体验

ContentProvider

Android四大组件之一,为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。对于ContentProvier而言,无论数据的来源是什么,它都认为是种表,然后把数据组织成表格。

某个应用程序通过ContentProvider暴露了自己的数据操作接口,那么不管该应用程序是否启动,其他应用程序都可以通过这个接口来操作它的内部数据。

Android附带了许多有用的ContentProvider,包括:

  • Browser:存储如浏览器的信息。
  • CallLog:存储通话记录等信息。
  • Contacts:存储联系人等信息。
  • MediaStore:存储媒体文件的信息。
  • Settings:存储设备的设置和首选项信息。

ContentProvider是抽象类,使用时需要自定义类继承于ContentProvider,必须实现以下方法:

Data access methods (such as insert(Uri, ContentValues) and update(Uri, ContentValues, String, String[])) may be called from many threads at once, and must be thread-safe. Other methods (such as onCreate()) are only called from the application main thread, and must avoid performing lengthy operations. 

ContentResolver

ContentResolver,内容访问者。可以通过ContentResolver来操作ContentProvider所暴露处理的接口。一般使用Content.getContentResolver()方法获取ContentResolver对象。ContentResolver 类提供了与ContentProvider类相同的4个方法insert、query、update、delete用来操作ContentProvider。

ContentUris类

方法:

应用:ContentProvider中insert方法返回的id,传递给ContentResolver 中insert方法。

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        long id = mDatabase.insert("info_tb", null, values);
        Uri uriWithId = ContentUris.withAppendedId(uri, id);
        return uriWithId;
    }
                Uri uri = mResolver.insert(uri, values);
                long newID = ContentUris.parseId(uri);
                Toast.makeText(this, "添加成功,新学生的学号是:"+newID, Toast.LENGTH_SHORT).show();

补充内容,Android中的URI 和Uri:https://blog.csdn.net/qq_33275597/article/details/80029792

实例1:获取短信息

       findViewById(R.id.sms_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //1.获取内容处理者
                ContentResolver resolver = getContentResolver();
                //2.查询方法
                //sms: short message service
                //    content://sms     短信箱
                //    content://sms/inbox     收件箱
                //     content://sms/sent       发件箱
                //      content://sms/draft     草稿箱
                Uri uri = Uri.parse("content://sms/draft");
                Cursor c = resolver.query(uri,null,null,null,null);
                //3.解析Cursor
                //遍历Cursor
                while(c.moveToNext()){
                    //对象,内容
                    //参数:列索引
                    //c.getString(2);
                    //遍历该行的列
                    String msg = "";

                    String address = c.getString(c.getColumnIndex("address"));
                    String body = c.getString(c.getColumnIndex("body"));

                    msg = address + ":" + body;
                    /*
                    for(int i = 0 ; i < c.getColumnCount() ; i++){
                        msg += c.getString(i) + "  ";
                    }
                    */
                    Log.e("TAG",msg);
                }
            }
        });

实例2:读取联系人

        findViewById(R.id.read_contact_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ContentResolver resolver = getContentResolver();
                //对于联系人而言,他们的存储方式是将姓名和其他内容(电话号码)由不同点contentProvider操作的
                //首先想象姓名和其他内容属于不同的表
                //而姓名所在的表是主表,其他内容位于从表
                //而主表中的主键会在从表中作为外键使用
                Cursor c1 = resolver.query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);
                while(c1.moveToNext()){

//                    ContactsContract.Contacts.DISPLAY_NAME    姓名
//                    ContactsContract.Contacts._ID     主键
                    String name = c1.getString(c1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                    String _id = c1.getString(c1.getColumnIndex(ContactsContract.Contacts._ID ));
                    Log.e("TAG","姓名是:" + name +" , id是" + _id);

                    String selections = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?";
                    Cursor c2 = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                            null,
                            selections,
                            new String[]{_id},
                            null);
                    while(c2.moveToNext()){
                        String number = c2.getString(c2.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                        name += "   " + number;
                    }

                    Log.e("TAG" , name);
                    /*
                    String msg = "";
                    for(int i = 0 ; i < c1.getColumnCount() ; i++){
                        msg += c1.getString(i) + "  ";
                    }
                    Log.e("TAG",msg);
                    */

                }
            }
        });

实例3:添加联系人

        findViewById(R.id.add_contact_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ContentResolver resolver = getContentResolver();

                //1.往一个ContentProvider中插入一条空数据,获取新生成的id
                //2.利用刚刚生成的id分别组合姓名和电话号码往另一个ContentProvider中插入数据U
                ContentValues values = new ContentValues();
                Uri uri = resolver.insert(ContactsContract.RawContacts.CONTENT_URI,values);
                long id = ContentUris.parseId(uri);

                //插入姓名
                //指定姓名列的内容
                values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,"Tommy");
                //指定和姓名关联的编号列的内容
                values.put(ContactsContract.Data.RAW_CONTACT_ID,id);
                //指定该行数据的类型
                values.put(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
                resolver.insert(ContactsContract.Data.CONTENT_URI,values);

                //插入电话号码
                //清空ContentValues对象
                values.clear();
                //指定电话号码列的内容
                values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, "15789065588");
                //指定和电话号码关联的编号列的内容
                values.put(ContactsContract.Data.RAW_CONTACT_ID,id);
                //指定该行数据的类型
                values.put(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
                //指定联系方式的类型
                values.put(ContactsContract.CommonDataKinds.Phone.TYPE,
                        ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);

                resolver.insert(ContactsContract.Data.CONTENT_URI,values);
            }
        });

实例4:自定义ContentProvider

一、数据提供程序

1、创建自定义类

public class MyContentProvider extends ContentProvider {
    public MyContentProvider() {
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // Implement this to handle requests to delete one or more rows.
        int result=mDatabase.delete("info_tb",selection,selectionArgs);
        return result;
    }

    @Override
    public String getType(Uri uri) {
        // TODO: Implement this to handle requests for the MIME type of the data
        // at the given URI.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        long id = mDatabase.insert("info_tb", null, values);
        Uri uriWithId = ContentUris.withAppendedId(uri, id);
        return uriWithId;
    }

    SQLiteDatabase mDatabase;
    @Override
    public boolean onCreate() {
        // TODO: Implement this to initialize your content provider on startup.
        SQLiteOpenHelper helper=new SQLiteOpenHelper(getContext(),"stu.db",null,1) {
            @Override
            public void onCreate(SQLiteDatabase sqLiteDatabase) {
                String sql = "create table info_tb (_id integer primary key autoincrement," +
                        "name varchar(20)," +
                        "age integer," +
                        "gender varchar(2))";
                sqLiteDatabase.execSQL(sql);
            }

            @Override
            public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

            }
        };
        mDatabase=helper.getReadableDatabase();
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        // TODO: Implement this to handle query requests from clients.
        Cursor cursor = mDatabase.query("info_tb", projection, selection, selectionArgs, null, null, sortOrder);
        return cursor;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        // TODO: Implement this to handle requests to update one or more rows.
        int update = mDatabase.update("info_tb", values, selection, selectionArgs);
        return update;
    }
}

2、在Manifest文件中添加如下代码

    <application
        。。。

        <provider
            android:name=".MyContentProvider"
            android:authorities="com.imooc.myprovider"
            android:enabled="true"
            android:exported="true"></provider>
    </application>

二、其他程序访问数据的代码

    private String mGender;
    private ContentResolver mResolver;


    @Override
    public void onClick(View view) {
        String name = mEdtName.getText().toString();
        String age = mEdtAge.getText().toString();
        String id = mEdtID.getText().toString();

        Uri uri = Uri.parse("content://com.imooc.myprovider");
        switch (view.getId()) {
            case R.id.insert_btn: {//添加
                ContentValues values=new ContentValues();
                values.put("name",name);
                values.put("age",age);
                values.put("gender",mGender);
                Uri uri2 = mResolver.insert(uri, values);
                long newID = ContentUris.parseId(uri2);
                Toast.makeText(this, "添加成功,新学生的学号是:"+newID, Toast.LENGTH_SHORT).show();
                break;
            }
            case R.id.search_btn: {//查询
                Cursor cursor = mResolver.query(uri, null, null, null, null);
                SimpleCursorAdapter adapter = new SimpleCursorAdapter(
                        this,
                        R.layout.item,
                        cursor,
                        new String[]{"_id", "name", "age", "gender",},
                        new int[]{R.id.id_item_tv, R.id.name_item_tv, R.id.age_item_tv, R.id.gender_item_tv},
                        CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
                mLvShowInfo.setAdapter(adapter);
                break;
            }
            case R.id.update_btn: {//修改
                ContentValues values=new ContentValues();
                values.put("name",name);
                values.put("age",age);
                values.put("gender",mGender);
                int update = mResolver.update(uri, values, "_id=?", new String[]{id});
                if(update>0){
                    Toast.makeText(this, "修改成功", Toast.LENGTH_SHORT).show();
                }else{
                    Toast.makeText(this, "修改失败", Toast.LENGTH_SHORT).show();
                }
                break;
            }
            case R.id.delete_btn: {//删除
                int delete = mResolver.delete(uri, "_id=?", new String[]{id});
                if(delete>0){
                    Toast.makeText(this, "删除成功", Toast.LENGTH_SHORT).show();
                }else{
                    Toast.makeText(this, "删除失败", Toast.LENGTH_SHORT).show();
                }
                break;
            }
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值