当前位置: 首页 > news >正文

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) {

        }

    }

}

相关文章:

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

内容提供者&#xff1a;ContentProvider 为App存取内部数据提供外部接口&#xff0c;让不同应用共享数据。 ①在配置里AndroidManifest.xml <provider android:name".UserInfoProvider" android:authorities"com.example.chapter07_server.provider.U…...

STM32_6(TIM)

TIM定时器&#xff08;第一部分&#xff09; TIM&#xff08;Timer&#xff09;定时器定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中断16位计数器、预分频器、自动重装寄存器的时基单元&#xff0c;在72MHz计数时钟下可以实现最大59.65s的定时不仅…...

Linux中flask项目开启https访问

1.下载阿里云免费证书 2.项目添加https配置 3.服务器开启https访问 3.1 重新安装OpenSSL 3.2.重新安装Python 上一次已经讲过Linux安装部署Python: Linux安装Python3.10与部署flask项目实战详细记录,今天记录一下Python项目如何支持https访问…...

Kubernetes 离线部署 Spinnaker

离线部署 Spinnaker 离线部署 spinnaker 需要提前准备以下依赖项 halyard 安装工具&#xff1a;该hal命令的apt源地址https://us-apt.pkg.dev/projects/spinnaker-community位于国外halyard boms物料清单&#xff1a;Spinnaker 将其halyard boms配置存储在公共谷歌云存储 ( g…...

TypeScript 学习笔记 第三部分 贪吃蛇游戏

尚硅谷TypeScript教程&#xff08;李立超老师TS新课&#xff09; 1. 创建开发环境 创建工程&#xff0c;使用学习笔记的第二部分安装css部分 npm i -D less less-loader css-loader style-loader对css部分处理&#xff0c;能够运行在低版本浏览器 npm i -D postcss postcss…...

【spring(一)】核心容器总结

&#x1f308;键盘敲烂&#xff0c;年薪30万&#x1f308; 目录 IOC 配置bean对象&#xff1a; DI 注入bean对象 ①.setter方法注入 ②.构造器注入 Bean的实例化 1.setter方法注入(重点) 2.静态工厂&#xff08;了解&#xff09; 3.实例工厂&#xff08;了解&#xff0…...

易点易动固定资产管理系统:实现全面的固定资产采购管理

在现代企业中&#xff0c;固定资产采购管理是一项关键的任务。为了确保企业的正常运营和发展&#xff0c;有效管理和控制固定资产采购过程至关重要。易点易动固定资产管理系统为企业提供了一种全面的解决方案&#xff0c;整合了从采购需求、采购计划、询比价、采购合同到采购执…...

力扣:178. 分数排名(Python3)

题目&#xff1a; 表: Scores ---------------------- | Column Name | Type | ---------------------- | id | int | | score | decimal | ---------------------- 在 SQL 中&#xff0c;id 是该表的主键。 该表的每一行都包含了一场比赛的分数。Score …...

raid磁盘阵列

在单机时代&#xff0c;采用单块磁盘进行数据存储和读写的方式&#xff0c;由于寻址和读写的时间消耗&#xff0c;导致I/O性能非常低&#xff0c;且存储容量还会受到限制。另外&#xff0c;单块磁盘极其容易出现物理故障&#xff0c;经常导致数据的丢失。此时&#xff0c;RAID技…...

SpringBoot学习笔记-实现微服务:匹配系统(上)

笔记内容转载自 AcWing 的 SpringBoot 框架课讲义&#xff0c;课程链接&#xff1a;AcWing SpringBoot 框架课。 CONTENTS 1. 配置WebSocket2. 前后端WebSocket通信2.1 WS通信的建立2.2 加入JWT验证 3. 前后端匹配业务3.1 实现前端页面3.2 实现前后端交互逻辑3.3 同步游戏地图 …...

重磅!全球首个“绿色黑灯工厂”落户中国,竟然是这家企业……

作者&#xff1a;叶蓁 “52”、“白加黑”、“无人看守作业”&#xff0c;这是九牧“绿色黑灯工厂”的几大关键词。 九牧绿色黑灯工厂不仅是单体产量最大的工厂&#xff0c;也是全球首个入选的“绿色黑灯工厂”。 11月17日&#xff0c;中国节能协会授予九牧5G智能马桶工厂全球…...

go语言学习-异常处理

1、异常场景 网络故障硬件故障组件故障输入错误逻辑错误链路调度错误 2、异常处理方式 # python或者java异常处理 try 可能出现的错误 catch对错误进行处理 xxx,err : 代码 if err ! nil {代码出现错误&#xff0c;需要做处理 }3、自定义错误 有两种方法&#xff1a;1、通过…...

如何使用 JavaScript 实现图片上传并转换为 LaTeX 公式

在本教程中&#xff0c;我们将学习如何使用 JavaScript 创建一个上传图片的功能&#xff0c;并将所选图片转换为 LaTeX 公式。我们将使用 FileReader 对象来读取图片并将其转换为 Base64 格式&#xff0c;然后利用 img2latex API 将其转换为 LaTeX 公式。 1. HTML 结构 首先&…...

深刻理解MySQL8游标处理中not found

深刻理解MySQL8游标处理中not found 最近使用MySQL的游标&#xff0c;在fetch循环过程中&#xff0c;程序总是提前退出 &#xff0c;百思不得其解&#xff0c;经过测试&#xff0c;原来是对于游标处理中not found的定义理解有误&#xff0c;默认是视同Oracle的游标not found定…...

甄知燕千云与SAP、EBS、TC、NS等应用深度集成,智能提单一键畅通,效能一键提升

当今全球化时代下&#xff0c;全球商业环境面临前所未有的机遇和挑战&#xff0c;企业需要持续的业务变革、组织优化来进行降本增效&#xff0c;企业管理软件已成为中小企业、大型企业数字化转型不可或缺的管理工具&#xff0c;企业内管理软件系统也越来越多。 为了适应当前企业…...

第99步 深度学习图像目标检测:SSDlite建模

基于WIN10的64位系统演示 一、写在前面 本期&#xff0c;我们继续学习深度学习图像目标检测系列&#xff0c;SSD&#xff08;Single Shot MultiBox Detector&#xff09;模型的后续版本&#xff0c;SSDlite模型。 二、SSDlite简介 SSDLite 是 SSD 模型的一个变种&#xff0c…...

用EasyAVFilter将网络文件或者本地文件推送RTMP出去的时候发现CPU占用好高,用的也是vcodec copy呀,什么原因?

最近同事在用EasyAVFilter集成在EasyDarwin中做视频拉流转推RTMP流的功能的时候&#xff0c;发现怎么做CPU占用都会很高&#xff0c;但是视频没有调用转码&#xff0c;vcodec用的就是copy&#xff0c;这是什么原因呢&#xff1f; 我们用在线的RTSP流就不会出现这种情况&#x…...

Vatee万腾科技的独特力量:Vatee数字时代创新的新视野

在数字化时代的浪潮中&#xff0c;Vatee万腾科技以其独特而强大的创新力量&#xff0c;为整个行业描绘了一幅崭新的视野。这不仅是一场科技创新的冒险&#xff0c;更是对未来数字时代发展方向的领先探索。 Vatee万腾将创新视为数字时代发展的引擎&#xff0c;成为推动行业向前的…...

【JavaSE】基础笔记 - 异常(Exception)

目录 1、异常的概念和体系结构 1.1、异常的概念 1.2、 异常的体系结构 1.3 异常的分类 2、异常的处理 2.1、防御式编程 2.2、异常的抛出 2.3、异常的捕获 2.3.1、异常声明throws 2.3.2、try-catch捕获并处理 3、自定义异常类 1、异常的概念和体系结构 1.1、异常的…...

QTableWidget——编辑单元格

文章目录 前言熟悉QTableWiget&#xff0c;通过实现单元格的合并、拆分、通过编辑界面实现表格内容及属性的配置、实现表格的粘贴复制功能熟悉QTableWiget的属性 一、[单元格的合并、拆分](https://blog.csdn.net/qq_15672897/article/details/134476530?spm1001.2014.3001.55…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...