Android开发从0开始(ContentProvider与数据)

内容提供者:ContentProvider

  为App存取内部数据提供外部接口,让不同应用共享数据。

①在配置里AndroidManifest.xml       

 <provider

            android:name=".UserInfoProvider"

            android:authorities="com.example.chapter07_server.provider.UserInfoProvider"

            android:enabled="true"

            android:exported="true"/>

危险权限表

运行时动态申请权限Lazy模式:

①检查是否开启指定权限:

public class PermissionUtil {

    //检查权限,返回true则已完全启用权限,返回false表示未完全启用权限

    public static boolean checkPermission(Activity act,String[] permissions,int requestCode)

    {

        int check = PackageManager.PERMISSION_GRANTED;

        //逐一将各个权限取出判断

        for(String permission: permissions){

            ContextCompat.checkSelfPermission(act,permission);

            check=ContextCompat.checkSelfPermission(act,permission);

            if(check!=PackageManager.PERMISSION_GRANTED){break;}

        }

  //②若有未开启的权限,则请求系统弹窗

        if (check!=PackageManager.PERMISSION_GRANTED){

            ActivityCompat.requestPermissions(act,permissions,requestCode);

            return false;

        }

            return true;   }  }

  ③判断用户的权限选择结果

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        //判断用户是否授权

        switch (requestCode){

            case REQUEST_CODE_CONTACTS:

                if(PermissionUtil.checkGRant(grantResults)){

                    Log.d("ning","通讯录权限获取成功");

                }else

                {

                    Log.d("ning","获取通讯录读写权限失败");

                }

                break;

            case REQUEST_CODE_SMS:

                if (PermissionUtil.checkGRant(grantResults)){

                    Log.d("ning","收发短信权限获取成功");

                }else

                {

                    Log.d("ning","收发短信权限获取失败");

  jumpToSetting();

                }

                break;    }    }

    //跳转带应用设置界面

    private  void jumpToSetting(){

        Intent intent = new Intent();

        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

        intent.setData(Uri.fromParts("package",getPackageName(),null));

        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        startActivity(intent);

    }

运行时动态申请权限Hunger模式:直接在onCreate中申请所有权限。

ContentResovler基本用法

添加联系人:

public void onClick(View view) {

        int id = view.getId();

        if (id == R.id.add) {//创建一个联系人对象

            Contact contact = new Contact();

            contact.name= et_name.getText().toString().trim();

            contact.email=et_email.getText().toString().trim();

            contact.phone=et_phone.getText().toString().trim();

            //方法一,使用ContentResolver多次写入.

            addContacts(getContentResolver(),contact);

        } else if (id == R.id.find) {

        }

}

    //往手机通讯录里添加一个联系人

    private void addContacts(ContentResolver resolver, Contact contact) {

        ContentValues values = new ContentValues();

        Uri uri= resolver.insert(ContactsContract.RawContacts.CONTENT_URI,values);

        long rawContactId = ContentUris.parseId(uri);

        ContentValues name = new ContentValues();

        //关联联系人编号

        name.put(Contacts.Data.RAW_CONTACT_ID,rawContactId);

        //"姓名"数据类型

        name.put(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);

        //联系人的姓名

        name.put(Contacts.Data.DATA2,contact.name);

        //往提供器添加联系人姓名

        resolver.insert(ContactsContract.Data.CONTENT_URI,name);

        ContentValues phone = new ContentValues();

        //关联联系人编号

        phone.put(Contacts.Data.RAW_CONTACT_ID,rawContactId);

        //"电话号码"数据类型

        phone.put(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);

        //联系人的电话号码

        phone.put(Contacts.Data.DATA2,contact.phone);

        phone.put(Contacts.Data.DATA2,CommonDataKinds.phone.TYPE_MOBILE);

        //往提供器添加联系人姓名电话号码

        resolver.insert(ContactsContract.Data.CONTENT_URI,phone);

        ContentValues email = new ContentValues();

        //关联联系人编号

        email.put(Contacts.Data.RAW_CONTACT_ID,rawContactId);

        //"邮箱"数据类型

        email.put(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);

        //联系人的邮箱

        email.put(Contacts.Data.DATA2,contact.email);

        //往提供器添加联系人邮箱

        resolver.insert(ContactsContract.Data.CONTENT_URI,email);

    }

批量处理添加联系人:

private void addFullContacts(ContentResolver resolver , Contact contact){

        //构建一个插入联系人主记录的内容操作器

        ContentProviderOperation op_main=ContentProviderOperation

                .newInsert(ContactsContract.RawContacts.CONTENT_URI)

                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME,null)

                .build();

      //构建对于姓名的操作

      ContentProviderOperation op_name= ContentProviderOperation

              .newInsert(ContactsContract.RawContacts.CONTENT_URI)

              .withValueBackReference(Contacts.Data.RAW_CONTACT_ID,0)

              .withValue(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)

              .withValue(Contacts.Data.DATA2,contact.name)

              .build();

        //构建对于电话号码操作

        ContentProviderOperation phone= ContentProviderOperation

                .newInsert(ContactsContract.RawContacts.CONTENT_URI)

                .withValueBackReference(Contacts.Data.RAW_CONTACT_ID,0)

                .withValue(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)

                .withValue(Contacts.Data.DATA2,contact.phone)

                .build();

        //构建对于邮箱的操作

        ContentProviderOperation email= ContentProviderOperation

                .newInsert(ContactsContract.RawContacts.CONTENT_URI)

                .withValueBackReference(Contacts.Data.RAW_CONTACT_ID,0)

                .withValue(Contacts.Data.MIMETYPE,CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)

                .withValue(Contacts.Data.DATA2,contact.email)

                .build();

        //构建列表将三个操作放入

        ArrayList<ContentProviderOperation> operations=new ArrayList<>();

        operations.add(op_main);

        operations.add(op_name);

        operations.add(phone);

        operations.add(email);

        //批处理提交四个操作

        try {

            resolver.applyBatch(ContactsContract.AUTHORITY,operations);

        } catch (OperationApplicationException e) {

            throw new RuntimeException(e);

        } catch (RemoteException e) {

            throw new RuntimeException(e);      }    }

批量查询联系人:

     //查询通讯录信息

    @SuppressLint("Range")

    private void readPhoneContacts(ContentResolver resolver ) {

      Cursor cursor= resolver.query(ContactsContract.RawContacts.CONTENT_URI,new String[]{ContactsContract.RawContacts._ID},null,null,null,null);

      while (cursor.moveToNext()){

          int rawContactId = cursor.getInt(0);

          Uri uri = Uri.parse("content://com.android.contacts/contacts"+rawContactId+"/data");

        Cursor dataCursor=resolver.query(uri,new String[]{Contacts.Data.MIMETYPE,Contacts.Data.DATA1,Contacts.Data.DATA2},null,null,null);

        Contact contact = new Contact();

        while (dataCursor.moveToNext()){

           String data1= dataCursor.getString(dataCursor.getColumnIndex(Contacts.Data.DATA1));

           String mimeType=dataCursor.getString(dataCursor.getColumnIndex(Contacts.Data.MIMETYPE));

           switch (mimeType){

               case CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE:

                   contact.name=data1; break;

               case CommonDataKinds.Email.CONTENT_ITEM_TYPE:

                   contact.Email=data1; break;

               case CommonDataKinds.Phone.CONTENT_ITEM_TYPE:

                   contact.Phone=data1; break;

           }

        }

        dataCursor.close();

      }

      cursor.close();   }

ContentObserver监听短信:

  public class MonitorSmsActivity extends AppCompatActivity {

    private SmsGetObserver mObserver;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_monitor_sms);

        //指定一个注册内容观察器,一单数据发生变化,就触发OnChange方法

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

        mObserver = new SmsGetObserver(this);

        getContentResolver().registerContentObserver(uri,true,mObserver);

    }

    protected void onDestroy(){

        super.onDestroy();

        getContentResolver().unregisterContentObserver(mObserver);

    }

    private static class SmsGetObserver extends ContentObserver {

        private final Context mContext;

        public SmsGetObserver(Context context){

            super(new Handler(Looper.getMainLooper()));

            this.mContext=context;   }

public void onChange(boolean selfChange, @Nullable Uri uri){

            super.onChange(selfChange,uri);   

            if(uri==null){return;}

            if(uri.toString().contains("content://sms/raw")||uri.toString().equals("content://sms")) {return;}

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

            if(cursor.moveToNext()){

                //短信的发送号码

                @SuppressLint("Range")  String sender=cursor.getString(cursor.getColumnIndex("address"));

                @SuppressLint("Range")  String content=cursor.getString(cursor.getColumnIndex("body"));

                Log.d("ning",String.format("sender:%s,content:%s",sender,content));

            }

            cursor.close();

        }

    }   }

跳转选择图片:

  ①创建意图

  Intent intent = new Intent(Intent.ACTION_GET_CONTENT );

②设置图片内容类型与跳转

Intent.setType(image/*);

mResultLauncher.launch(intent );

FileProvider:

 继承于ContentProvider,对第三方应用暴露文件,并授权读写操作的权限。

①首先在AndroidManifest.xml文件中配置

        <provider

            android:authorities="@string/file_provider"

            android:name="androidx.core.content.FileProvider"

            android:grantUriPermissions="true">

        <!--配置哪些路径是可以通过FileProvider访问-->

            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"

                android:resource="@xml/file_paths"/>

        </provider>

②其次在对应路径xml的文件夹中的file_paths中写配置文件。

③在代码中对应实现。  

访问其他程序中的数据:

  ①使用现有的内容提供器来读取和操作相应的程序数据

  ②创建自己的内容提供器给我们程序的数据提供外部访问接口。

Notification通知栏的使用:

   Notification notification = new Notification.Builder(this)

         .setContentTitle("this is content title") //指定通知栏标题内容

         .setContentText("this is content text")//指定通知栏正文内容

         .setWhen(System.currentTimeMillis())//创建时间

         .setSmallIcon(R.mipmap.ic_launcher) //通知栏小图标

         .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))

                    .build(); //通知栏大图标

           manager.notify(NOTIFICATION_ID, notification); //通道号要提前创建

                       参数1:通道号  参数2:notification对象

PendingIntent延迟意图:

   方法1:getActivity()

   方法2:getBroadcast()

   方法3:getService()

以上均为三个参数:参1:Context 。参2:一般不用传0。参数3:意图

参数4:确定行为FLAG_ONESHOT,FLAG_NO_CREATE,FLAG_CANCEL,FLAG_UPDATE_CURRENT通常可以填0.

点击后图标消失:

①在后部分调用.setAutoCancel( true )方法

②在onCreate中

NotificationManager manager = (Notif icat ionManager) getSystemService

(NOTIFICATION_ SERVICE) ; //注册管理器

manager . cancel((NOTIFICATION_ID); . //注册取消。

调用摄像头

  ①创建File对象,用于存储。

  ②调用getExternalCacheDir( )方法获取目录。

  ③做版本适配

  ④用intent去启动摄像头。

注意调用都有权限注册。

播放音频:

一般使用MediaPlayer类实现,常用方法如下

调用播放视频

一般使用VideoView类的方法。

数据存储部分:

 共享参数-SharedPreferences:轻量级存储工具,Key-Value形式。

使用场景:

  ①简单且孤立的数据。

  ②文本形式数据。

  ③需要持久化存储的数据。

  ④App个性化配置信息,用户使用App行为信息。

  ⑤临时片段信息。

 getSharedPreferences("config", Context.MODE_PRIVATE);

①然后先ALT+ENTER声明成变量,再Ctrl+ALT+F变全局

private SharedPreferences preferences;

preferences = getSharedPreferences("config", Context.MODE_PRIVATE);

//在下面监听

public void onClick(View view) {

        String name = et_name.getText().toString();

        String age = et_age.getText().toString();

        String height = et_height.getText().toString();

        String weight = et_weight.getText().toString();

        //获取编辑器

        SharedPreferences.Editor editor = preferences.edit();

        editor.putString("name",name);

        editor.putInt("age", Integer.parseInt(age));

        editor.putFloat("height",Float.parseFloat(height));

        editor.putFloat("weight",Float.parseFloat(weight));

        editor.putBoolean("married",gr_married.isChecked());

        editor.commit();

}

②重新再取数据:(通过键值对取)

        String name= preferences.getString("name","");

SQLite

(1) 数据定义语言

CREATE TABLE IF NOT EXISTS 表名(

字段A PRIMARY KEY

字段B,

字段C

支持类型

NULL:表示空值。

INTEGER:表示整数,可以存储整数值。

REAL:表示浮点数,可以存储浮点数值。

TEXT:表示文本,可以存储字符串。

BLOB:表示二进制数据,可以存储任意二进制数据。

(2)删除表格:

 DROP TABLE IF EXISTS user_info

(3)修改表格:

ALTER TABLE user_info ADD COLUMN phone VARCHAR;

(只支持增加字段,不支持修改,删除字段)添加多列就分多次。

(4)数据操作语言与其他数据库相似

  1. SQLite Database 数据库管理器

  1,管理类:

  OpenDatabase():打开指定路径数据库。

  isOpen():判断数据库是否已经打开。

Close():关闭数据库。

getVersion():获取版本。

SetVersion():设置数据库版本。

  2,事务类:

beginTransaction:开始事物。

SetTransactionSuccessful:设置事务的成功标志.

endTransaction:结束事务。

创建数据库,删除数据库:

①首先在全局生命这个数据库名

private String mDataBaseName;

mDataBaseName = getFilesDir() + "/test.db";

    public void onClick(View view) {

      int id = view.getId();

      if (id == R.id.btn_database_create) {

            //打开数据库,参数1:数据库名地址+名字,参数2:打开模式,参数3:游标

SQLiteDatabase db = openOrCreateDatabase(mDataBaseName, Context.MODE_PRIVATE, null);

            //输出化语言:

String desc = String.format("数据库%s创建%s", db.getPath(), (db != null) ? "成功" : "失败");

            tv_database.setText(desc);}

else if (id == R.id.btn_database_delete) {

            //删除数据库

            boolean result = deleteDatabase(mDataBaseName);

String desc_fail = String.format("数据库%s删除%s", mDataBaseName, result ? "成功" : "失败");

tv_database.setText(desc_fail);   }    }

数据库所在路径:data->data->包名->file

页面与数据库交互SQLiteOpenhelper

两个抽象方法: onCreate ( ), onUpgrade ( )

两个重要实例方法getReadableDatabase( ), getWritableDatabase( )。均可创建或打开数据库。

(6)事务管理:(一致性,原子性)

  beginTransaction:开始事务.

  setTransactionSuccessful:设置事务的成功标志.

endTransaction:结束事务.

若事务失败泽会回滚操作,保证原子性。

  1. 外部存储空间

定义部分

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.File;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import java.nio.Buffer;

public class FileUtil {

    //把字符串保存到指定路径

    public static void saveText(String path,String txt){

        BufferedWriter os =null;  //创建一个os

        try {os = new BufferedWriter(new FileWriter(path));  //new一个对象,其中包含指定路径

            os.write(txt);                                  //将txt 写入该路径

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            if (os!=null)

            {

                try {

                    os.close();

                }catch (IOException e){

                    e.printStackTrace();

                }

            }

        }

    }

    //从指定路径读取内容字符串

    public static String openText(String path){

        BufferedReader is=null;

        StringBuilder sb =new StringBuilder();

        try {

            is =new BufferedReader(new FileReader(path));

            String line = null;

            while ((line=is.readLine())!=null){

                sb.append(line);

            }

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            if (is!=null)

            {

                try {

                    is.close();

                }catch (IOException e){

                    e.printStackTrace();

                }

            }

        }

        return sb.toString();

    }

}

引用部分:

      //外部存储的私有空间写入

  String directory = null; //创建一个字符串

  String fileName = System.currentTimeMillis()+".txt"; //创建一个当前时间的文件名

  directory = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(); //获取路径

  path =directory + File.separatorChar+fileName;  //构建完整路径

                FileUtil.saveText(path,sb.toString());          //进行保存

                ToastUtil.show(this,"保存成功");

//外部存储的私有空间读出

tv_txt.setText(FileUtil.openText(path))

外部存储公有空间:还要手机获取权限

directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();

(7)存储卡上读写图片文件

BitmapFactory工具用于读取各种来源的图片:相关方法如下:

decodeResource:该方法可从资源文件中读取图片信息。

DecodeFile:该方法可将指定路径的图片读取到Bitmap对象。

DecodeStream:该方法从输入流中读取位图数据。

①定义触发保存事件

    public void onClick(View view) {

        int id = view.getId();

        if (id == R.id.btn_save) {

            String fileName = System.currentTimeMillis() + ".jpeg";

            //获取当前App的私有下载目录

            path = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + File.separatorChar + fileName;

            //从指定资源文件获取位图像对象

            Bitmap b1 = BitmapFactory.decodeResource(getResources(), R.drawable.ting1);

            //将位图对象保存下来

            FileUtil.saveImage(path, b1);

            ToastUtil.show(this, "保存成功");

        } else if (id == R.id.btn_read) {

            Bitmap b2 = FileUtil.openImage(path);

            iv_content.setImageBitmap(b2);

         }    }

②对应保存

   //把位图数据保存到指定路径的图片文件

    public static void saveImage(String path, Bitmap b1) {

        FileOutputStream fos = null;

        try{

            fos=new FileOutputStream(path);

            //把位图数据压缩到文件流中

            b1.compress(Bitmap.CompressFormat.JPEG,100,fos);}

        catch (Exception e){ e.printStackTrace(); }finally {

            //关闭输入输出流

            if(fos!=null){

                try {   fos.close();   }catch (IOException e){

                    e.printStackTrace();  }  }   }   }

③读取相应位图

    //从指定路径读取位图数据

    public static Bitmap openImage(String path) {

            Bitmap bitmap=null;

            FileInputStream fis=null;

            try {

                fis =new FileInputStream(path);

                bitmap = BitmapFactory.decodeStream(fis);

            }catch (Exception e){

                e.printStackTrace();

            }finally {

                if (fis!=null){

                    try {

                        fis.close();

                    }catch (IOException e)

                    {

                        e.printStackTrace();

                    }      }     }  return bitmap; }

(8)Application生命周期

  在App运行过程中有且仅有一个Application对象,贯穿生命周期。

public class MyApplication extends Application {

    //在APP启动时调用

    @Override

    public void onCreate() {

        super.onCreate();

        Log.d("ning","onCreate");

    }

    //APP终止(在真实的产品不会回调)

    @Override

    public void onTerminate() {

        super.onTerminate();

        Log.d("ning","onTerminate");

    }

    //配置改变时调用

    @Override

    public void onConfigurationChanged(@NonNull Configuration newConfig) {

        super.onConfigurationChanged(newConfig);

    }

}

  1. Application全局变量

适用于会频繁读取的信息,如用户名,手机号。

不方便由意图传输的数据,例如位图对象,非字符串类型。

容易因频繁分配内存导致的内存泄漏的对象,Handler等。可以采用单例模式。

操作:

  • private static MyApplication mApp;  //定义一个私有静态的实例MyApplication名为app
  • public static MyApplication getInstance(){   return mApp; }//获取单例,返回mApp
  • public void onCreate() {

super.onCreate();   mApp = this; }//在oncreate里实例化,将this指针地址给mApp

④在外部再调用MyApplication.getInstance();

  1. JetPackRoom:

Room框架通过注解技术简化数据库操作

在build.gradle的dependencies中配置    

implementation 'androidx.room:room-runtime:2.2.5'// 导入 Room 依赖库

annotationProcessor 'androidx.room:room-compiler:2.2.5'// 导入注解处理器 ( Java )

编写一个表对应的实体类Bookinfo

package com.example.myapplication.enity;

import androidx.room.Entity;

import androidx.room.PrimaryKey;

@Entity

public class Bookinfo {

    @PrimaryKey(autoGenerate = true) //自动增长

    private int id;

    private String name;

    private String author;

    private String press;

    private  double price;

    public int getId() {

        return id;

    }

    public void setId(int id) {

        this.id = id;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public String getAuthor() {

        return author;

    }

    public void setAuthor(String author) {

        this.author = author;

    }

    public String getPress() {

        return press;

    }

    public void setPress(String press) {

        this.press = press;

    }

    public double getPrice() {

        return price;

    }

    public void setPrice(double price) {

        this.price = price;

    }

    @Override

    public String toString() {

        return "Bookinfo{" +

                "id=" + id +

                ", name='" + name + '\'' +

                ", author='" + author + '\'' +

                ", press='" + press + '\'' +

                ", price=" + price +

                '}';

    }

}

③编写一个表对应的持久化类BookDao的接口。会自动生产类。

package com.example.myapplication.dao;

import androidx.room.Dao;

import androidx.room.Delete;

import androidx.room.Insert;

import androidx.room.Query;

import androidx.room.Update;

import com.example.myapplication.enity.Bookinfo;

import java.util.List;

@Dao

public interface BookDao {

    @Insert

    void insert(Bookinfo... book);

    @Delete

    void delete(Bookinfo... book);

    @Query("DELETE FROM Bookinfo")

    void deleteAll();

    @Update

    int update(Bookinfo... book);

    @Query("SELECT * FROM bookinfo ")

    List<Bookinfo>queryAll();

    @Query("SELECT * FROM bookinfo WHERE name = :name ORDER BY id DESC limit 1")

    Bookinfo queryByName(String name);

}

④创建一个抽象类:BookDatabase

@Database(entities = {Bookinfo.class},version = 1,exportSchema = true)

public abstract class BookDatabase extends RoomDatabase {

    //获取该数据库中某张表的持久化对象

public abstract BookDao bookDao();   }

⑤在自定义的Application类中声明书籍数据库的唯一实例。

  public class RoomWriteActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText shuming;

    private EditText zuozhe;

    private EditText chubanshe;

    private EditText jiage;

private BookDatabase bookDB;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_room_write);

        shuming = findViewById(R.id.shuming);

        zuozhe = findViewById(R.id.zuozhe);

        chubanshe = findViewById(R.id.chubanshe);

        jiage = findViewById(R.id.jiage);

        findViewById(R.id.btn_chaxun).setOnClickListener(this);

        findViewById(R.id.btn_shanchu).setOnClickListener(this);

        findViewById(R.id.btn_tianjia).setOnClickListener(this);

        findViewById(R.id.btn_xiugai).setOnClickListener(this);

        //从App实例中获取唯一的书籍持续化对象

        bookDB = MyApplication.getInstance().getBookDB();

    }

    @Override

    public void onClick(View view) {

        String  name=shuming.getText().toString();

        String  author=zuozhe.getText().toString();

        String  press=chubanshe.getText().toString();

        String  price=jiage.getText().toString();

        int id = view.getId();

        if (id == R.id.btn_tianjia) {

            Bookinfo b1 = new Bookinfo();

            b1.setName(name);

            b1.setAuthor(author);

            b1.setPress(press);

            b1.setPrice(Double.parseDouble(price));

            bookDao.insert(b1);

        } else if (id == R.id.btn_xiugai) {

            List<Bookinfo> list= bookDao.queryAll();

            for(Bookinfo b:list){

                Log.d("ning",b.toString());

            }

        } else if (id == R.id.btn_shanchu) {

        } else if (id == R.id.btn_chaxun) {

        }

    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/184053.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pytest-pytest-html测试报告这样做,学完能涨薪3k

在 pytest 中提供了生成html格式测试报告的插件 pytest-html 安装 安装命令如下&#xff1a; pip install pytest-html使用 我们已经知道执行用例的两种方式&#xff0c;pytest.main()执行和命令行执行&#xff0c;而要使用pytest-html生成报告&#xff0c;只需要在执行时加…

不小心删除了重要文档?试试这10个工具,成功率高达99%!

微软于今年早些时候发布了下一版本的 Windows 操作系统 Windows 11。测试版已经推出&#xff0c;而稳定版本将于今年晚些时候推出。很多Windows爱好者已经安装了Windows版。毫无疑问&#xff0c;测试版让用户体验了Windows的新功能。然而&#xff0c;测试版中也出现了很多未知的…

mybatis注解方式动态标签时有特殊符号,出现元素内容必须由格式正确的字符数据或标记组成

原始代码demo Select("SELECT COUNT(1) FROM AAAA WHERE name #{nage} AND age< 4") public Integer sumXxxxx(String nage, String age);现需求改为nage可以为空&#xff0c;因此使用了动态拼接 Select("<script> SELECT COUNT(1) FROM AAAA WHERE …

Windows | 模仿网易云任务栏实现自定义按钮及缩略图

前言 最近更新网易云发现任务栏按钮中除了播放相关的按钮&#xff0c;多了一个喜欢的按钮&#xff1a; 之前我一直以为网易云任务栏的按钮只是 Windows 为音乐软件专门提供的&#xff0c;于是我又看了一眼系统自带的播放器&#xff0c;发现并没有爱心按钮&#xff1a; 这时我就…

基于5G+物联网+SaaS+AI的农业大数据综合解决方案:PPT全文44页,附下载

关键词&#xff1a;智慧农业大数据&#xff0c;5G智慧农业&#xff0c;物联网智慧农业&#xff0c;SaaS智慧农业&#xff0c;AI智慧农业&#xff0c;智慧农业大数据平台 一、智慧农业大数据建设背景 1、应对全球人口快速增长带来的粮食生产压力&#xff0c;未来的粮食生产力必…

【C++】:多态

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关多态的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结…

Python Opencv实践 - 全景图片拼接stitcher

做一个全景图片切片的程序Spliter 由于手里没有切割好的全景图片资源&#xff0c;因此首先写了一个切片的程序spliter。 如果有现成的切割好的待拼接的切片文件&#xff0c;则不需要使用spliter。 对于全景图片的拼接&#xff0c;需要注意一点&#xff0c;各个切片图片之间要有…

什么是机器学习

前言 机器学习&#xff08;Machine Learning, ML&#xff09;是一个总称&#xff0c;用于解决由各位程序员自己基于 if-else 等规则开发算法而导致成本过高的问题&#xff0c;想要通过帮助机器 「发现」 它们 「自己」 解决问题的算法来解决 &#xff0c;而不需要程序员将所有…

影响语音芯片识别率的因素概述

语音芯片识别率是指芯片对人类语音信号的识别能力。在实际应用中&#xff0c;语音芯片识别率的高低直接影响了用户对芯片的体验和满意度。因此&#xff0c;提高语音芯片识别率是当前语音技术领域的重要任务之一。 1.、语音芯片的硬件设计&#xff1a;设计良好的芯片可以更好地…

竹云参编《公共数据授权运营平台技术要求》团体标准正式发布

2023年11月23日&#xff0c;第二届全球数字贸易博览会“数据要素治理与市场化论坛”于杭州成功召开&#xff0c;国家数据局党组书记、局长刘烈宏&#xff0c;浙江省委常委、常务副省长徐文光出席会议并致辞。会上&#xff0c;国家工业信息安全发展研究中心发布并解读了我国首部…

大厂前沿技术导航

百度Geek说 - 知乎 腾讯技术 - 知乎 美团技术团队

Java 项目中常用注解汇总!! (自整理)

Spring框架的注解 PostMapping("/getDetails") post请求 映射到接口 RequestBody 用来接收HTTP请求体中参数 GetMapping("/getDetails") get请求 映射到接口 RequestParam 用来接收URL中的查询参数 PutMappi…

Tomcat 配置

1&#xff1a; 打开 2&#xff1a;选择版本号&#xff0c;我这边是 1.7 3&#xff1a;添加 web 4: 添加jar包 5&#xff1a;添加 6&#xff1a;添加 Tomcat

逆矩阵相关性质与例题

1.方阵的行列式&#xff1a;就是将方阵中的每一个元素转换至行列式中。 1.性质一&#xff1a;转置方阵的行列式等于转置前的行列式。&#xff08;对标性质&#xff1a;行列式与它的转置行列式相等&#xff09; 2.性质二&#xff1a;|ka||a|*k的n次方&#xff0c;n为方阵阶数。 …

平台工程时代的 Kubernetes 揭秘:2023年生产状况报告深度剖析

Kubernetes 在生产环境中的复杂性已经成为常态&#xff0c;在2023年这个平台工程盛行的时代&#xff0c;容器管理的最大亮点可能在于其灵活性&#xff0c;然而在运维政策和治理等方面仍然存在诸多挑战。八年过去了&#xff0c;在生产环境中使用 Kubernetes 仍然需要面临许多挑战…

目前比较好用的护眼台灯,小学生适合的护眼台灯推荐

随着技术的发展&#xff0c;灯光早已成为每家每户都需要的东西。但是灯光不好可能会对眼睛造成伤害是很多人没有注意到的。现在随着护眼灯产品越来越多&#xff0c;市场上台灯的选择越来越多样化&#xff0c;如何选择一个对眼睛无伤害、无辐射的台灯成为许多家长首先要考虑的问…

mysql:修改密码的几种方式

背景 当我们 brew install mysql 新安装 mysql 的时候&#xff0c;是没有密码的&#xff0c;我们可以直接通过 mysql -u root 连接上。但是密码还是要设置的&#xff0c;一是为了安全&#xff0c;二是有些数据库软件如 Sequel 连接都是必须要密码的&#xff0c;接下来我们来看…

自监督LIGHTLY SSL教程

Lightly SSL 是一个用于自监督学习的计算机视觉框架。 github链接&#xff1a;GitHub - lightly-ai/lightly: A python library for self-supervised learning on images. Documentation&#xff1a;Documentation — lightly 1.4.20 documentation 以下内容主要来自Documen…

ElasticSearch 7 SQL 详解

平时使用Elasticsearch的时候,会在Kibana中使用Query DSL来查询数据.每次要用到Query DSL时都基本忘光了,需要重新在回顾一遍,最近发现Elasticsearch已经支持SQL查询了(6.3版本以后),整理了下一些用法. 简介 Elasticsearch SQL是一个X-Pack组件,它允许针对Elasticsearch实时执…

Zabbix-Liunx服务器内存使用率测试

要在Python 2.7中运行内存消耗脚本并安装psutil&#xff0c;您需要先安装pip。以下是完整的步骤&#xff0c;包括如何在Python 2.7环境中安装pip&#xff0c;然后安装psutil&#xff0c;以及最后如何运行内存消耗脚本。 步骤1: 安装pip 在Python 2.7中安装pip&#xff1a; 首先…
最新文章