安卓开发学习记录(续)

news2025/1/18 7:41:12

文章目录

  • 十一、综合训练(购物车功能)
  • 十二、内容提供者Provider


十一、综合训练(购物车功能)

实现功能:

手机商品页面展示,加入购物车功能,商品详情页面,清空购物车,删除购物车商品。

  1. 数据库准备,准备的数据库有商品数据库,还有存储购物车信息的数据库,使用SqliteOpenHelper进行操作,商品数据库的字段有id,description,price,picPath,购物车字段id,goodsId,count,实现如下:
package com.example.shoppingcart.entity;

//购物车信息
public class CartInfo {
    public int id;
    // 商品编号
    public int goodsId;
    // 商品数量
    public int count;

    public CartInfo(){}

    public CartInfo(int id, int goodsId, int count) {
        this.id = id;
        this.goodsId = goodsId;
        this.count = count;
    }
}

package com.example.shoppingcart.entity;

import com.example.shoppingcart.R;

import java.util.ArrayList;

public class Goodsinfo {
    public int id;
    public String name;
    public String description;
    public float price;
    public String picPath;
    public int pic;

    private static String[] mNameArray = {
            "iPhone11", "Mate30", "小米10", "OPPO Reno3", "vivo X30", "荣耀30S"
    };
    // 声明一个手机商品的描述数组
    private static String[] mDescArray = {
            "Apple iPhone11 256GB 绿色 4G全网通手机",
            "华为 HUAWEI Mate30 8GB+256GB 丹霞橙 5G全网通 全面屏手机",
            "小米 MI10 8GB+128GB 钛银黑 5G手机 游戏拍照手机",
            "OPPO Reno3 8GB+128GB 蓝色星夜 双模5G 拍照游戏智能手机",
            "vivo X30 8GB+128GB 绯云 5G全网通 美颜拍照手机",
            "荣耀30S 8GB+128GB 蝶羽红 5G芯片 自拍全面屏手机"
    };
    // 声明一个手机商品的价格数组
    private static float[] mPriceArray = {6299, 4999, 3999, 2999, 2998, 2399};
    // 声明一个手机商品的大图数组
    private static int[] mPicArray = {
            R.drawable.iphone, R.drawable.huawei, R.drawable.xiaomi,
            R.drawable.oppo, R.drawable.vivo, R.drawable.rongyao
    };
    public static ArrayList<Goodsinfo> getDeafultList(){
        ArrayList<Goodsinfo> goodsList=new ArrayList<Goodsinfo>();
        for(int i=0;i<mNameArray.length;i++){
            Goodsinfo goodsinfo=new Goodsinfo();
            goodsinfo.id=i;
            goodsinfo.name=mNameArray[i];
            goodsinfo.description=mDescArray[i];
            goodsinfo.price=mPriceArray[i];
            goodsinfo.pic=mPicArray[i];
            goodsList.add(goodsinfo);
        }
        return goodsList;
    }
}

package com.example.shoppingcart.database;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.example.shoppingcart.entity.CartInfo;
import com.example.shoppingcart.entity.Goodsinfo;

import java.util.ArrayList;
import java.util.List;

public class ShoppingDBHelper extends SQLiteOpenHelper {
    private static final String DB_NAME="shopping.db";
    private static final String TABLE_GOODS_INFO="goods_info";
    private static final String TABLE_CART_INFO="cart_info";
    private static final int DB_VERSION=2;
    private static ShoppingDBHelper databaseUserHelper=null;

    public ShoppingDBHelper(Context context) {
        super(context,DB_NAME,null,DB_VERSION);
    }
    //单例模式获取数据库实例
    public static  ShoppingDBHelper getInstance(Context context){
        if(databaseUserHelper==null){
            databaseUserHelper=new ShoppingDBHelper(context);
        }
        return databaseUserHelper;
    }
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        String sql="";
        sql= "CREATE TABLE IF NOT EXISTS "+TABLE_GOODS_INFO+"(_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,name VARCHAR NOT NULL,description VARCHAR NOT NULL,price FLOAT NOT NULL,pic_path VARCHAR NOT NULL);";
        sqLiteDatabase.execSQL(sql);

        //购物车信息表
        sql= "CREATE TABLE IF NOT EXISTS "+TABLE_CART_INFO+"(_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,good_id INTEGER NOT NULL,count INTEGER NOT NULL);";
        sqLiteDatabase.execSQL(sql);
    }

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

    public void insertGoodsinfos(List<Goodsinfo> list){
        SQLiteDatabase database=databaseUserHelper.getWritableDatabase();
        try{
            database.beginTransaction();
            for(Goodsinfo goodsinfo:list){
                ContentValues contentValues=new ContentValues();
                contentValues.put("name",goodsinfo.name);
                contentValues.put("description",goodsinfo.description);
                contentValues.put("price",goodsinfo.price);
                contentValues.put("pic_path",goodsinfo.picPath);
                database.insert(TABLE_GOODS_INFO,null,contentValues);
            }
            database.setTransactionSuccessful();
        }
        catch (Exception e){
            e.printStackTrace();
        }finally {
            database.endTransaction();
        }
    }
    public List<Goodsinfo> queryAllGoodsInfo(){
        String sql="SELECT *FROM "+TABLE_GOODS_INFO;
        List<Goodsinfo> list=new ArrayList<Goodsinfo>();
        SQLiteDatabase database=databaseUserHelper.getWritableDatabase();
        Cursor cursor=database.rawQuery(sql,null);
        while(cursor.moveToNext()) {
            Goodsinfo goodsinfo = new Goodsinfo();
            goodsinfo.id = cursor.getInt(0);
            goodsinfo.name = cursor.getString(1);
            goodsinfo.description = cursor.getString(2);
            goodsinfo.price = cursor.getFloat(3);
            goodsinfo.picPath = cursor.getString(4);
            list.add(goodsinfo);
        }
        cursor.close();
        return list;
    }

    public void insertCartInfo(int goodsId) {
        SQLiteDatabase database=databaseUserHelper.getWritableDatabase();
        //购物车不存在该商品,则添加一条信息
        CartInfo cartInfo=queryCartInfoByGoodsId(goodsId);
        ContentValues values=new ContentValues();
        values.put("good_id",goodsId);
        if(cartInfo==null){
            values.put("count",1);
            database.insert(TABLE_CART_INFO,null,values);
        }
        //如果购物车有该商品,则更新商品数量
        else{
                values.put("_id",cartInfo.id);
                values.put("count",++cartInfo.count);
                database.update(TABLE_CART_INFO,values,"_id=?",new String[]{String.valueOf(cartInfo.id)});
        }
    }

    private CartInfo queryCartInfoByGoodsId(int goodsId) {
        SQLiteDatabase database=databaseUserHelper.getReadableDatabase();
        Cursor cursor=database.query(TABLE_CART_INFO,null,"good_id=?",new String[]{String.valueOf(goodsId)},null,null,null,null);
        CartInfo info=null;
        if(cursor.moveToNext()){
            info=new CartInfo();
            info.id=cursor.getInt(0);
            info.goodsId=cursor.getInt(1);
            info.count=cursor.getInt(2);
        }
        return info;
    }


    //统计购物车商品的总数量
    public int countCartInfo() {
        SQLiteDatabase database=databaseUserHelper.getWritableDatabase();
        int count=0;
        String sql="SELECT sum(count) FROM " +TABLE_CART_INFO;
        @SuppressLint("Recycle") Cursor cursor=database.rawQuery(sql,null);
        if(cursor.moveToNext()){
            cursor.getInt(0);
        }
        return  count;
    }

    public List<CartInfo> queryAllCartInfo() {
        SQLiteDatabase database=databaseUserHelper.getWritableDatabase();
        List<CartInfo> list=new ArrayList<CartInfo>();
        @SuppressLint("Recycle") Cursor cursor=database.query(TABLE_CART_INFO,null,null,null,null,null,null);
        while(cursor.moveToNext()){
            CartInfo info=new CartInfo();
            info.id=cursor.getInt(0);
            info.goodsId=cursor.getInt(1);
            info.count=cursor.getInt(2);
            list.add(info);
        }
        return list;
    }

    public Goodsinfo queryAllGoodsInfoById(int goodsId) {
        Goodsinfo info=null;
        SQLiteDatabase database=databaseUserHelper.getWritableDatabase();
        @SuppressLint("Recycle") Cursor cursor=database.query(TABLE_GOODS_INFO,null,"_id=?",new String[]{String.valueOf(goodsId)},null,null,null);
        if(cursor.moveToNext()){
            info = new Goodsinfo();
            info.id = cursor.getInt(0);
            info.name = cursor.getString(1);
            info.description = cursor.getString(2);
            info.price = cursor.getFloat(3);
            info.picPath = cursor.getString(4);
        }
        return info;
    }

    //根据商品ID删除购物车信息
    public void deleteCartInfoByGoodsId(int goodsId) {
        SQLiteDatabase database=databaseUserHelper.getWritableDatabase();
        database.delete(TABLE_CART_INFO,"good_id=?",new String[]{String.valueOf(goodsId)});

    }
    //删除所有购物车信息
    public void deleteAllCartInfo(){
        SQLiteDatabase database=databaseUserHelper.getWritableDatabase();
        database.delete(TABLE_CART_INFO,"1=1",null);
    }
}

Activity类主要有4个,分别为MyApplication,购物车类,商品市场类,商品详情类,MyApplication启动时自动将商品数据插入到数据库,并设置购物车全局变量为0.
商品类的展示再通过从数据库中获取存储的商品信息,通过获取商品的子视图,动态的嵌入到页面中,当点击加入购物车时,将点击的商品加入到购物车数据库,随后购物车全局变量+1,显示出来。
购物车功能实现思路:从购物车数据库中取出商品的good_id,从商品数据库中查询出商品的全部信息,然后动态嵌入子视图进行展示。清空功能则直接清空购物车数据库,并将购物车全局变量归0,长按点击删除实现思路则是对嵌入的view进行长监听,长按点击则弹窗,如果删除则从购物车数据库中删除,并将view子视图移除,Myapplication全局变量-1。
商品详情页实现思路:利用Intent传一个商品的good_id进入到商品详情页,通过good_id查询商品的信息,并赋到控件中展示。

MyApplication类:

package com.example.shoppingcart;

import android.app.Application;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.Log;

import com.example.shoppingcart.database.ShoppingDBHelper;
import com.example.shoppingcart.entity.Goodsinfo;
import com.example.shoppingcart.util.FileUtil;
import com.example.shoppingcart.util.SharedUtil;

import java.io.File;
import java.util.List;

public class MyApplication extends Application {
    private static MyApplication mApp;
    public int goodsCount;

    public static  MyApplication getInstance(){
        return  mApp;
    }
    public void onCreate() {
        super.onCreate();
        mApp=this;
        Log.d("App状态:","App启动");
        InitGoodsInfo();
    }
    private void InitGoodsInfo() {
        boolean isFirst= SharedUtil.getInstance(this).readBoolean("first",true);
        String directory=getExternalFilesDir((Environment.DIRECTORY_DOWNLOADS)).toString()+ File.separatorChar;
       if(isFirst){
           List<Goodsinfo> list=Goodsinfo.getDeafultList();
           for(Goodsinfo goodsinfo:list){
               Bitmap bitmap= BitmapFactory.decodeResource(getResources(),goodsinfo.pic);
               String path=directory+goodsinfo.id+".jpg";
               FileUtil.saveImage(path,bitmap);
               bitmap.recycle();
               goodsinfo.picPath=path;
           }
           //打开数据库将商品信息插入表中
           ShoppingDBHelper shoppingDBHelper=ShoppingDBHelper.getInstance(this);
           shoppingDBHelper.getWritableDatabase();
           shoppingDBHelper.insertGoodsinfos(list);
           shoppingDBHelper.close();
           SharedUtil.getInstance(this).writeBoolean("first",false);
       }
    }
}

商品市场类:

package com.example.shoppingcart;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.shoppingcart.database.ShoppingDBHelper;
import com.example.shoppingcart.entity.Goodsinfo;
import com.example.shoppingcart.util.ToastUtil;

import java.util.List;

public class ShoppingChannelActivity extends AppCompatActivity implements  View.OnClickListener{
    private ShoppingDBHelper shoppingDBHelper;
    private  TextView tv_count;
    private GridLayout gl_Channel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shopping_channel);
        shoppingDBHelper=ShoppingDBHelper.getInstance(this);
        shoppingDBHelper.getWritableDatabase();
        shoppingDBHelper.getReadableDatabase();
        TextView tv_title=findViewById(R.id.tv_title);
        tv_title.setText("手机商场");
        tv_count=findViewById(R.id.tv_count);
        gl_Channel=findViewById(R.id.gl_channel);
        findViewById(R.id.iv_back).setOnClickListener(this);
        findViewById(R.id.iv_cart).setOnClickListener(this);
        showGoods();
    }

    //通过手机视图根文件的形式,动态查询数据库,并嵌入到页面中
    private void showGoods() {
        //获取屏幕宽度
        int screenWidth=getResources().getDisplayMetrics().widthPixels;
        LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(screenWidth/2,LinearLayout.LayoutParams.WRAP_CONTENT);
            //查询数据库所有商品记录
        List<Goodsinfo> list=shoppingDBHelper.queryAllGoodsInfo();
        gl_Channel.removeAllViews();
        for(Goodsinfo goodsinfo:list){
            //获取布局文件item_goods.xml的根视图
            @SuppressLint("InflateParams") View view= LayoutInflater.from(this).inflate(R.layout.item_goods,null);
            ImageView iv_thumb=view.findViewById(R.id.iv_thumb);
            TextView tv_name=view.findViewById(R.id.tv_name);
            TextView tv_price=view.findViewById(R.id.tv_price);
            Button btn_add=view.findViewById(R.id.btn_add);
            iv_thumb.setImageURI(Uri.parse(goodsinfo.picPath));
            tv_name.setText(goodsinfo.name);
            tv_price.setText(String.valueOf((int) goodsinfo.price));
            btn_add.setOnClickListener(v->{
                addToCart(goodsinfo.id,goodsinfo.name);
            });
            iv_thumb.setOnClickListener(v->{
                Intent intent=new Intent(ShoppingChannelActivity.this,ShoppingDetailActivity.class);
                intent.putExtra("good_id",goodsinfo.id);
                startActivity(intent);
            });
            //把商品视图加到网格布局,设置屏幕的宽高
            gl_Channel.addView(view,params);
        }
    }
    private void addToCart(int goodsId,String name){
        shoppingDBHelper.insertCartInfo(goodsId);
        int count=++MyApplication.getInstance().goodsCount;
        tv_count.setText(String.valueOf(count));
        ToastUtil.show(this,"已添加一部"+name+"到购物车");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("返回了","返回了页面");
        //查询商品总数并展示
        showCartInfoTotal();
    }

    private void showCartInfoTotal() {
        int count=shoppingDBHelper.countCartInfo();
        MyApplication.getInstance().goodsCount=count;
        Log.d("count:", String.valueOf(count));
        tv_count.setText(String.valueOf(count));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        shoppingDBHelper.close();
    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.iv_back:
                finish();
                break;
            case R.id.iv_cart:
                Intent intent=new Intent(this,ShoppingcartActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(intent);
                break;
        }
    }
}

购物车类:

package com.example.shoppingcart;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.example.shoppingcart.database.ShoppingDBHelper;
import com.example.shoppingcart.entity.CartInfo;
import com.example.shoppingcart.entity.Goodsinfo;
import com.example.shoppingcart.util.ToastUtil;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class ShoppingcartActivity extends AppCompatActivity implements View.OnClickListener {
    private  TextView tv_count;
    private LinearLayout ll_cart;
    private ShoppingDBHelper shoppingDBHelper;
    private List<CartInfo> mCartList;
    private  TextView tv_total_price;
    private  LinearLayout ll_empty;
    private  LinearLayout ll_content;
    //声明一个根据商品编号查找商品信息的映射,把商品信息缓存起来
    private final Map<Integer,Goodsinfo> goodsinfoMap=new HashMap<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shoppingcart);
        tv_count=findViewById(R.id.tv_count);
        TextView tv_title=findViewById(R.id.tv_title);
        tv_title.setText("购物车");
        ll_cart=findViewById(R.id.ll_cart);
        tv_total_price=findViewById(R.id.tv_total_price);
        findViewById(R.id.iv_back).setOnClickListener(this);
        findViewById(R.id.btn_shopping_channel).setOnClickListener(this);
        findViewById(R.id.btn_clear).setOnClickListener(this);
        findViewById(R.id.btn_settle).setOnClickListener(this);
        tv_count.setText(String.valueOf(MyApplication.getInstance().goodsCount));
        shoppingDBHelper=ShoppingDBHelper.getInstance(this);
        ll_empty=findViewById(R.id.ll_empty);
        ll_content=findViewById(R.id.ll_content);
    }

    @Override
    protected void onResume() {
        super.onResume();
        showCart();
    }
    //展示购物车中的商品列表
    private void showCart() {
        //移除下面所有子视图
        ll_cart.removeAllViews();
        mCartList=shoppingDBHelper.queryAllCartInfo();
        if(mCartList.size()==0){
            return ;
        }
        for(CartInfo info:mCartList ){
            //根据商品编号查询商品数据库中的记录
            Goodsinfo goods=shoppingDBHelper.queryAllGoodsInfoById(info.goodsId);
            goodsinfoMap.put(info.goodsId,goods);

            View view=LayoutInflater.from(this).inflate(R.layout.item_cart,null);
            ImageView iv_thumb=view.findViewById(R.id.iv_thumb);
            TextView tv_name=view.findViewById(R.id.tv_name);
            TextView tv_desc=view.findViewById(R.id.tv_desc);
            TextView tv_count=view.findViewById(R.id.tv_price);
            @SuppressLint("CutPasteId") TextView tv_price=view.findViewById(R.id.tv_price);
            TextView tv_sum=view.findViewById(R.id.tv_sum);
            iv_thumb.setImageURI(Uri.parse(goods.picPath));
            tv_name.setText(goods.name);
            tv_desc.setText(goods.description);
            tv_count.setText(String.valueOf(info.count));
            tv_price.setText(String.valueOf((int) goods.price));
            tv_sum.setText(String.valueOf((int) (info.count*goods.price)));
            //给商品行添加长按事件,长按商品就删除该商品
            view.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(final View v) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(ShoppingcartActivity.this);
                    builder.setMessage("是否从购物车删除"+goods.name+"?");
                    builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ll_cart.removeView(v); // 移除当前视图
                            deleteGoods(info); // 删除该商品
                        }
                    });
                    builder.setNegativeButton("否", null);
                    builder.create().show(); // 显示提醒对话框
                    return true;
                }
            });
            view.setOnClickListener(v->{
                Intent intent = new Intent(ShoppingcartActivity.this, ShoppingDetailActivity.class);
                intent.putExtra("good_id", goods.id);
                startActivity(intent);
            });
            ll_cart.addView(view);
        }
        //重新计算购物车商品总金额
        refreshTotalPrice();
    }

    private void deleteGoods(CartInfo info) {
        MyApplication.getInstance().goodsCount-=info.count;
        //从购物车数据库中删除商品
        shoppingDBHelper.deleteCartInfoByGoodsId(info.goodsId);
        //从购物车列表中删除商品
        CartInfo removed=null;
        for(CartInfo cartInfo:mCartList){
            if(cartInfo.goodsId==info.goodsId){
                removed=cartInfo;
                break;
            }
        }
        Log.d("delete执行:","执行");
        mCartList.remove(removed);
        //显示最新商品数量
        showCount();
        ToastUtil.show(this,"已从购物车中删除"+ Objects.requireNonNull(goodsinfoMap.get(info.goodsId)).name);
        goodsinfoMap.remove(info.goodsId);
        refreshTotalPrice();
    }

    private void showCount() {
        tv_count.setText(String.valueOf(MyApplication.getInstance().goodsCount));
        //购物车中没有商品,显示空空如也
        if(MyApplication.getInstance().goodsCount==0){
            ll_empty.setVisibility(View.VISIBLE);
            ll_content.setVisibility(View.GONE);
            ll_cart.removeAllViews();
        }else{
            ll_content.setVisibility(View.VISIBLE);
            ll_empty.setVisibility(View.GONE);
        }
    }

    private void refreshTotalPrice() {
        int totalPrice=0;
        for(CartInfo info:mCartList){
            Goodsinfo goods=goodsinfoMap.get(info.goodsId);
            totalPrice+=goods.price*info.count;
        }
        tv_total_price.setText(String.valueOf(totalPrice));
    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.iv_back:
                finish();
                break;
            case R.id.btn_shopping_channel:
                Intent intent=new Intent(this,ShoppingChannelActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(intent);
                break;
            case R.id.btn_clear:
                shoppingDBHelper.deleteAllCartInfo();
                MyApplication.getInstance().goodsCount=0;
                showCount();
                break;
            case R.id.btn_settle:
                AlertDialog.Builder builder=new AlertDialog.Builder(this);
                builder.setTitle("结算商品");
                builder.setMessage("支付功能尚未开通");
                builder.setPositiveButton("我知道了",null);
                builder.create().show();
                break;
        }
    }
}

商品详情页类:

package com.example.shoppingcart;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.shoppingcart.database.ShoppingDBHelper;
import com.example.shoppingcart.entity.Goodsinfo;
import com.example.shoppingcart.util.ToastUtil;

import org.w3c.dom.Text;

public class ShoppingDetailActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView tv_count;
    private TextView tv_goods_price;
    private TextView tv_goods_desc;
    private ImageView tv_goods_pic;
    private ShoppingDBHelper shoppingDBHelper;
    private int mGoodsId;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shopping_detail);
        tv_count=findViewById(R.id.tv_count);
        tv_goods_desc=findViewById(R.id.tv_goods_desc);
        tv_goods_price=findViewById(R.id.tv_goods_price);
        tv_goods_pic=findViewById(R.id.iv_goods_pic);
        TextView tv_title=findViewById(R.id.tv_title);
        tv_title.setText("商品详情");
        findViewById(R.id.iv_back).setOnClickListener(this);
        findViewById(R.id.iv_cart).setOnClickListener(this);
        findViewById(R.id.btn_add_cart).setOnClickListener(this);
        shoppingDBHelper=ShoppingDBHelper.getInstance(this);

    }
    @Override
    protected void onResume() {
        super.onResume();
        showDetail();
    }

    private void showDetail() {
        //获取传来的商品编号,通过商品编号来展示页面
        mGoodsId=getIntent().getIntExtra("good_id",0);
        if(mGoodsId>0){
            Goodsinfo goodsinfo=shoppingDBHelper.queryAllGoodsInfoById(mGoodsId);
            tv_goods_desc.setText(goodsinfo.description);
            tv_goods_price.setText(String.valueOf(goodsinfo.price));
            tv_goods_pic.setImageURI(Uri.parse(goodsinfo.picPath));
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.iv_back:
                finish();
                break;
            case R.id.iv_cart:
                Intent intent = new Intent(this, ShoppingcartActivity.class);
                startActivity(intent);
                break;
            case R.id.btn_add_cart:
                addToCart(mGoodsId);
                break;
        }

    }

    private void addToCart(int mGoodsId) {
        int count = ++MyApplication.getInstance().goodsCount;
        tv_count.setText(String.valueOf(count));
        shoppingDBHelper.insertCartInfo(mGoodsId);
        ToastUtil.show(this, "成功添加至购物车");
    }
}

商品展示视图:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/orange"
    android:orientation="vertical" >

        <include layout="@layout/title_shopping"/>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <GridLayout
            android:id="@+id/gl_channel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:columnCount="2"/>

    </ScrollView>


</LinearLayout>

购物车展示视图:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/orange"
    android:orientation="vertical">

    <include layout="@layout/title_shopping" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <LinearLayout
                android:id="@+id/ll_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:visibility="visible">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal">

                    <TextView
                        android:layout_width="85dp"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:text="图片"
                        android:textColor="@color/black"
                        android:textSize="15sp" />

                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="3"
                        android:gravity="center"
                        android:text="名称"
                        android:textColor="@color/black"
                        android:textSize="15sp" />

                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center"
                        android:text="数量"
                        android:textColor="@color/black"
                        android:textSize="15sp" />

                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center"
                        android:text="单价"
                        android:textColor="@color/black"
                        android:textSize="15sp" />

                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center"
                        android:text="总价"
                        android:textColor="@color/black"
                        android:textSize="15sp" />

                </LinearLayout>

                <LinearLayout
                    android:id="@+id/ll_cart"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:padding="0dp">

                    <Button
                        android:id="@+id/btn_clear"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:text="清空"
                        android:textColor="@color/black"
                        android:textSize="17sp" />

                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center|right"
                        android:text="总金额:"
                        android:textColor="@color/black"
                        android:textSize="17sp" />

                    <TextView
                        android:id="@+id/tv_total_price"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginRight="10dp"
                        android:gravity="center|left"
                        android:textColor="@color/red"
                        android:textSize="25sp" />

                    <Button
                        android:id="@+id/btn_settle"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:text="结算"
                        android:textColor="@color/black"
                        android:textSize="17sp" />
                </LinearLayout>

            </LinearLayout>

            <LinearLayout
                android:id="@+id/ll_empty"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:visibility="gone"
                tools:visibility="visible">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="100dp"
                    android:layout_marginBottom="100dp"
                    android:gravity="center"
                    android:text="哎呀,购物车空空如也,快去选购商品吧"
                    android:textColor="@color/black"
                    android:textSize="17sp" />

                <Button
                    android:id="@+id/btn_shopping_channel"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:text="逛逛手机商场"
                    android:textColor="@color/black"
                    android:textSize="17sp" />
            </LinearLayout>
        </RelativeLayout>
    </ScrollView>

</LinearLayout>

商品详情视图:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/orange"
    android:orientation="vertical">

    <include layout="@layout/title_shopping" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/iv_goods_pic"
                android:layout_width="match_parent"
                android:layout_height="350dp"
                android:scaleType="fitCenter"
                tools:src="@drawable/xiaomi" />

            <TextView
                android:id="@+id/tv_goods_price"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingLeft="5dp"
                android:textColor="@color/red"
                android:textSize="22sp"
                tools:text="1990" />

            <TextView
                android:id="@+id/tv_goods_desc"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingLeft="5dp"
                android:textColor="@color/black"
                android:textSize="15sp"
                tools:text="小米 MI10 8GB+128GB 钛银黑 5G手机 游戏拍照手机" />

            <Button
                android:id="@+id/btn_add_cart"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="加入购物车"
                android:textColor="@color/black"
                android:textSize="17sp" />
        </LinearLayout>
    </ScrollView>

</LinearLayout>

单一商品视图:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/ll_item"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="@color/white"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textColor="@color/black"
        android:textSize="17sp"
        tools:text="小米手机" />

    <ImageView
        android:id="@+id/iv_thumb"
        android:layout_width="180dp"
        android:layout_height="150dp"
        android:scaleType="fitCenter"
        tools:src="@drawable/xiaomi" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_price"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:gravity="center"
            android:textColor="@color/red"
            android:textSize="15sp"
            tools:text="20" />

        <Button
            android:id="@+id/btn_add"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3"
            android:gravity="center"
            android:text="加入购物车"
            android:textColor="@color/black"
            android:textSize="15sp" />
    </LinearLayout>

</LinearLayout>

购物车标志视图:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="#aaaaff">

    <ImageView
        android:id="@+id/iv_back"
        android:layout_width="50dp"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:padding="10dp"
        android:scaleType="fitCenter"
        android:src="@drawable/ic_back"/>
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:textColor="@color/black"
        android:textSize="20sp" />

    <ImageView
        android:id="@+id/iv_cart"
        android:layout_width="50dp"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:scaleType="fitCenter"
        android:src="@drawable/cart" />

    <TextView
        android:id="@+id/tv_count"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/iv_cart"
        android:layout_marginLeft="-20dp"
        android:gravity="center"
        android:background="@drawable/shape_oval_red"
        android:text="0"
        android:textColor="@color/white"
        android:textSize="15sp" />
</RelativeLayout>

单一商品子视图:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/ll_item"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="@color/white"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textColor="@color/black"
        android:textSize="17sp"
        tools:text="小米手机" />

    <ImageView
        android:id="@+id/iv_thumb"
        android:layout_width="180dp"
        android:layout_height="150dp"
        android:scaleType="fitCenter"
        tools:src="@drawable/xiaomi" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_price"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:gravity="center"
            android:textColor="@color/red"
            android:textSize="15sp"
            tools:text="20" />

        <Button
            android:id="@+id/btn_add"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3"
            android:gravity="center"
            android:text="加入购物车"
            android:textColor="@color/black"
            android:textSize="15sp" />
    </LinearLayout>

</LinearLayout>

购物车展示单一商品子视图:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/iv_thumb"
        android:layout_width="85dp"
        android:layout_height="85dp"
        android:scaleType="fitCenter"
        tools:src="@drawable/xiaomi"/>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="2"
            android:gravity="left|center"
            android:textColor="@color/black"
            android:textSize="17sp"
            tools:text="小米手机"/>

        <TextView
            android:id="@+id/tv_desc"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="3"
            android:gravity="left|center"
            android:textColor="@color/black"
            android:textSize="12sp"
            tools:text="小米 MI10 8GB+128GB 钛银黑 5G手机 游戏拍照手机"/>
    </LinearLayout>

    <TextView
        android:id="@+id/tv_count"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center"
        android:textColor="@color/black"
        android:textSize="17sp"
        tools:text="2"/>

    <TextView
        android:id="@+id/tv_price"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="right|center"
        android:textColor="@color/black"
        android:textSize="15sp"
        tools:text="1000"/>

    <TextView
        android:id="@+id/tv_sum"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1.2"
        android:gravity="right|center"
        android:textColor="@color/red"
        android:textSize="17sp"
        tools:text="2000"/>

</LinearLayout>

file

file

file

file

十二、内容提供者Provider

为App存取内部数据提供统一的外部接口,让不同应用之间得以共享数据,将用户的输入内容,通过ContentProvider跨进程通信传递到Server App,主要通过Uri作为地址传输,客户端通过ProviderResolver类进行操作,Uri格式如下:

content://authority/data_path/id
content://  通用前缀,标识Uri用于ContentProvider定位资源
authority  授权者名称,用于确定具体由哪一个ContentProvider提供资源
data_path  数据路径
id  数据编号,用来请求单条数据

例子:创建server和client端,从client端操作server端的数据库,达到添加,查询,删除用户功能

Server: DatabaseUserHelper.java

package com.example.server_provider.database;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;


import java.util.ArrayList;
import java.util.List;

public class DatabaseUserHelper extends SQLiteOpenHelper {
    private static final String DB_NAME="user.db";
    public static final String TABLE_NAME="user_info";

    private static final int DB_VERSION=2;
    private static DatabaseUserHelper databaseUserHelper=null;

    public DatabaseUserHelper(Context context) {
        super(context,DB_NAME,null,DB_VERSION);
    }
    //单例模式获取数据库实例
    public static  DatabaseUserHelper getInstance(Context context){
        if(databaseUserHelper==null){
            databaseUserHelper=new DatabaseUserHelper(context);
        }
        return databaseUserHelper;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        String sql= "CREATE TABLE IF NOT EXISTS "+TABLE_NAME+"(_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,name VARCHAR NOT NULL,age INTEGER NOT NULL,height LONG NOT NULL,weight float NOT NULL,married INTEGER NOT NULL);";
        sqLiteDatabase.execSQL(sql);
    }

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

provider类:

package com.example.server_provider.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;

import com.example.server_provider.database.DatabaseUserHelper;

public class UserInfoProvider extends ContentProvider {
    private DatabaseUserHelper databaseUserHelper;
    public static final String AUTHORITIES = "com.example.server_provider.provider.UserInfoProvider";
    private static final UriMatcher URI_MATCHER=new UriMatcher(UriMatcher.NO_MATCH);
    private static final int USERS=1;
    private static final int USER=2;
    static {
        //Uri匹配器
        URI_MATCHER.addURI(AUTHORITIES,"/user",USERS);
        URI_MATCHER.addURI(AUTHORITIES,"user/#",USER);
    }
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int count=0;
        switch (URI_MATCHER.match(uri)){
            case USERS:
                SQLiteDatabase db1=databaseUserHelper.getWritableDatabase();
                count=db1.delete(DatabaseUserHelper.TABLE_NAME,selection,selectionArgs);
                db1.close();
                break;
            case USER:
                String id=uri.getLastPathSegment();
                SQLiteDatabase  db2=databaseUserHelper.getWritableDatabase();
                count=db2.delete(DatabaseUserHelper.TABLE_NAME,"_id=?",new String[]{id});
                db2.close();
                break;
        }
        return count;
    }

    @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) {
        if(URI_MATCHER.match(uri)==USERS) {
            SQLiteDatabase db = databaseUserHelper.getWritableDatabase();
            db.insert(DatabaseUserHelper.TABLE_NAME, null, values);
        }
        return uri;
    }

    @Override
    public boolean onCreate() {
        Log.d("Provider","Provider启动");
        databaseUserHelper=DatabaseUserHelper.getInstance(getContext());
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        if(URI_MATCHER.match(uri)==USERS) {
            SQLiteDatabase db = databaseUserHelper.getWritableDatabase();
            return db.query(DatabaseUserHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, null);
        }
      return null;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        // TODO: Implement this to handle requests to update one or more rows.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

client端操作类:

package com.example.client_provider;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.example.client_provider.entity.User;
import com.example.client_provider.util.ToastUtil;

public class ContentWriteActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText name;
    private EditText age;
    private EditText weight;
    private EditText height;
    private CheckBox married;
    private Button save;
    private Button delete;
    private Button query;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_content_write);
        name=findViewById(R.id.name);
        age=findViewById(R.id.age);
        weight=findViewById(R.id.weight);
        height=findViewById(R.id.height);
        married=findViewById(R.id.married);
        save=findViewById(R.id.save);
        delete=findViewById(R.id.delete);
        query=findViewById(R.id.query);
        save.setOnClickListener(this);
        delete.setOnClickListener(this);
        query.setOnClickListener(this);

    }

    @SuppressLint({"NonConstantResourceId", "Range"})
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.save:
                ContentValues values=new ContentValues();
                values.put(UserInfoContent.NAME,name.getText().toString());
                values.put(UserInfoContent.AGE,Integer.parseInt(age.getText().toString()));
                values.put(UserInfoContent.HEIGHT,height.getText().toString());
                values.put(UserInfoContent.WEIGHT,weight.getText().toString());
                values.put(UserInfoContent.MARRIED,married.isChecked());
                getContentResolver().insert(UserInfoContent.CONTENT_Uri,values);
                ToastUtil.show(this,"保存成功");
                break;
            case R.id.query:
                Cursor cursor=getContentResolver().query(UserInfoContent.CONTENT_Uri,null,null,null,null);
                if(cursor!=null){
                    while (cursor.moveToNext()){
                        User info=new User();
                        info.id=cursor.getInt(cursor.getColumnIndex(UserInfoContent._ID));
                        info.name=cursor.getString(cursor.getColumnIndex(UserInfoContent.NAME));
                        info.age=cursor.getInt(cursor.getColumnIndex(UserInfoContent.AGE));
                        info.height=cursor.getInt(cursor.getColumnIndex(UserInfoContent.HEIGHT));
                        info.weight=cursor.getFloat(cursor.getColumnIndex(UserInfoContent.WEIGHT));
                        info.married= cursor.getInt(cursor.getColumnIndex(UserInfoContent.MARRIED)) == 1;
                        Log.d("查询结果:",info.toString());
                    }
                    cursor.close();
                }
                break;
            case R.id.delete:
                //删除id为2的
                Uri uri= Uri.parse("content://com.example.server_provider.provider.UserInfoProvider/user/2");
                //删除全
                int count = getContentResolver().delete(UserInfoContent.CONTENT_Uri, "name=?", new String[]{"Aiwin"});
                if(count>0){
                    ToastUtil.show(this,"删除成功");
                }
                break;
        }

    }
}
  1. 运行时动态申请权限

Android系统未了防止某些App滥用权限,从6.0开始引入运行时权限管理机制,允许App在允许过程中拥有某项权限,一旦缺少,可自动弹出小窗口提示开启权限,
也可在应用启动时候即申请全部权限,一般流程如下:

  1. 检查App是否开启指定权限,调用ContextCompat的checkSelfPermission方法
  2. 请求系统弹窗,便于用户选择,调用ActivityCompat的requestPermissions方法,命令系统弹出申请窗口
  3. 重写获得页面的权限请求回调方法onRequestPermissionsResult,在该方法内部处理用户权限选择结果。

例子:申请短信读写、联系人读写权限

 package com.example.client_provider;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;

import com.example.client_provider.util.PermissionUtil;
import com.example.client_provider.util.ToastUtil;

 public class PermissionHungryActivity extends AppCompatActivity implements View.OnClickListener{

     private static final int RequestAll=0;
     private static final String[] PERMISSION_ALL=new String[]{
             Manifest.permission.READ_CONTACTS,
             Manifest.permission.WRITE_CONTACTS,
             Manifest.permission.READ_SMS,
             Manifest.permission.SEND_SMS
     };
     private static  final String[] PERMISSION_CONTACT=new String[]{
             Manifest.permission.READ_CONTACTS,
             Manifest.permission.WRITE_CONTACTS
     };
     private static final int RequestCodeConTact=1;
     private static final String[] PERMISSION_SMS=new String[]{
             Manifest.permission.READ_SMS,
             Manifest.permission.SEND_SMS
     };
     private static final int RequestCodeSMS=2;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_permission_lazy);
         findViewById(R.id.btn_contact).setOnClickListener(this);
         findViewById(R.id.btn_sms).setOnClickListener(this);
         PermissionUtil.CheckPermissions(this,PERMISSION_ALL,RequestAll);
     }

     @SuppressLint("NonConstantResourceId")
     @Override
     public void onClick(View view) {
         switch (view.getId()){
             case R.id.btn_contact:
                 PermissionUtil.CheckPermissions(this,PERMISSION_CONTACT,RequestCodeConTact);
                 break;
             case R.id.btn_sms:
                 PermissionUtil.CheckPermissions(this,PERMISSION_SMS,RequestCodeSMS);
                 break;
         }

     }

     @Override
     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
         switch (requestCode){
             case RequestAll:
                 if(PermissionUtil.checkGrant(grantResults)){
                     Log.d("权限情况","所有权限获取成功");
                 }
                 else{
                     for(int i=0;i<permissions.length;i++){
                         if(grantResults[i]!= PackageManager.PERMISSION_GRANTED){
                             switch (permissions[i]){
                                 case Manifest.permission.READ_CONTACTS:
                                 case Manifest.permission.WRITE_CONTACTS:
                                     ToastUtil.show(this,"通讯录读写获取不成功");
                                     JumpToSettings();
                                     return ;
                                 case Manifest.permission.READ_SMS:
                                 case Manifest.permission.SEND_SMS:
                                     ToastUtil.show(this,"短信读写获取不成功");
                                     JumpToSettings();
                                     return ;
                             }
                         }
                     }
                 }
             case RequestCodeConTact:
                 if(PermissionUtil.checkGrant(grantResults))
                 {
                     Log.d("权限情况:","通讯录权限请求成功");
                 }
                 else{
                     ToastUtil.show(this,"通讯录获取失败");
                     JumpToSettings();
                 }
                 break;
             case RequestCodeSMS:
                 if(PermissionUtil.checkGrant(grantResults))
                 {
                     Log.d("权限情况:","短信权限请求成功");
                 }
                 else{
                     ToastUtil.show(this,"短信获取失败");
                     JumpToSettings();
                 }
                 break;
         }
     }
     public void JumpToSettings(){
         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);
     }
}
package com.example.client_provider.util;

import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class PermissionUtil {
    public static boolean CheckPermissions(Activity activity, String[] permissions, int RequestCode){
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){
            int check= PackageManager.PERMISSION_GRANTED;
            for(String permission:permissions ){
                check=ContextCompat.checkSelfPermission(activity,permission);
                if(check!=PackageManager.PERMISSION_GRANTED){
                    break;
                }
            }
            //未开启权限则自动弹窗
            if(check!=PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(activity,permissions,RequestCode);
                return false;
            }
        }
        return true;
    }

    public static boolean checkGrant(int[] grantResults) {
        if(grantResults!=null){
            for(int grantResult :grantResults){
                if(grantResult!=PackageManager.PERMISSION_GRANTED){
                    return false;
                }
            }
            return true;
        }
        return false;
    }

}

  1. 添加查询联系人

利用ContentResolver读写联系人,联系人分为两张表:
raw_contacts表:记录联系人的_id号,状态等信息
data表:记录用户通讯录的所有数据,根据mimetype_id表示不同的数据类型,raw_contact_id与raw_contacts表中的_id对应,根据这种外键联系,
一个联系人可添加多个邮箱,多个电话号码。

例子:添加和查询联系人,前提:权限已开启

package com.example.client_provider;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ContentProvider;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.CommonDataKinds;
import com.example.client_provider.entity.Contact;

import java.util.ArrayList;

public class ContactAddActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText et_contact_name;
    private EditText et_contact_phone;
    private EditText et_contact_email;
    @SuppressLint({"WrongViewCast", "MissingInflatedId"})
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_contact_add);
        et_contact_name=findViewById(R.id.tv_name);
        et_contact_phone=findViewById(R.id.phone);
        et_contact_email=findViewById(R.id.email);
        findViewById(R.id.add).setOnClickListener(this);
        findViewById(R.id.query).setOnClickListener(this);
    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.add:
                Contact contact=new Contact();
                contact.name=et_contact_name.getText().toString();
                contact.phone=et_contact_phone.getText().toString();
                contact.email=et_contact_email.getText().toString();
                //使用ContentSolver多次写入
                //addContacts(getContentResolver(),contact);
                //批量处理联系人,好处是,要么全部成功,要么全部失败,保证了事务的一致性
                addFullContacts(getContentResolver(), contact);
                break;
            case  R.id.query:
                readPhoneContact(getContentResolver());
                break;
        }
    }

    private void readPhoneContact(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()) {
                @SuppressLint("Range") String data1 = dataCursor.getString(dataCursor.getColumnIndex(Contacts.Data.DATA1));
                @SuppressLint("Range") 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();
            if (contact.name != null) {
                Log.d("联系人:", contact.toString());
            }
        }
        cursor.close();
        }

    private void addFullContacts(ContentResolver contentResolver, Contact contact) {
        ContentProviderOperation op_main=ContentProviderOperation
                .newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME,null)
                .build();
    //联系人姓名记录操作器
        ContentProviderOperation op_name = ContentProviderOperation
                .newInsert(ContactsContract.Data.CONTENT_URI)
                // 将第0个操作的id,即 raw_contacts 的 id 作为 data 表中的 raw_contact_id
                .withValueBackReference(Contacts.Data.RAW_CONTACT_ID, 0)
                .withValue(Contacts.Data.MIMETYPE, CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(Contacts.Data.DATA2, contact.name)
                .build();

        ContentProviderOperation op_phone=ContentProviderOperation
                .newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(Contacts.Data.RAW_CONTACT_ID,0)
                .withValue(Contacts.Data.MIMETYPE,CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(Contacts.Data.DATA1, contact.email)
                .withValue(Contacts.Data.DATA2, CommonDataKinds.Email.TYPE_WORK)
                .build();

        ContentProviderOperation op_email = ContentProviderOperation
                .newInsert(ContactsContract.Data.CONTENT_URI)
                // 将第0个操作的id,即 raw_contacts 的 id 作为 data 表中的 raw_contact_id
                .withValueBackReference(Contacts.Data.RAW_CONTACT_ID, 0)
                .withValue(Contacts.Data.MIMETYPE, CommonDataKinds.Email.CONTENT_ITEM_TYPE)
                .withValue(Contacts.Data.DATA1, contact.email)
                .withValue(Contacts.Data.DATA2, CommonDataKinds.Email.TYPE_WORK)
                .build();

        ArrayList<ContentProviderOperation> operations = new ArrayList<>();
        operations.add(op_main);
        operations.add(op_name);
        operations.add(op_phone);
        operations.add(op_email);

        try {
            contentResolver.applyBatch(ContactsContract.AUTHORITY,operations);
        } catch (OperationApplicationException | RemoteException e) {
            throw new RuntimeException(e);
        }
    }

    private void addContacts(ContentResolver resolver, Contact contact) {
        ContentValues values=new ContentValues();
        Uri uri=resolver.insert(ContactsContract.RawContacts.CONTENT_URI,values);
        //获取RawContacts表中的ID
        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.Phone.CONTENT_ITEM_TYPE);
        phone.put(Contacts.Data.DATA1,contact.phone);
        //联系类型,1表示家庭,2表示工作
        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.Email.CONTENT_ITEM_TYPE);
        email.put(Contacts.Data.DATA1,contact.email);
        email.put(Contacts.Data.DATA2,CommonDataKinds.Email.TYPE_WORK);
        resolver.insert(ContactsContract.Data.CONTENT_URI,email);

    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++算法初级9——递归

C算法初级9——递归 文章目录C算法初级9——递归递归求阶乘递归求斐波那契数列递归&#xff0c;简单地来说&#xff0c;就是一个函数自己调用自己。函数f()就好像是工厂中生产零件的模板&#xff0c;每次我们调用函数f()的时候&#xff0c;都会依照模板生产一个新的零件&#x…

项目4:后台管理的开发和使用(前端)

项目4&#xff1a;后台管理的开发和使用&#xff08;前端&#xff09; 1.npm包管理器的基本学习 2.利用现成后台管理系统开发 3.后台管理系统的路由配置 4.后台管理系统的地址访问配置 5.前后端联调 6.完善积分等级的前端系统 7.对前端系统的全面分析&#xff08;Vue组件…

跳槽进阿里了,其实也没那么难...

对于很多没有学历优势的人来说&#xff0c;面试大厂是非常困难的&#xff0c;这对我而言&#xff0c;也是一样&#xff0c;出身于二本&#xff0c;原本以为就三点一线的生活度过一生&#xff0c;直到生活上的变故&#xff0c;才让我有了新的想法和目标&#xff0c;因此我这个二…

【C++ -模块一 常量变量、关键字、数据类型】

C 模块一C框架代码&#xff1a;第一个C程序&#xff0c;打印hello C &#xff01;代码注释&#xff1a;一 变量和常量&#xff1a;1.1变量变量创建语法&#xff1a;1.2 常量&#xff1a;不能被修改的数据&#xff08;1&#xff09; #define定义的宏常量&#xff1a;一般写在文件…

排序(3)之交换排序

目录 前言 交换排序 1.冒泡排序 1.1冒泡排序的实现 1.2 特性总结 2.快速排序 2.1hoare版本 2.2 挖坑法 2.3 前后指针版本 3.快速排序的优化 3.1 三数取中法 3.2 小区间优化 4.快速排序的非递归实现 前言 今天小编给大家带来交换排序的内容&#xff0c;对于交换排序…

C-关键字(下)

文章目录循环控制switch-case-break-defaultdo-while-forgetchar()break-continuegotovoidvoid*returnconstconst修饰变量const修饰数组const修饰指针指针补充const 修饰返回值volatilestruct柔型数组union联合体联合体空间开辟问题利用联合体的性质,判断机器是大端还是小端enu…

力扣javascript刷题343——动态规划之整数拆分

这几天有在开始投暑期实习的简历&#xff0c;可能确实是投的太晚了&#xff0c;好多厂都没有hc了&#xff0c;阿里简历面都没过&#xff08;感觉是kpi面试&#xff09;&#xff0c;被深深打击到了呜呜呜&#xff0c;花了两天整理情绪&#xff0c;重新出发&#xff0c;下篇文章针…

mysql 索引详解

mysql 索引索引分类1. 普通索引和唯一索引2. 单列索引和组合索引3. 全文索引4&#xff0e;空间索引操作使用索引1. 在已有表中添加索引2. 删除索引索引是一个单独存储在磁盘上的数据库结构&#xff0c;使用索引可以快速找出在某个或多个列中有一特定值的行&#xff0c;提高查询…

【C语言 -结构体 结构体声明、定义、初始化、结构体成员访问、结构体传参】

C语言 - 结构体声明、定义、初始化、结构体成员访问、结构体传参一 结构体类型的声明&#xff1a;声明格式&#xff1a;二 结构体的定义并初始化2.1用结构体创建&#xff08;定义&#xff09;结构体变量&#xff08;对象&#xff09;的两种方式&#xff1a;&#xff08;1&#…

WebRTC 系列(三、点对点通话,H5、Android、iOS)

WebRTC 系列&#xff08;二、本地 demo&#xff0c;H5、Android、iOS&#xff09; 上一篇博客中&#xff0c;我已经展示了各端的本地 demo&#xff0c;大家应该知道 WebRTC 怎么用了。在本地 demo 中是用了一个 RemotePeerConnection 来模拟远端&#xff0c;可能理解起来还有点…

HTTP协议:当下最主流的应用层协议之一,你确定不了解一下吗?

一.HTTP协议的含义http是什么&#xff1f;超文本传输协议&#xff08;Hyper Text Transfer Protocol&#xff0c;HTTP&#xff09;是一个简单的请求-响应协议&#xff0c;它通常运行在TCP之上。‘超’可以理解为除了文本之外的图片&#xff0c;音频和视频&#xff0c;和一些其他…

硬盘、文件系统相关常识

1.硬盘 以机械硬盘为例&#xff0c;下面是机械硬盘的外形结构。 结构图&#xff1a; 每个磁盘分为两个盘面&#xff0c;每个盘面中有很多磁道(Disk Track)&#xff0c;每个磁道上有很多扇区(Sector)&#xff0c;磁道上的一段一段的就是扇区。 扇区是最小的单位&#xff0c;…

Flutter开发日常练习-黑白主题

1.添加了白天黑夜模式 2.country_picker: ^2.0.20 城市信息框架 3.image_picker: ^0.8.53 photo_manager: ^2.3.0 相机和相册的调用 4.shared_preferences: ^2.0.8 sqflite: ^1.3.1 path: 数据异步持久化到磁盘 注:登录的时候记录一下登录状态isLogin,通过isLogin来标记是否…

OCR之论文笔记TrOCR

文章目录TrOCR: Transformer-based Optical Character Recognition with Pre-trained Models一. 简介二. TrOCR2.1. Encoder2.2 Decoder2.3 Model Initialiaztion2.4 Task Pipeline2.5 Pre-training2.6 Fine-tuning2.7 Data Augmentation三. 实验3.1 Data3.2 Settings3.2 Resul…

如何战胜AI?唯努力尔-- DSP算法的FPGA实现指南

如何战胜AI?唯努力尔! DSP算法的FPGA实现指南! 来一集番外。 而这 也是开坑的第一个算法&#xff01;我们先讲案例再谈实现指南 文章目录如何战胜AI?唯努力尔! DSP算法的FPGA实现指南!观前提醒实用算法原理数学原理代码模块划分与实现FIR滤波器误差计算与系数更新模块最终代…

算法 贪心2 || 122.买卖股票的最佳时机II 55. 跳跃游戏 45.跳跃游戏II

122.买卖股票的最佳时机II 如果想到其实最终利润是可以分解的&#xff0c;那么本题就很容易了&#xff01; 如何分解呢&#xff1f; 假如第0天买入&#xff0c;第3天卖出&#xff0c;那么利润为&#xff1a;prices[3] - prices[0]。 相当于(prices[3] - prices[2]) (prices[2…

HBuilderX 开发工具

介绍 uni-app 官方推荐使用 HBuilderX 来开发 uni-app 类型的项目。 主要好处&#xff1a; 模板丰富完善的智能提示一键运行 下载 HBuilderX 1、官网下载地址&#xff1a;https://www.dcloud.io/hbuilderx.html 2、下载正式版&#xff08;根据自己电脑选&#xff09; 安装…

( “树” 之 DFS) 112. 路径总和 ——【Leetcode每日一题】

112. 路径总和 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点…

虚假评论检测可视化系统的实现

菜鸟一枚&#xff0c;大佬勿喷&#xff0c;主要是想分享&#xff0c;希望能帮到像我一样的人。 主要代码是参考&#xff1a;https://github.com/SoulDGXu/NLPVisualizationSystem/tree/master/frontend 他这个代码实现了词云、摘要生成等功能吧。因为我做的是虚假评论检测系统&…

星环科技自研技术,加速大数据从持久化、统一化、资产化、业务化到生态化

从2013年成立开始&#xff0c;星环科技就专注于大数据基础技术与企业数据业务的更好结合&#xff0c;同时面对中国更为复杂的数据应用场景&#xff0c;研发了多种更贴合国内大数据应用需求的大数据管理技术&#xff0c;在大数据技术领域有多项基础技术突破。星环科技在坚持技术…