Android组件

1 日期、时间选择器

implementation 'com.contrarywind:Android-PickerView:3.2.7'

<TextView
	android:id="@+id/search_end_time"
	android:layout_width="wrap_content"
	android:layout_height="45dp"
	android:text="2023-02-14"
	android:textColor="@color/text_color"
	android:gravity="center"
	android:textSize="10sp"
	android:textStyle="bold"/>
import com.bigkoo.pickerview.TimePickerView;

	private TextView search_end_time; //搜索结束时间
	private TimePickerView pvTime_end; //日期选择器
	
	public void initView(){
        search_end_time = view.findViewById(R.id.search_end_time);
        search_end_time.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //点击组件的点击事件
                pvTime_end.show(search_end_time);
            }
        });
        //控制时间范围(如果不设置范围,则使用默认时间1900-2100年,此段代码可注释)
        //因为系统Calendar的月份是从0-11的,所以如果是调用Calendar的set方法来设置时间,月份的范围也要是从0-11
        Calendar selectedDate = Calendar.getInstance();
        Calendar selectedStartDate = Calendar.getInstance();
        selectedStartDate.set(2000, 0, 1);
        Calendar selectedEndDate = Calendar.getInstance();
        selectedEndDate.set(2100, 11, 31);
        //时间选择器
        pvTime_end = new TimePickerView.Builder(getContext(), new TimePickerView.OnTimeSelectListener() {
            @Override
            public void onTimeSelect(Date date, View v) {//选中事件回调
                // 这里回调的v,就是show()方法里面所添加的 View 参数,如果show的时候没有添加参数,v则为null
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
                search_end_time.setText(format.format(date));
            }
        })
                //年月日时分秒的显示与否,不设置则默认全部显示,这里可自行定制
                .setType(new boolean[]{true, true, true, false, false, false})
                .setLabel(" 年", "月", "日", "", "", "")
                .setCancelText("取消")//取消按钮文字
                .setSubmitText("确认")//确认按钮文字.isCenterLabel(true)
                .setDividerColor(Color.DKGRAY)
                .setContentSize(20)
                .setDate(selectedDate)
                .setRangDate(selectedStartDate, selectedEndDate)
                .setDecorView(null)
                .build();
	}

自定义显示
.setType(new boolean[]{true, true, true, true, true, true})// 默认全部显示
.setCancelText(“Cancel”)//取消按钮文字
.setSubmitText(“Sure”)//确认按钮文字
.setContentSize(18)//滚轮文字大小
.setTitleSize(20)//标题文字大小
.setTitleText(“Title”)//标题文字
.setOutSideCancelable(false)//点击屏幕,点在控件外部范围时,是否取消显示
.isCyclic(true)//是否循环滚动
.setTitleColor(Color.BLACK)//标题文字颜色
.setSubmitColor(Color.BLUE)//确定按钮文字颜色
.setCancelColor(Color.BLUE)//取消按钮文字颜色
.setTitleBgColor(0xFF666666)//标题背景颜色 Night mode
.setBgColor(0xFF333333)//滚轮背景颜色 Night mode
.setDate(selectedDate)// 如果不设置的话,默认是系统时间*/
.setRangDate(startDate,endDate)//起始终止年月日设定
.setLabel(“年”,“月”,“日”,“时”,“分”,“秒”)//默认设置为年月日时分秒
.isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。
.isDialog(true)//是否显示为对话框样式

2 播放铃声

在这里插入图片描述

import android.media.MediaPlayer;

	
	private MediaPlayer player; //播放声音
	
	public void initData(){
		//初始化
		player = MediaPlayer.create(getContext(), R.raw.notification);
	}
	
	public void f(){
		//播放
		player.start();
	}

3 手机震动

	//方法1
	public void f1(){
	    Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
	    vibrator.vibrate(100);
	}
	//上面这种方式,在有些低版本手机中返回桌面后,收到新消息不会震动
	//下面这种方式都可:

	//方法2
	public void f2(){
    	playVibrate(getContext(), false);
	}

 	/**
     * 手机震动
     *
     * @param context
     * @param isRepeat 是否重复震动
     */
    public static void playVibrate(Context context, boolean isRepeat) {

        /*
         * 设置震动,用一个long的数组来表示震动状态(以毫秒为单位)
         * 如果要设置先震动1秒,然后停止0.5秒,再震动2秒则可设置数组为:long[]{1000, 500, 2000}。
         * 别忘了在AndroidManifest配置文件中申请震动的权限:android.permission.VIBRATE
         */
        try {
            Vibrator mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
            long[] patern = new long[]{200, 100, 200};
            AudioAttributes audioAttributes = null;
            /**
             * 适配android7.0以上版本的震动
             * 说明:如果发现5.0或6.0版本在app退到后台之后也无法震动,那么只需要改下方的Build.VERSION_CODES.N版本号即可
             */
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                audioAttributes = new AudioAttributes.Builder()
                        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                        .setUsage(AudioAttributes.USAGE_ALARM) //key
                        .build();
                mVibrator.vibrate(patern, isRepeat ? 1 : -1, audioAttributes);
            }else {
                mVibrator.vibrate(patern, isRepeat ? 1 : -1);
            }
        } catch (Exception ex) {
        }
    }

4 时间、日期相关

4.1 定时器

import android.os.Handler;

public class ZhilingFragment extends Fragment {
	Handler mHandler = new Handler();
	Runnable r = new Runnable() {
	    @Override
	    public void run() {
	        //每隔10分钟循环执行run方法
	        if (mHandler != null) {
	            getData3(); //do something
	            mHandler.postDelayed(this, 10 * 1000);
	        }
	    }
	};
	public void dingshiqiGetZhilingliuzhuanList(){
		// 开启定时器
		mHandler.postDelayed(r, 100);//延时100毫秒
		// 停止定时器
		mHandler.removeCallbacks(r);
	}
}

4.2 Date与字符串的转换

//字符串转Date类型
String time = "2020-02-02 02:02:02";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
    Date newTime = format.parse(time);
    System.out.println("转换以后的时间::"+newTime);//Sun Feb 02 02:02:02 CST 2020
} catch (Exception e) {
    e.printStackTrace();
}

//Date类型转换成字符串
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
String nowTime = format.format(date);
System.out.println("当前的时间::"+nowTime);//2020-08-25 21:28:22

4.3 计算某一日期的前(后)一天

long time = System.currentTimeMillis()/*new Date().getTime()*/;
Date date = new Date(time - 1000 * 60 * 60 * 24 * 1);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateS = format.format(date);

4.4 延迟器

new Handler().postDelayed(new Runnable(){
    public void run(){
        do();
    }
},2000);

5 设置角标

implementation 'q.rorbin:badgeview:1.1.3'

    private TextView tab_check_btn; // 需要绑定角标的控件
    private QBadgeView badgeView1; //角标控件

	public void initData(){
        badgeView1 = new QBadgeView(getContext());
        badgeView1.bindTarget(tab_check_btn);
    }
    
	public void f(){
		//在导航栏“指令流转”中绑定角标
		badgeView1.setBadgeNumber(100);
	}

在这里插入图片描述

6 常用布局

6.1 TextView、EditView边框

<EditText
    android:id="@+id/edit_content"
    android:layout_width="0sp"
    android:layout_height="wrap_content"
    android:layout_weight="3"
    android:enabled="true"
    android:minLines="8"
    android:maxLines="10"
    android:scrollbars="vertical"
    android:background="@drawable/border"
    android:text=""
    android:textStyle="bold"
    android:textColor="@color/text_selected"
    android:gravity="left"
    android:textSize="16sp"/>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#FFFFFF"/>
    <stroke
        android:width="1dp"
        android:color="#A0A0A0"/>
    <padding
        android:bottom="10dp"
        android:left="10dp"
        android:right="10dp"
        android:top="10dp"/>
    <corners android:radius="10dp"/>
</shape>

6.2 TextView设置部分文字颜色

TextView desc1 = (TextView)findViewById(R.id.desc1);
TextView desc2 = (TextView)findViewById(R.id.desc2);
TextView desc3 = (TextView)findViewById(R.id.desc3);
String content1 = "务必使用<font color='#ff0000'>银行卡</font>开户时<font color='red'>预留手机号</font>!";
String content2 = "点击获取验证码按钮后,您将收到<font color='red'>银行验证码短信</font>!";
String content3 = "时间<font color='red'>工作日09:00 - 次日06:00</font>!";
desc1.setText(Html.fromHtml(content1));
desc2.setText(Html.fromHtml(content2));
desc3.setText(Html.fromHtml(content3));

6.3 验证码

(1)工具类 CodeUtils.java

package com.example.testbar.utils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

import java.util.Random;

public class CodeUtils {
    //随机码集
    private static final char[] CHARS = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };

    private static CodeUtils mCodeUtils;
    private int mPaddingLeft, mPaddingTop;
    private StringBuilder mBuilder = new StringBuilder();
    private Random mRandom = new Random();

    //Default Settings
    private static final int DEFAULT_CODE_LENGTH = 4;//验证码的长度  这里是4位
    private static final int DEFAULT_FONT_SIZE = 60;//字体大小
    private static final int DEFAULT_LINE_NUMBER = 3;//多少条干扰线
    private static final int BASE_PADDING_LEFT = 20; //左边距
    private static final int RANGE_PADDING_LEFT = 30;//左边距范围值
    private static final int BASE_PADDING_TOP = 70;//上边距
    private static final int RANGE_PADDING_TOP = 15;//上边距范围值
    private static final int DEFAULT_WIDTH = 200;//默认宽度.图片的总宽
    private static final int DEFAULT_HEIGHT = 100;//默认高度.图片的总高
    private static final int DEFAULT_COLOR = Color.rgb(0xee, 0xee, 0xee);//默认背景颜色值

    private String code;

    public static CodeUtils getInstance() {
        if (mCodeUtils == null) {
            mCodeUtils = new CodeUtils();
        }
        return mCodeUtils;
    }

    //生成验证码图片
    public Bitmap createBitmap() {
        mPaddingLeft = 0; //每次生成验证码图片时初始化
        mPaddingTop = 0;

        Bitmap bitmap = Bitmap.createBitmap(DEFAULT_WIDTH, DEFAULT_HEIGHT, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        code = createCode();
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawColor(DEFAULT_COLOR);
        Paint paint = new Paint();
        paint.setTextSize(DEFAULT_FONT_SIZE);

        for (int i = 0; i < code.length(); i++) {
            randomTextStyle(paint);
            randomPadding();
            canvas.drawText(code.charAt(i) + "", mPaddingLeft, mPaddingTop, paint);
        }

        //干扰线
        for (int i = 0; i < DEFAULT_LINE_NUMBER; i++) {
            drawLine(canvas, paint);
        }

        canvas.save();//保存
        canvas.restore();
        return bitmap;
    }

    /**
     * 得到图片中的验证码字符串
     *
     * @return
     */
    public String getCode() {
        return code;
    }

    //生成验证码
    public String createCode() {
        mBuilder.delete(0, mBuilder.length()); //使用之前首先清空内容
        for (int i = 0; i < DEFAULT_CODE_LENGTH; i++) {
            mBuilder.append(CHARS[mRandom.nextInt(CHARS.length)]);
        }
        return mBuilder.toString();
    }

    //生成干扰线
    private void drawLine(Canvas canvas, Paint paint) {
        int color = randomColor();
        int startX = mRandom.nextInt(DEFAULT_WIDTH);
        int startY = mRandom.nextInt(DEFAULT_HEIGHT);
        int stopX = mRandom.nextInt(DEFAULT_WIDTH);
        int stopY = mRandom.nextInt(DEFAULT_HEIGHT);
        paint.setStrokeWidth(1);
        paint.setColor(color);
        canvas.drawLine(startX, startY, stopX, stopY, paint);
    }

    //随机颜色
    private int randomColor() {
        mBuilder.delete(0, mBuilder.length()); //使用之前首先清空内容
        String haxString;
        for (int i = 0; i < 3; i++) {
            haxString = Integer.toHexString(mRandom.nextInt(0xEE));
            if (haxString.length() == 1) {
                haxString = "0" + haxString;
            }
            mBuilder.append(haxString);
        }
        return Color.parseColor("#" + mBuilder.toString());
    }

    //随机文本样式
    private void randomTextStyle(Paint paint) {
        int color = randomColor();
        paint.setColor(color);
        paint.setFakeBoldText(mRandom.nextBoolean());  //true为粗体,false为非粗体
        float skewX = mRandom.nextInt(11) / 10;
        skewX = mRandom.nextBoolean() ? skewX : -skewX;
        paint.setTextSkewX(skewX); //float类型参数,负数表示右斜,整数左斜
        paint.setUnderlineText(mRandom.nextBoolean()); //true为下划线,false为非下划线
        paint.setStrikeThruText(mRandom.nextBoolean()); //true为删除线,false为非删除线
    }

    //随机间距
    private void randomPadding() {
        mPaddingLeft += BASE_PADDING_LEFT + mRandom.nextInt(RANGE_PADDING_LEFT);
        mPaddingTop = BASE_PADDING_TOP + mRandom.nextInt(RANGE_PADDING_TOP);
    }
}

(2)layout:

<ImageView
    android:id="@+id/image"
    android:layout_width="100dp"
    android:layout_height="match_parent"
    android:layout_marginLeft="10dp" />

(3)activity:

//获取需要展示图片验证码的ImageView
ImageView image = (ImageView) getActivity().findViewById(R.id.image);
//获取工具类生成的图片验证码对象
final Bitmap[] bitmap = {CodeUtils.getInstance().createBitmap()};
//获取当前图片验证码的对应内容用于校验
final String[] code = {CodeUtils.getInstance().getCode()};

image.setImageBitmap(bitmap[0]);
image.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        bitmap[0] = CodeUtils.getInstance().createBitmap();
        code[0] = CodeUtils.getInstance().getCode();
        image.setImageBitmap(bitmap[0]);
        Toast.makeText(getContext(), code[0], Toast.LENGTH_SHORT).show();
    }
});

6.4 轮播图

//banner轮播框架
implementation 'com.youth.banner:banner:1.4.10'
// Glide 图片加载
implementation 'com.github.bumptech.glide:glide:3.7.0'

<com.youth.banner.Banner
    android:id="@+id/mBanner"
    android:layout_width="match_parent"
    android:layout_height="330dp" />
private Banner mBanner;
public void initView() {
    mBanner = getActivity().findViewById(R.id.mBanner);
    //图片资源
    int[] imageResourceID = new int[]{R.drawable.zh_selected, R.drawable.zhss_selected, R.drawable.message, R.drawable.center_selected};
    List<Integer> imgeList = new ArrayList<>();
    //轮播标题
    String[] mtitle = new String[]{"图片1", "图片2", "图片3", "图片4"};
    List<String> titleList = new ArrayList<>();

    for (int i = 0; i < imageResourceID.length; i++) {
        imgeList.add(imageResourceID[i]);//把图片资源循环放入list里面
        titleList.add(mtitle[i]);//把标题循环设置进列表里面
        //设置图片加载器,通过Glide加载图片
        mBanner.setImageLoader(new ImageLoader() {
            @Override
            public void displayImage(Context context, Object path, ImageView imageView) {
                Glide.with(getActivity()).load(path).into(imageView);
            }
        });
        //设置轮播的动画效果,里面有很多种特效,可以到GitHub上查看文档。
        mBanner.setBannerAnimation(Transformer.Accordion);
        mBanner.setImages(imgeList);//设置图片资源
        mBanner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE);//设置banner显示样式(带标题的样式)
        mBanner.setBannerTitles(titleList); //设置标题集合(当banner样式有显示title时)
        //设置指示器位置(即图片下面的那个小圆点)
        mBanner.setIndicatorGravity(BannerConfig.CENTER);
        mBanner.setDelayTime(1000);//设置轮播时间3秒切换下一图
        mBanner.setOnBannerListener(new OnBannerListener() {
            @Override
            public void OnBannerClick(int position) {
                Toast.makeText(getContext(), "你点击了第" + (position + 1) + "张轮播图", Toast.LENGTH_SHORT).show();
            }
        });//设置监听
        mBanner.start();//开始进行banner渲染
        mBanner.startAutoPlay();//开始轮播
        //mBanner.stopAutoPlay();//结束轮播
    }
}

6.5 读取strings.xml配置的数组

资源文件(res/strings.xml)定义字符串、一维数组

<resources>
    <string name="nav_Zh">治安系统</string>
    <string name="nav_NbCheck">人员核查</string>
    <string name="nav_Message">即时通讯</string>
    <string name="nav_Info">个人信息</string>
    
    <!-- 一维数组 -->
    <string-array name= "good" >
        <item>a</item>
        <item>b</item>
        <item>c</item>
        <item>d</item>
    </string-array>

</resources>
	Resources res =getResources();
    // 取xml文件格式的字符数组
    String[] good=res.getStringArray(R.array.good);
    Log.e("xml数组", String.valueOf(good));

无法直接定义二维数组,但可以通过一维数组得到

<!-- 用一维数组的方式间接定义二维数组 (注意区分,和,)-->
<array name= "two" >
	<item>a,b,c,d,e,f,g</item>
	<item>h,i,g,k,l,m,n</item>
</array>
	Resources res =getResources();
	// 取xml文件格式的字符数组
	String[] array = res.getStringArray(R.array.two);
	String[][] result = getTwoDimensionalArray(array);
	/**
     * 按设定规则解析一维数组为二维数组
     * @param array
     * @return
     */
    private String[][] getTwoDimensionalArray(String[] array) {
        String[][] twoDimensionalArray = null ;
        for ( int i = 0 ; i < array.length; i++) {
            String[] tempArray = array[i].split( "," );
            if (twoDimensionalArray == null ) {
                twoDimensionalArray = new String[array.length][tempArray.length];
            }
            for ( int j = 0 ; j < tempArray.length; j++) {
                twoDimensionalArray[i][j] = tempArray[j];
            }
        }
        return twoDimensionalArray;
    }

6.6 动态获取drawable下的图片

	// 为TextView R.id.mgbs_pic1设置图片pic1_1_1_1.jpg
	TextView mgbs_pic1 = view.findViewById(R.id.mgbs_pic1);
	Field field = R.drawable.class.getDeclaredField("pic1_1_1_1");
	int pic_id = field.getInt("pic1_1_1_1");
	mgbs_pic1.setBackgroundResource(pic_id);

6.7 动态追加layout

	LayoutInflater inflater = getLayoutInflater();
	// 将LinearLayout下清空
	xcczl_linearLayout.removeAllViews();
	// 加载diy的layout
	View view = inflater.inflate(R.layout.layout_mgbs, null);
	// 设置layout中的元素
	TextView mgbs_title = view.findViewById(R.id.mgbs_title);
    mgbs_title.setText("123456 ");
    // 加layout增加到父元素
    xcczl_linearLayout.addView(view);

6.8 ImageView填充width,按比例自适应height

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/mgbs_big_pic"
        android:scaleType="fitXY"
        android:adjustViewBounds="true"
        tools:ignore="MissingConstraints" />
		Intent intent = getIntent();
        String pic_name = intent.getStringExtra("pic_name");
        ImageView mgbs_big_pic = findViewById(R.id.mgbs_big_pic);
        Field field = null;
        try {
            field = R.drawable.class.getDeclaredField(pic_name);
            int pic_id = field.getInt(pic_name);
            mgbs_big_pic.setImageResource(pic_id);
        } catch (Exception e) {
            e.printStackTrace();
        }

6.9 读取assests下json文件

在这里插入图片描述

{
  "name": "John Smith",
  "age": 35,
  "isMarried": true,
  "hobbies": [
    "reading",
    "fishing",
    "hiking"
  ]
}
/**
     * 读取assets下json文件
     * @param context
     * @param filename
     * @return
     */
    public static JSONObject getJSONFile(Context context, String filename) {
        try {
            InputStream is = context.getAssets().open(filename);
            int size = is.available();
            byte[] buffer = new byte[size];
            is.read(buffer);
            is.close();
            String jsonString = new String(buffer, "UTF-8");
            JSONObject jsonObject = new JSONObject(jsonString);
            return jsonObject;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

//方法使用
JSONObject jsonObject = FileUtils.getJSONFile(getContext(), "test.json");

7 下拉框

    1. 加入依赖
      implementation 'com.github.arcadefire:nice-spinner:1.4.4'
    1. 布局

用户可以在xml文件布局中添加以下属性到NiceSpinner控件中,对NiceSpinner进行设置。
arrowTint   color   设置下拉箭头上的颜色
hideArrow   boolean   设置是显示还是隐藏下拉箭头
arrowDrawable   reference   set the drawable of the drop-down arrow
textTint   color   设置文本颜色
backgroundSelector   color   选项背景色
dropDownListPaddingBottom   dimension   设置下拉列表的底部填充(即设置下拉框控件的高度)

    <!--数据类型下拉框-->
    <org.angmarch.views.NiceSpinner
        android:id="@+id/nice_spinner"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_below="@+id/rw"
        android:layout_centerHorizontal="true"        
        app:arrowTint="@color/white"
        app:backgroundSelector="@color/text_color"
        app:textTint="@color/white"/>
    1. 代码
public class TestActivity extends AppCompatActivity {
 
    private NiceSpinner niceSpinner;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        NiceSpinner niceSpinner = (NiceSpinner) findViewById(R.id.nice_spinner);
        niceSpinner.setTextColor(Color.GREEN);
 
        LinkedList<String> data=new LinkedList<>(Arrays.asList("华为", "京东", "腾讯", "小米"));
        //添加数据源
        niceSpinner.attachDataSource(data);
        // 设置背景色
        nice_spinner.setBackgroundResource(R.drawable.shuzikuang);
        //默认展示第一项:“京东”
		nice_spinner.setSelectedIndex(1);
        
        niceSpinner.getSelectedItem();
        // 获取展示的内容
        niceSpinner.getText();
        niceSpinner.setOnSpinnerItemSelectedListener(new OnSpinnerItemSelectedListener() {
            @Override
            public void onItemSelected(NiceSpinner parent, View view, int position, long id) {
                Toast.makeText(TestActivity.this,niceSpinner.getText(),Toast.LENGTH_SHORT)
                        .show();
            }
        });
        
    }
 
}

8 生成Excel

    1. 加入依赖implementation 'net.sourceforge.jexcelapi:jxl:2.6.12''
    1. 工具类
package com.example.smartlock.util;

import android.content.Context;
import android.widget.Toast;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.format.Colour;
import jxl.write.Label;
import jxl.write.WritableCell;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;

/**
 * 创建时间:2020-12-25
 * 编写人:kanghb
 * 功能描述:将数据导出excel 经测试4万条学生数据一秒左右完成
 */
public class ExcelUtil {

    /**
     * 上下文对象
     */
    private static Context mContext;

    private static WritableFont arial14font = null;
    private static WritableCellFormat arial14format = null;
    private static WritableFont arial10font = null;
    private static WritableCellFormat arial10format = null;
    private static WritableFont arial12font = null;
    private static WritableCellFormat arial12format = null;
    private final static String UTF8_ENCODING = "UTF-8";


    /**
     * 单元格的格式设置 字体大小 颜色 对齐方式、背景颜色等...
     */
    private static void format() {
        try {
            arial14font = new WritableFont(WritableFont.ARIAL, 14, WritableFont.BOLD);
            arial14font.setColour(jxl.format.Colour.LIGHT_BLUE);
            arial14format = new WritableCellFormat(arial14font);
            arial14format.setAlignment(jxl.format.Alignment.CENTRE);
            arial14format.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN);
            arial14format.setBackground(jxl.format.Colour.VERY_LIGHT_YELLOW);

            arial10font = new WritableFont(WritableFont.ARIAL, 10, WritableFont.BOLD);
            arial10format = new WritableCellFormat(arial10font);
            arial10format.setAlignment(jxl.format.Alignment.CENTRE);
            arial10format.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN);
            arial10format.setBackground(Colour.GRAY_25);

            arial12font = new WritableFont(WritableFont.ARIAL, 12);
            arial12format = new WritableCellFormat(arial12font);
            //对齐格式
            arial12format.setAlignment(jxl.format.Alignment.CENTRE);
            //设置边框
            arial12format.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN);


        } catch (WriteException e) {
            e.printStackTrace();
        }
    }


    /**
     * 初始化Excel表格
     *
     * @param filePath  存放excel文件的路径(MPCMS/Export/demo.xls)
     * @param sheetName Excel表格的表名
     * @param colName   excel中包含的列名(可以有多个)
     */
    public static void initExcel(String filePath, String sheetName, String[] colName, Context context) {
        if (null == mContext) {
            mContext = context;
        }
        format();
        WritableWorkbook workbook = null;

        try {
            File file = new File(mContext.getFilesDir().getPath() + "/Export");
            makeDir(file);
            File saveFile = new File(file, filePath);
            if (!saveFile.exists()) {
                saveFile.createNewFile();
            }

            workbook = Workbook.createWorkbook(saveFile);
            //设置表格的名字
            WritableSheet sheet = workbook.createSheet(sheetName, 0);
            //创建标题栏
            sheet.addCell((WritableCell) new Label(0, 0, filePath, arial14format));
            for (int col = 0; col < colName.length; col++) {
                sheet.addCell(new Label(col, 0, colName[col], arial10format));
            }
            //设置行高
            sheet.setRowView(0, 340);
            workbook.write();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 将制定类型的List写入Excel中
     *
     * @param objList  待写入的list,
     * @param fileName 文件名:用户名_模块_任务名_时间
     * @param c
     */
    @SuppressWarnings("unchecked")
    public static void writeObjListToExcel(List<ArrayList<String>> objList, String fileName, Context c) {
        if (objList != null && objList.size() > 0) {
            WritableWorkbook writebook = null;
            InputStream in = null;
            try {
                WorkbookSettings setEncode = new WorkbookSettings();
                setEncode.setEncoding(UTF8_ENCODING);
                File file = new File(mContext.getFilesDir().getPath() + "/Export");
                makeDir(file);
                File saveFile = new File(file, fileName);
                if (!saveFile.exists()) {
                    saveFile.createNewFile();
                }

                in = new FileInputStream(saveFile);
                Workbook workbook = Workbook.getWorkbook(in);
                writebook = Workbook.createWorkbook(saveFile, workbook);
                WritableSheet sheet = writebook.getSheet(0);


                for (int j = 0; j < objList.size(); j++) {
                    ArrayList<String> list = (ArrayList<String>) objList.get(j);
                    for (int i = 0; i < list.size(); i++) {
                        sheet.addCell(new Label(i, j + 1, list.get(i), arial12format));
                        if (list.get(i).length() <= 5) {
                            //设置列宽
                            sheet.setColumnView(i, list.get(i).length() + 8);
                        } else {
                            //设置列宽
                            sheet.setColumnView(i, list.get(i).length() + 5);
                        }
                    }
                    //设置行高
                    sheet.setRowView(j + 1, 350);
                }

                writebook.write();
                Toast.makeText(c, "导出Excel成功", Toast.LENGTH_SHORT).show();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (writebook != null) {
                    try {
                        writebook.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

    public static void makeDir(File dir) {
        if (!dir.getParentFile().exists()) {
            makeDir(dir.getParentFile());
        }
        dir.mkdir();
    }

}
    1. 调用
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_zu_ke_login);
        initView();

        List recordList = new ArrayList();
        List row = new ArrayList(Arrays.asList("1","2", "3", "400.89", "5", "2022-12-01", "10:30", "800000"));
        recordList.add(row);
        recordList.add(row);
        recordList.add(row);
        recordList.add(row);
        recordList.add(row);

        String[] title = {"标识符", "用途", "类型", "金额", "支付方式", "日期", "时间", "备注"};
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
        long time = System.currentTimeMillis();
        String fileName = "消费记录_" + format.format(time) + ".xls";
        ExcelUtil.initExcel(fileName, "sheet1", title, this);
        ExcelUtil.writeObjListToExcel(recordList, fileName, this);
    }

9 sharePreference工具类

SPUtils.put(LoginActivity.this, Config.LOGIN_DATA, "张三");
String uid = (String) SPUtils.get(getContext(), Config.LOGIN_DATA, "");

package com.fri.hzapp.util;


import android.content.Context;
import android.content.SharedPreferences;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * sharePreference工具类
 */
public class SPUtils {
    /**
     * 保存在手机里面的文件名
     */
    public static final String FILE_NAME = "share_data";

    /**
     * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
     *
     * @param context
     * @param key
     * @param object
     */
    public static void put(Context context, String key, Object object) {

        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        if (object instanceof String) {
            editor.putString(key, (String) object);
        } else if (object instanceof Integer) {
            editor.putInt(key, (Integer) object);
        } else if (object instanceof Boolean) {
            editor.putBoolean(key, (Boolean) object);
        } else if (object instanceof Float) {
            editor.putFloat(key, (Float) object);
        } else if (object instanceof Long) {
            editor.putLong(key, (Long) object);
        } else {
            editor.putString(key, object.toString());
        }

        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
     *
     * @param context
     * @param key
     * @param defaultObject
     * @return
     */
    public static Object get(Context context, String key, Object defaultObject) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);

        if (defaultObject instanceof String) {
            return sp.getString(key, (String) defaultObject);
        } else if (defaultObject instanceof Integer) {
            return sp.getInt(key, (Integer) defaultObject);
        } else if (defaultObject instanceof Boolean) {
            return sp.getBoolean(key, (Boolean) defaultObject);
        } else if (defaultObject instanceof Float) {
            return sp.getFloat(key, (Float) defaultObject);
        } else if (defaultObject instanceof Long) {
            return sp.getLong(key, (Long) defaultObject);
        }

        return null;
    }

    /**
     * 移除某个key值已经对应的值
     *
     * @param context
     * @param key
     */
    public static void remove(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.remove(key);
        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 清除所有数据
     *
     * @param context
     */
    public static void clear(Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 查询某个key是否已经存在
     *
     * @param context
     * @param key
     * @return
     */
    public static boolean contains(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        return sp.contains(key);
    }

    /**
     * 返回所有的键值对
     *
     * @param context
     * @return
     */
    public static Map<String, ?> getAll(Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        return sp.getAll();
    }

    /**
     */
    private static class SharedPreferencesCompat {
        private static final Method sApplyMethod = findApplyMethod();

        /**
         * 反射查找apply的方法
         *
         * @return
         */
        @SuppressWarnings({"unchecked", "rawtypes"})
        private static Method findApplyMethod() {
            try {
                Class clz = SharedPreferences.Editor.class;
                return clz.getMethod("apply");
            } catch (NoSuchMethodException e) {
            }
            return null;
        }

        /**
         * 如果找到则使用apply执行,否则使用commit
         *
         * @param editor
         */
        public static void apply(SharedPreferences.Editor editor) {
            try {
                if (sApplyMethod != null) {
                    sApplyMethod.invoke(editor);
                    return;
                }
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
            } catch (InvocationTargetException e) {
            }
            editor.commit();
        }
    }



    /**
     * save json string of data list to share preference
     * @param tag
     * @param datalist
     */
    public static <T>  void setDataList(String tag, List<T> datalist,Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        if (null == datalist)
            return;

        Gson gson = new Gson();
        //change datalist to json
        String strJson = gson.toJson(datalist);
        editor.putString(tag, strJson);
        editor.commit();
    }

    /**
     * get data List from share preferences
     * @param tag share preferences data tag
     * @param cls target list element object class
     * @return list
     */
    public  static <T> List<T> getDataList(String tag, Class<T> cls,Context context) {
        List<T> datalist=new ArrayList<T>();
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        String strJson = sp.getString(tag, null);
        if (null == strJson) {
            return datalist;
        }
        try {
            Gson gson = new Gson();
            JsonArray array = new JsonParser().parse(strJson).getAsJsonArray();
            for (JsonElement jsonElement : array) {
                datalist.add(gson.fromJson(jsonElement, cls));
            }
        } catch (Exception e) {
        }
        return datalist;
    }
}

10 生成日志文件

application文件中:LogToFileUtils.init(this);
LogToFileUtils.write("zhiling---JSZL---item_TIP: 1");
写日志操作,查看路径:手机存储 》Android 》data 》包名 》 files 》 FriLog

package com.fri.hzapp.util;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Environment;
import android.text.format.Formatter;
import android.util.Log;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 将日志复制到文件工具类
 */

public class LogToFileUtils {
    /**
     * 上下文对象
     */
    private static Context mContext;
    /**
     * FileLogUtils类的实例
     */
    private static LogToFileUtils instance;
    /**
     * 用于保存日志的文件
     */
    private static File logFile;
    /**
     * 日志中的时间显示格式
     */
    private static SimpleDateFormat logSDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    /**
     * 日志的最大占用空间 - 单位:字节
     * <p>
     * 注意:为了性能,没有每次写入日志时判断,故日志在写入第二次初始化之前,不会受此变量限制,所以,请注意日志工具类的初始化时间
     * <p>
     * 为了衔接上文,日志超出设定大小后不会被直接删除,而是存储一个副本,所以实际占用空间是两份日志大小
     * <p>
     * 除了第一次超出大小后存为副本外,第二次及以后再次超出大小,则会覆盖副本文件,所以日志文件最多也只有两份
     * <p>
     * 默认10M
     */
    private static final int LOG_MAX_SIZE = 10 * 1024 * 1024;
    /**
     * 以调用者的类名作为TAG
     */
    private static String tag;

    private static final String MY_TAG = "LogToFileUtils";


    /**
     * 初始化日志库
     *
     * @param context
     */
    public static void init(Context context) {
        Log.i(MY_TAG, "init. ..");
        if (null == mContext || null == instance || null == logFile || !logFile.exists()) {
            mContext = context;
            instance = new LogToFileUtils();
            logFile = getLogFile();
            Log.i(MY_TAG, "LogFilePath is: " + logFile.getPath());
            // 获取当前日志文件大小
            long logFileSize = getFileSize(logFile);
            Log.d(MY_TAG, "Log max size is: " + Formatter.formatFileSize(context, LOG_MAX_SIZE));
            Log.i(MY_TAG, "log now size is: " + Formatter.formatFileSize(context, logFileSize));
            // 若日志文件超出了预设大小,则重置日志文件
            if (LOG_MAX_SIZE < logFileSize) {
                resetLogFile();
            }
        } else {
            Log.i(MY_TAG, "LogToFileUtils has been init ...");
        }
    }

    /**
     * 写入日志文件的数据
     *
     * @param str 需要写入的数据
     */
    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    public static void write(final Object str) {
        SharedPreferences sharedPreferences = mContext.getSharedPreferences("oldTime", Context.MODE_PRIVATE);
        try {
            String getoldtime = sharedPreferences.getString("oldtime", "");
            Log.e("LZ----取出来来的时间getoldtime", getoldtime);
            if (!getoldtime.isEmpty() || !getoldtime.equals("") || getoldtime != null) {
                //转换开始时间对比
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                Date startdate = null;

                try {
                    startdate = sdf.parse(getoldtime);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                if (getGapCount(startdate, TimeUtil.currentTime()) > 1) {//判断是否超过七天,如果超过则删除文件
                    Log.e("FRi----", "判断是是否超过七天");
                    File ff = getLogFile();
                    if ((!ff.exists()) || (!ff.isDirectory())) {
                        ff.delete();
                        SharedPreferences.Editor editor = sharedPreferences.edit();
                        editor.putString("oldtime", TimeUtil.getoldTime());
                        Log.e("FRI----oldtime", TimeUtil.getoldTime());
                        editor.commit();//提交修改
                    }

                } else {
                    // 判断是否初始化或者初始化是否成功
                    if (null == mContext || null == instance || null == logFile || !logFile.exists()) {
                        Log.e(MY_TAG, "Initialization failure !!!");
                        return;
                    }
                    String logStr = getFunctionInfo() + " - " + str.toString();
                    Log.i(tag, logStr);

                    try {
                        BufferedWriter bw = new BufferedWriter(new FileWriter(logFile, true));
                        bw.write(logStr);
                        bw.write("UTF-8");
                        bw.write("\r\n");
                        bw.flush();
                    } catch (Exception e) {
                        Log.e(tag, "Write failure !!! " + e.toString());
                    }
                }
            } else {
                SharedPreferences.Editor editor = sharedPreferences.edit();//获取编辑器
                editor.putString("oldtime", TimeUtil.getoldTime());
                Log.e("FRI---oldtime", TimeUtil.getoldTime());
                editor.commit();//提交修改

            }
        } catch (Exception e) {
            SharedPreferences.Editor editor = sharedPreferences.edit();//获取编辑器
            editor.putString("oldtime", TimeUtil.getoldTime());
            editor.commit();//提交修改
        }
    }


    /**
     * 重置日志文件
     * <p>
     * 若日志文件超过一定大小,则把日志改名为lastLog.txt,然后新日志继续写入日志文件
     * <p>
     * 每次仅保存一个上一份日志,日志文件最多有两份
     * <p/>
     */
    private static void resetLogFile() {
        Log.i(MY_TAG, "Reset Log File ... ");
        // 创建lastLog.txt,若存在则删除
        File lastLogFile = new File(logFile.getParent() + "/lastLog.txt");
        if (lastLogFile.exists()) {
            lastLogFile.delete();
        }
        // 将日志文件重命名为 lastLog.txt
        logFile.renameTo(lastLogFile);
        // 新建日志文件
        try {
            logFile.createNewFile();
        } catch (Exception e) {
            Log.e(MY_TAG, "Create log file failure !!! " + e.toString());
        }
    }

    /**
     * 获取文件大小
     *
     * @param file 文件
     * @return
     */
    private static long getFileSize(File file) {
        long size = 0;
        if (file.exists()) {
            try {
                FileInputStream fis = new FileInputStream(file);
                size = fis.available();
            } catch (Exception e) {
                Log.e(MY_TAG, e.toString());
            }
        }
        return size;
    }

    /**
     * 获取APP日志文件
     *
     * @return APP日志文件
     */
    public static File getLogFile() {
        File file;
        // 判断是否有SD卡或者外部存储器
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            // 有SD卡则使用SD - PS:没SD卡但是有外部存储器,会使用外部存储器
            // SD\Android\data\包名\files\Log\logs.txt
            file = new File(mContext.getExternalFilesDir("FriLog").getPath() + "/");
        } else {
            // 没有SD卡或者外部存储器,使用内部存储器
            // \data\data\包名\files\Log\logs.txt
            file = new File(mContext.getFilesDir().getPath() + "/FriLog/");
        }
        // 若目录不存在则创建目录
        if (!file.exists()) {
            file.mkdir();
        }
        File logFile = new File(file.getPath() + "/fri_logs.txt");
        if (!logFile.exists()) {
            try {
                logFile.createNewFile();
            } catch (Exception e) {
                Log.e("ic_launcher_foreground", "Create log file failure !!! " + e.toString());
            }
        }
        return logFile;
    }


    /**
     *     * 获取两个日期之间的间隔天数
     *     * @return
     *     
     */


    public static int getGapCount(Date startDate, Date endDate) {
        Calendar fromCalendar = Calendar.getInstance();
        fromCalendar.setTime(startDate);
        fromCalendar.set(Calendar.HOUR_OF_DAY, 0);
        fromCalendar.set(Calendar.MINUTE, 0);
        fromCalendar.set(Calendar.SECOND, 0);
        fromCalendar.set(Calendar.MILLISECOND, 0);

        Calendar toCalendar = Calendar.getInstance();
        toCalendar.setTime(endDate);
        toCalendar.set(Calendar.HOUR_OF_DAY, 0);
        toCalendar.set(Calendar.MINUTE, 0);
        toCalendar.set(Calendar.SECOND, 0);
        toCalendar.set(Calendar.MILLISECOND, 0);

        return (int) (toCalendar.getTime().getTime() - fromCalendar.getTime().getTime()) / (1000 * 60 * 60 * 24);

    }


    /**
     * 获取当前函数的信息
     *
     * @return 当前函数的信息
     */
    private static String getFunctionInfo() {
        StackTraceElement[] sts = Thread.currentThread().getStackTrace();
        if (sts == null) {
            return null;
        }
        for (StackTraceElement st : sts) {
            if (st.isNativeMethod()) {
                continue;
            }
            if (st.getClassName().equals(Thread.class.getName())) {
                continue;
            }
            if (st.getClassName().equals(instance.getClass().getName())) {
                continue;
            }
            tag = st.getFileName();
            return "[" + logSDF.format(new Date()) + " " + st.getClassName() + " " + st
                    .getMethodName() + " Line:" + st.getLineNumber() + "]";
        }
        return null;
    }

    /**
     * 两个时间相差多少天
     */
    public long dateDiff(String startTime, String endTime, String format) {
        // 按照传入的格式生成一个simpledateformate对象
        SimpleDateFormat sd = new SimpleDateFormat(format);
        long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数
        long nh = 1000 * 60 * 60;// 一小时的毫秒数
        long nm = 1000 * 60;// 一分钟的毫秒数
        long ns = 1000;// 一秒钟的毫秒数
        long diff;
        long day = 0;
        try {
            // 获得两个时间的毫秒时间差异
            diff = sd.parse(endTime).getTime()
                    - sd.parse(startTime).getTime();
            day = diff / nd;// 计算差多少天
            long hour = diff % nd / nh;// 计算差多少小时
            long min = diff % nd % nh / nm;// 计算差多少分钟
            long sec = diff % nd % nh % nm / ns;// 计算差多少秒
            // 输出结果
            System.out.println("时间相差:" + day + "天" + hour + "小时" + min
                    + "分钟" + sec + "秒。");
            if (day >= 1) {
                return day;
            } else {
                if (day == 0) {
                    return 1;
                } else {
                    return 0;
                }

            }

        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;

    }
    
}

11 okhttp

11.1 配置环境

    1. 加入依赖
      compile 'com.squareup.okhttp3:okhttp:3.6.0'
      implementation 'com.google.code.gson:gson:2.8.2
    1. res下新建xml文件夹,在其中新建network_security_config.xml,其内容如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>
    1. 在AndroidManifest.xml中application标签下添加:
      android:networkSecurityConfig="@xml/network_security_config"
      注意添加网络请求权限:
      <uses-permission android:name="android.permission.INTERNET" />

11.2 方法一,原生使用

11.2.1 Activity.java

// 按钮触发
private void sendByOKHttp() {
    System.out.println("-------------------------OKHttp");
    new Thread(new Runnable() {
        @Override
        public void run() {
            OkHttpClient client = new OkHttpClient();
            JSONObject jsonObject = new JSONObject();
            try {
                jsonObject.put("okhttp","success");
                jsonObject.put("msg", 123);
                int[] ss = {1,2,3,4};
                jsonObject.put("hhh", ss);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            
            String json = new Gson().toJson(jsonObject);
            String url = "http://192.168.42.228:8080/test";
            RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
            final Request request = new Request.Builder().url(url).post(requestBody).build();
            try {
                Response response = client.newCall(request).execute();//发送请求
                String result = response.body().string();
                System.out.println(result);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

11.2.2 Controller.java

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.70</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.1</version>
</dependency>
@RequestMapping(value = "/test", method = RequestMethod.POST)
@ResponseBody
public JSONObject g( @RequestBody String  json123){
    System.out.println(json123);
    JSONObject jsonObject = JSON.parseObject(json123);
    JSONObject data = (JSONObject) jsonObject.get("nameValuePairs");
    JSONArray aa = (JSONArray) data.get("hhh");
    System.out.println(aa);
    jsonObject.put("name", "lzh-ok");
    return jsonObject;
}
// json123,参数名不必一致

11.2.3 Springboot 配置log4j

    1. 引包
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.9</version>
</dependency>
    1. 新建log4j.properties
# LOG4J配置
log4j.rootCategory=INFO,stdout,file
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n

# 日志输出到文件
#log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
#log4j.appender.file.file=${project.basedir}/log/springboot.log
#log4j.appender.file.DatePattern='.'yyyy-MM-dd
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n
    1. 新建一个引入log4j的工具类

@ComponentScan
@ConfigurationProperties(“classpath:log4j.properties”)
public class Log4jConfigure {
}

    1. log4j的使用

声明:
private static Logger logger = Logger.getLogger(AndroidApplication.class);
使用:
logger.info(“spring boot App is starting…”);

11.3 方法二,OkhttpUtil

直接将OkhttpUtil、NetCallBack复制即可
OkhttpUtil:Android http请求工具包
NetCallBack:回调接口

package com.example.testproject.util;

import android.content.Context;
import android.os.Environment;
import android.util.Log;


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 网络请求
 */
public class OkhttpUtil {
    private static OkhttpUtil mInstance;
    private OkHttpClient mOkHttpClient;
    private OnDownloadListener listener;
    public static final MediaType JSON
            = MediaType.parse("application/json; charset=utf-8");
    private String saveDir = "";

    /**
     * 单例加静态对象
     */
    public static OkhttpUtil getInstance() {
        if (mInstance == null) {
            synchronized (OkhttpUtil.class) {
                if (mInstance == null) {
                    mInstance = new OkhttpUtil();
                }
            }
        }
        return mInstance;
    }


    /**
     * OkHttp的一些参数配置
     */
    private OkhttpUtil() {
        mOkHttpClient = new OkHttpClient.Builder()
                .readTimeout(30, TimeUnit.SECONDS)
                .connectTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
//                .sslSocketFactory(TrustAllCerts.createSSLSocketFactory())
//                .hostnameVerifier(new TrustAllCerts.TrustAllHostnameVerifier())
                .retryOnConnectionFailure(true)
                .build();
    }



    /**
     * get异步请求
     */
    public void asynGet(String url, Map<String, String> BodyParams) {
        Request request = new Request.Builder()
                .url(url + setUrlParams(BodyParams))
                .build();
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //ToastUtil.showShortToast(DxhdLoginActivity.this,"网络请求失败!!!");
                Log.e("fri", "访问服务失败!");
            }

            @Override
            public void onResponse(Call call, Response response) {
                try {
                    //okhttp默认是utf-8编码,如果页面没设定utf-8格式,会乱码,这里手动设定为gbk即可
                    if (response.isSuccessful()) {
                       /* byte[] responseBytes = response.body().bytes();
                        handler.obtainMessage(1, new String(responseBytes, "utf-8")).sendToTarget();*/
                        String content = response.body().string();
                        Log.e("fri", content);
                    } else {
                        Log.e("fri", "服务器错误!");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }


    /**
     * post请求json
     */
    public void postJson(Context context, String url, String json, final NetCallBack callBack) {
        String access_token = (String) SPUtils.get(context, "ACCESS_TOKEN", "");
        RequestBody requestBody = RequestBody.create(JSON, json);
        final Request request = new Request.Builder().url(url).post(requestBody).addHeader("Authorization", access_token).build();
//        LogToFileUtils.write("url:"+url+" \njson:"+json);
        Log.e("","url:"+url+" \njson:"+json);
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callBack.onError(e.getMessage());
                Log.e("","e.getMessage():"+e.getMessage());
//                LogToFileUtils.write("e.getMessage():"+e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {
                    callBack.onSuccess(response.body().string());
//                    LogToFileUtils.write("response.body().string():"+response.body().string());
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        });
    }

    /**
     * 上传文件
     *
     * @param url
     * @param filePath
     * @param callBack
     */
    public void upload(Context context, String url, String filePath, final NetCallBack callBack) {
        String access_token = (String) SPUtils.get(context, "ACCESS_TOKEN", "");

        String fileName = filePath.split("/")[filePath.split("/").length - 1];
        try {
            fileName = URLEncoder.encode(fileName, "UTF-8");//App传递给后台时候编码
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        Log.e("fri-upload-FileName: ", fileName);
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("yyid", "A00111010810000002901")
                .addFormDataPart("scrsfzh", "130526199502025218")
                .addFormDataPart("scrxm", "海淀刑侦暴龙 ")
                .addFormDataPart("scrjg", "海淀分局")
                .addFormDataPart("files", fileName,
                        RequestBody.create(MediaType.parse("multipart/form-data"), new File(filePath)))

                .build();
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .addHeader("Authorization", access_token)
                .build();

        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callBack.onError(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) {
                try {
                    callBack.onSuccess(response.body().string());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

    }

    /**
     * 异步下载文件并保存
     */
    public void download(Context context, String type, final String url, final String file_name, final OnDownloadListener listener) {
        if ("img".equals(type)) {
            saveDir = context.getExternalFilesDir("FriImageCache").getPath() + "/";
        } else if ("audio".equals(type)) {
            saveDir = context.getExternalFilesDir("FriAudioCache").getPath() + "/";
        } else if ("video".equals(type)) {
            saveDir = context.getExternalFilesDir("FriVideoCache").getPath() + "/";
        } else if ("file".equals(type)) {
            saveDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Download";
        } else if ("apk".equals(type)) {
            saveDir = context.getExternalFilesDir("FriApk").getPath() + "/";
        }
//        LogToFileUtils.write("下载链接" + url);
        String access_token = (String) SPUtils.get(context, "ACCESS_TOKEN", "");

        this.listener = listener;
//        Request request = new Request.Builder().url(Config.API_DOWNLOAD_URL + "?fileUrl=" + url + "&fileName=" + file_name).addHeader("Authorization", access_token)
//                .build();
        Request request = new Request.Builder().url(url).addHeader("Authorization", access_token)
                .build();
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                listener.onDownloadFailed();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
//                LogToFileUtils.write("下载成功" + response.body().contentLength());
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len;
                FileOutputStream fos = null;
                //储存下载文件的目录
                String savePath = isExistDir(saveDir);
                try {
                    is = response.body().byteStream();
                    long total = response.body().contentLength();
                    File file = new File(savePath, file_name);

                    fos = new FileOutputStream(file);
                    long sum = 0;
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                        sum += len;
                        int progress = (int) (sum * 1.0f / total * 100);
                        listener.onDownloading(progress);
                        //下载中
                    }
                    fos.flush();
                    listener.onDownloadSuccess(file.getPath());
                    //下载完成
                    Log.e("fri", "download finish");
                } catch (Exception e) {
//                    LogToFileUtils.write("下载异常" + e.getMessage());
                } finally {
                    try {
                        if (is != null)
                            is.close();
                    } catch (IOException e) {

                    }
                    try {
                        if (fos != null) {
                            fos.close();
                        }
                    } catch (IOException e) {
//                        LogToFileUtils.write("下载失败" + e.getMessage());

                    }
                }
            }
        });
    }


    /**
     * Post上传文件的参数
     */
    private RequestBody SetFileRequestBody(Map<String, String> BodyParams, Map<String, String> fileParams) {
        //带文件的Post参数
        RequestBody body;
        MultipartBody.Builder MultipartBodyBuilder = new MultipartBody.Builder();
        MultipartBodyBuilder.setType(MultipartBody.FORM);
        RequestBody fileBody;
        if (BodyParams != null) {
            Iterator<String> iterator = BodyParams.keySet().iterator();
            String key;
            while (iterator.hasNext()) {
                key = iterator.next();
                MultipartBodyBuilder.addFormDataPart(key, BodyParams.get(key));
                Log.d("post http", "post_Params===" + key + "====" + BodyParams.get(key));
            }
        }

        if (fileParams != null) {
            Iterator<String> iterator = fileParams.keySet().iterator();
            String key;
            int i = 0;
            while (iterator.hasNext()) {
                key = iterator.next();
                i++;
                MultipartBodyBuilder.addFormDataPart(key, fileParams.get(key));
                Log.d("post http", "post_Params===" + key + "====" + fileParams.get(key));
                fileBody = RequestBody.create(MediaType.parse("image/png"), new File(fileParams.get(key)));
                MultipartBodyBuilder.addFormDataPart(key, i + ".png", fileBody);
            }
        }
        body = MultipartBodyBuilder.build();
        return body;
    }

    /**
     * get方法连接拼加参数
     */
    private String setUrlParams(Map<String, String> mapParams) {
        String strParams = "";
        if (mapParams != null) {
            Iterator<String> iterator = mapParams.keySet().iterator();
            String key;
            while (iterator.hasNext()) {
                key = iterator.next();
                strParams += "&" + key + "=" + mapParams.get(key);
            }
        }

        return strParams;
    }

    /**
     * 判断文件下载目录是否存在
     */
    private String isExistDir(String saveDir) throws IOException {
        File downloadFile = new File(saveDir);
        if (!downloadFile.mkdirs()) {
            downloadFile.createNewFile();
        }
        String savePath = downloadFile.getAbsolutePath();
        return savePath;
    }

    /**
     * 从路径获取文件名
     */
    public String getNameFromUrl(String url) {
        return url.substring(url.lastIndexOf("/") + 1);
    }

    /**
     * 下载进度监听
     */
    public interface OnDownloadListener {
        /**
         * 下载成功
         */
        void onDownloadSuccess(String path);

        /**
         * 下载进度
         *
         * @param progress
         */
        void onDownloading(int progress);

        /**
         * 下载失败
         */
        void onDownloadFailed();
    }
}
package com.example.testproject.util;

/**
 * 网络请求回调
 */
public interface NetCallBack {
    /**
     * 数据请求成功
     * @param data 请求到的数据
     */
    void onSuccess(String data);
    /**
     *  使用网络API接口请求方式时,虽然已经请求成功但是由
     *  于{@code msg}的原因无法正常返回数据。
     */
    void onFailure(String msg);
    /**
     * 请求数据失败,指在请求网络API接口请求方式时,出现无法联网、
     * 缺少权限,内存泄露等原因导致无法连接到请求数据源。
     */
    void onError(String msg);
    /**
     * 当请求数据结束时,无论请求结果是成功,失败或是抛出异常都会执行此方法给用户做处理,通常做网络
     * 请求时可以在此处隐藏“正在加载”的等待控件
     */
    void onComplete();
}

11.3.1 http请求

Android:

Button buttonTestHttp = getActivity().findViewById(R.id.mapHttp);
buttonTestHttp.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        System.err.println("testBtn in Frament");
        JsonObject jsonObject = new JsonObject();
        try {
            jsonObject.addProperty("name", "lzh");
        } catch (JsonIOException jsonException) {
            jsonException.printStackTrace();
        }catch (JsonParseException jsonException){
            jsonException.printStackTrace();
        }
        String value = jsonObject.toString();
        OkhttpUtil.getInstance().postJson(getContext(),/*ipv4地址*/ "http://192.168.1.19:8080/test", value, new NetCallBack() {

            @Override
            public void onSuccess(String data) {
                Log.e("data:---", data);
            }

            @Override
            public void onFailure(String msg) {
                Log.e("Failure: " , msg);
            }

            @Override
            public void onError(String msg) {
                Log.e("Error: " , msg);
            }

            @Override
            public void onComplete() {
                Log.e("Complete", "");
            }
        });
    }
});

SpringBoot:

@RequestMapping(value = "/test", method = RequestMethod.POST)
@ResponseBody
public JSONObject g(@RequestBody String json) throws ParseException {
    JSONObject jsonObject = JSONObject.parseObject(json); 
    logger.info(data.get("arr"));
    jsonObject.put("hahaha", "qwsd221阿斯顿");
    return jsonObject;
}

String result = HttpUtil.post(queryLayerInfoUrl, paramMap);
JSONObject jsonObject = JSON.parseArray(result).getJSONObject(0);

11.3.2 上传文件

OkhttpUtil.getInstance().upload(this, Config.API_UPLOAD_URL, file_real_path, new NetCallBack() {
        @Override
        public void onSuccess(String data) {
            LogToFileUtils.write("上传返回" + data);
            JSONObject obj = null;
            try {
                obj = new JSONObject(data).getJSONObject("data");
                String path = obj.getString("content");
                String file_name = path.split("/")[path.split("/").length - 1];
                file_name = URLDecoder.decode(file_name, "UTF-8");
                Log.e("fri", path);
                runOnUiThread(() -> showLoadingDialog("文件发送中"));
                sendFile("audio", path, file_name, file_real_path, (int) (recordTime * 1000));
            } catch (Exception e) {
                LogToFileUtils.write("上传返回" + e.getMessage());
            }
        }
    });
});

在sendFile方法中,实现数据库操作,记录文件保存位置

11.3.3 下载文件

OkhttpUtil.getInstance().download(context, "img", download_url, file_name, new OkhttpUtil.OnDownloadListener() {
    @Override
    public void onDownloadSuccess(final String path) {
        context.runOnUiThread(() -> {
        });
    }

    @Override
    public void onDownloading(int progress) {
    }

    @Override
    public void onDownloadFailed() {
        context.runOnUiThread(() -> {
            BottomToast.show(context, "图片下载失败");
        });
    }
});

12 activity动态修改xml

    1. 在layout下新建一个xml,这就是要不断增加的自定义组件
<?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="match_parent">

    <LinearLayout
        android:id="@+id/son"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="姓名:"
            android:textSize="30dp"/>
        <EditText
            android:id="@+id/name"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:hint="name"
            android:textSize="30dp"/>
        <Button
            android:id="@+id/btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="btn"
            android:textSize="30dp"/>
    </LinearLayout>

</RelativeLayout>
    1. 增加自定义组件的容器activity_diy.xml
      ScrollView:当容器中内容大于屏幕高度时,自动出现的滚动条
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fadingEdge="vertical"
    android:scrollbars="vertical">

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/all"
    tools:context=".DIYActivity">

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

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="add"
            android:textSize="30dp"
            android:onClick="add"/>
        <LinearLayout
            android:layout_width="10dp"
            android:layout_height="match_parent"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="sub"
            android:textSize="30dp"
            android:onClick="sub"/>
    </LinearLayout>
</LinearLayout>
</ScrollView>
    1. DIYActivity.java
    public void add(View v){
        LayoutInflater inflater = getLayoutInflater();
        View view = inflater.inflate(R.layout.diy, null);
        //为diy linearlayout中的button添加点击事件
        Button btn = view.findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                System.out.println("btn---" + view.getId());
            }
        });
        //为diy RelativeLayout添加点击事件
        view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(event.getAction() == MotionEvent.ACTION_DOWN){
                    System.out.println(v.getId());
                    RelativeLayout l = (RelativeLayout) v;
                    EditText editText = l.findViewById(R.id.name);
                    editText.setText("hhhh----");
                    v.setVisibility(View.GONE);
                }
                return false;
            }
        });
        LinearLayout con = findViewById(R.id.all);
        // con.removeAllViews();
        int count = con.getChildCount();
        //修改linearLayout的id
        view.setId(count+1);
        //修改linearLayout中编辑框的值
        EditText editText = view.findViewById(R.id.name);
        editText.setText("name-" + count);
        //向容器中添加linearLayout
        con.addView(view);
        System.out.println(count);
    }
    public void sub(View v){
        LinearLayout con = findViewById(R.id.all);
        int count = con.getChildCount();
        System.out.println(count);
        for(int i = 1; i < count; i++){
            RelativeLayout l = (RelativeLayout) con.getChildAt(i);
            System.out.println(l.getId());
        }
    }

13 Dialog 弹出框

Dialog继承Object,异步调用,不会阻塞UI线程。以下是对他的整体框架:
在这里插入图片描述
AlertDialog用法:
(1)setTitle :为对话框设置标题
(2)setIcon :为对话框设置图标
(3)setMessage:为对话框设置内容
(4)setView : 给对话框设置自定义样式
(5)setItems :设置对话框要显示的一个list,一般用于显示几个命令时
(6)setMultiChoiceItems :用来设置对话框显示一系列的复选框
(7)setSingleChoiceItems :用来设置对话框显示一系列的单选框
(8)setNeutralButton :普通按钮
(9)setPositiveButton :给对话框添加"Yes"按钮
(10)setNegativeButton :对话框添加"No"按钮
(11)create : 创建对话框
(12)show :显示对话框

13.1 只显示标题和内容

AlertDialog alertDialog1 = new AlertDialog.Builder(that)
                            .setTitle("这是标题")//标题
                            .setMessage("这是内容")//内容
                            .setIcon(R.mipmap.ic_launcher)//图标
                            .create();
                    alertDialog1.show();

13.2 有多个按钮:确定、取消、普通按钮

AlertDialog alertDialog2 = new AlertDialog.Builder(DIYActivity.this)
        .setTitle("这是标题")
        .setMessage("有多个按钮")
        .setIcon(R.mipmap.ic_launcher)
        .setPositiveButton("确定", new DialogInterface.OnClickListener() {//添加"Yes"按钮
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Toast.makeText(DIYActivity.this, "这是确定按钮", Toast.LENGTH_SHORT).show();
            }
        })

        .setNegativeButton("取消", new DialogInterface.OnClickListener() {//添加取消
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Toast.makeText(DIYActivity.this, "这是取消按钮", Toast.LENGTH_SHORT).show();
            }
        })
        .setNeutralButton("普通按钮", new DialogInterface.OnClickListener() {//添加普通按钮
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Toast.makeText(DIYActivity.this, "这是普通按钮按钮", Toast.LENGTH_SHORT).show();
            }
        })
        .create();
alertDialog2.show();

底部文本弹框:
Toast.makeText(DIYActivity.this, “这是确定按钮”, Toast.LENGTH_SHORT).show();

13.3 显示列表,多命令选择其一

final String[] items3 = new String[]{"---1---","---2---","---3---","---4---"};//创建item
AlertDialog alertDialog3 = new AlertDialog.Builder(DIYActivity.this)
        .setTitle("选择您喜欢的")
        .setIcon(R.mipmap.ic_launcher)
        .setItems(items3, new DialogInterface.OnClickListener() {//添加列表
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Toast.makeText(DIYActivity.this, "点的是:" + items3[i], Toast.LENGTH_SHORT).show();
            }
        })
        .create();
alertDialog3.show();

13.4 弹出单选框

final String[] items4 = new String[]{"---1---","---2---","---3---","---4---"};//创建item
AlertDialog alertDialog4 = new AlertDialog.Builder(DIYActivity.this)
        .setTitle("选择您喜欢的")
        .setIcon(R.mipmap.ic_launcher)
        .setSingleChoiceItems(items4, 0, new DialogInterface.OnClickListener() {//添加单选框
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                index = i;
            }
        })
        .setPositiveButton("确定", new DialogInterface.OnClickListener() {//添加"Yes"按钮
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Toast.makeText(DIYActivity.this, "这是确定按钮" + "点的是:" + items4[index], Toast.LENGTH_SHORT).show();
            }
        })
        .setNegativeButton("取消", new DialogInterface.OnClickListener() {//添加取消
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Toast.makeText(DIYActivity.this, "这是取消按钮", Toast.LENGTH_SHORT).show();
            }
        })
        .create();
alertDialog4.show();

13.5 弹出复选框

final String[] items5 = new String[]{"---1---","---2---","---3---","---4---"};//创建item
final boolean[] booleans = {true, true, false, false};
AlertDialog alertDialog5 = new AlertDialog.Builder(this)
        .setTitle("选择您喜欢的")
        .setIcon(R.mipmap.ic_launcher)
        .setMultiChoiceItems(items5, booleans, new DialogInterface.OnMultiChoiceClickListener() {//创建多选框
            @Override
            public void onClick(DialogInterface dialogInterface, int i, boolean b) {
                booleans[i] = b;
            }
        })
        .setPositiveButton("确定", new DialogInterface.OnClickListener() {//添加"Yes"按钮
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                StringBuilder stringBuilder = new StringBuilder();
                for (int a = 0; a < booleans.length; a++) {
                    if (booleans[a]) {
                        stringBuilder.append(items5[a] + " ");
                    }
                }
                Toast.makeText(AlertDialogActivity.this, "这是确定按钮" + "点的是:" + stringBuilder.toString(), Toast.LENGTH_SHORT).show();
            }
        })

        .setNegativeButton("取消", new DialogInterface.OnClickListener() {//添加取消
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Toast.makeText(AlertDialogActivity.this, "这是取消按钮", Toast.LENGTH_SHORT).show();
            }
        })
        .create();
alertDialog5.show();

13.6 弹出自定义View框

final AlertDialog.Builder alertDialog7 = new AlertDialog.Builder(DIYActivity.this);
View view1 = View.inflate(DIYActivity.this, R.layout.diy, null);
final EditText et = view1.findViewById(R.id.name);
Button bu = view1.findViewById(R.id.btn);
alertDialog7
        .setTitle("Login")
        .setIcon(R.mipmap.ic_launcher)
        .setView(view1)
        .create();
final AlertDialog show = alertDialog7.show();
bu.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Toast.makeText(DIYActivity.this, "电话" + et.getText().toString(), Toast.LENGTH_SHORT).show();
        show.dismiss();
    }
});

diy为在layout下自定义view的xml文件
带滚动条的自定义布局:

<?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="wrap_content"
    android:padding="10px"
    android:orientation="vertical">

    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="400sp"
        android:fadingEdge="vertical"
        android:scrollbars="vertical"
        android:id="@+id/zlp_scroll"
        android:background="@color/colorPrimaryDark">
        <LinearLayout
            android:id="@+id/zlp_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimaryDark"
            android:orientation="vertical">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="ZLP Dialog"
                android:textColor="#fff"
                android:textSize="50dp"/>
        </LinearLayout>
    </ScrollView>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimaryDark"
        android:layout_below="@+id/zlp_scroll"
        android:paddingTop="20px"
        android:gravity="right"
        android:orientation="horizontal">
        <Button
            android:id="@+id/zlp_ok"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="好的"
            android:textStyle="bold"
            android:textSize="18sp"/>
    </LinearLayout>
</RelativeLayout>

14 导航栏

    1. activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"> 纵向布局

    <LinearLayout 类似于div
        android:id="@+id/top"
        android:layout_width="match_parent" 适应父级
        android:layout_height="wrap_content" 适应内容
        android:orientation="horizontal" 横向布局
        android:gravity="center" 内容居中
        android:layout_alignParentTop="true" 置顶
        tools:ignore="MissingConstraints">

        <Button
            android:id="@+id/btntest"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="2dp"
            android:layout_marginRight="2dp"
            android:text="确定"/>

    </LinearLayout>

    <LinearLayout
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="center"
        android:layout_below="@+id/top"置于top之下
        android:layout_marginTop="50dp"
        tools:ignore="MissingConstraints"
        android:visibility="visible"> 可见,gone不可见
        <TextView
            android:id="@+id/tv_hello"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.498"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.334" />

    </LinearLayout>

    <androidx.viewpager.widget.ViewPager 用于放置fragment
        android:id="@+id/sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        android:minHeight="200dp"
        android:layout_below="@+id/btn" 置于btn之下
        android:layout_above="@+id/bottom" 置于bottom之上
        android:layout_marginTop="50dp" />

    <com.google.android.material.tabs.TabLayout 用于放置导航栏
        android:id="@+id/bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        android:layout_alignParentBottom="true" 置底
android:background="#1F1"
        android:layout_marginTop="25dp">
    </com.google.android.material.tabs.TabLayout>

</RelativeLayout>
    1. MainActivity.java

导航栏适配、button监听器、图标使用

public class MainActivity extends AppCompatActivity {

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

    private fragment_NewPage np = new fragment_NewPage();//导航1
    private fragment_NewPage2 np2 = new fragment_NewPage2();//导航2
    private fragment_NewPage3 np3 = new fragment_NewPage3();//导航3
    private fragment_newpage4 np4 = new fragment_newpage4();//导航4
    private ArrayList fragments = new ArrayList();
    private TabLayout tabLayout;//导航栏
    private ViewPager viewPager;//存放fragment
    private FragmentPagerAdapter adapter;
    private String[] strings ={"主页","人员审核","信息","我"}; //导航栏文字

    @SuppressLint("WrongViewCast")
    private void initView() {
        tabLayout = findViewById(R.id.bottom);
        fragments.add(np);
        fragments.add(np2);
        fragments.add(np3);
        fragments.add(np4);
        viewPager = findViewById(R.id.sp);
        adapter = new TitleFragmentPagerAdapter(getSupportFragmentManager(), fragments, strings);
        viewPager.setAdapter(adapter);
        tabLayout.setupWithViewPager(viewPager);
        onTabItemSelected();
    }

    private void onTabItemSelected() {
        for (int i =0;i<tabLayout.getTabCount();i++) {
            TabLayout.Tab tab = tabLayout.getTabAt(i);
            Drawable drawable = null;
            switch (i){
                case 0:
                    Log.e("fragment 1", "selected");
                    drawable = getResources().getDrawable(android.R.drawable.ic_menu_compass);
                    break;
                case 1:
                    Log.e("fragment 2", "selected");
                    drawable = getResources().getDrawable(android.R.drawable.ic_menu_view);
                    break;
                case 2:
                    Log.e("fragment 3", "selected");
                    drawable = getResources().getDrawable(android.R.drawable.sym_action_chat);
                    break;
                case 3:
                    Log.e("fragment 4", "selected");
                    drawable = getResources().getDrawable(android.R.drawable.ic_menu_myplaces);
                    break;
            }
            tab.setIcon(drawable);
        }
    }

    private class TitleFragmentPagerAdapter extends FragmentPagerAdapter {
        private List mFragmentList = null;
        private String[] titles;
        public TitleFragmentPagerAdapter(FragmentManager mFragmentManager,
                                         List<Fragment> fragmentList) {
            super(mFragmentManager);
            mFragmentList = fragmentList;
        }

        public TitleFragmentPagerAdapter(FragmentManager mFragmentManager,
                                         List<Fragment> fragmentList, String[] titles) {
            super(mFragmentManager);
            mFragmentList = fragmentList;
            this.titles = titles;
        }

        @Override
        public int getCount() {
            return mFragmentList.size();
        }

        @Override
        public Fragment getItem(int position) {
            Fragment fragment = null;
            if (position < mFragmentList.size()) {
                fragment = (Fragment) mFragmentList.get(position);
            } else {
                fragment = (Fragment) mFragmentList.get(0);
            }
            return fragment;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            if (titles != null && titles.length > 0)
                return titles[position];
            return null;
        }
    }

    public void testBtn() {
        Button btn = findViewById(R.id.btntest);
        btn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                TextView tv = findViewById(R.id.tv_hello);
                tv.setText("(-^-LZH-^-)");
            }
        });
    }
}

图标库使用:
java使用示例:
Drawable drawable = getResources().getDrawable(android.R.drawable.ic_dialog_email);
android使用示例:
android:icon="@android:drawable/bottom_bar"
图标查看:https://www.bbsmax.com/A/Vx5MYXR75N/

    1. Fragment.java -> button添加监听器
      (1)重写onActivityCreated,Fragment中的button监听必须在onActivityCreated中
      在这里插入图片描述
      (2)添加监听器
      在这里插入图片描述

15 mSwipeRefreshLayout+ScrollView下拉刷新、触底加载

(1)layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ShanglaRefesh">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:id="@+id/title">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="50dp"
            android:text="TITLE"
            android:gravity="center"
            android:textStyle="bold"/>
    </LinearLayout>
    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swiperefreshlayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/title"
        android:layout_above="@+id/progress">
        <!-- 新闻列表展示-->
        <!--        <androidx.recyclerview.widget.RecyclerView-->
        <!--            android:id="@+id/recyclerView"-->
        <!--            android:layout_width="match_parent"-->
        <!--            android:layout_height="match_parent" />-->
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/scroll">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:id="@+id/recyclerView"/>
        </ScrollView>
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    <ProgressBar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/progress"
        android:layout_above="@+id/bottom"
        android:visibility="gone"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:id="@+id/bottom"
        android:layout_alignParentBottom="true">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="50dp"
            android:id="@+id/btn"
            android:text="BOTTOM"
            android:gravity="center"
            android:textStyle="bold"/>
    </LinearLayout>

</RelativeLayout>

(2)activity

private boolean fadou = true;

LinearLayout recyclerView = findViewById(R.id.recyclerView);
SwipeRefreshLayout mSwipeRefreshLayout = findViewById(R.id.swiperefreshlayout);
mSwipeRefreshLayout.setColorSchemeColors(Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN);
//进入即加载
runOnUiThread(() -> {
    mSwipeRefreshLayout.setRefreshing(true);
    for(int i = 0; i < 3; i++) {
        TextView textView = new TextView(getApplicationContext());
        textView.setTextSize(100);
        textView.setText(i + " " + i);
        recyclerView.addView(textView);
        new Handler().postDelayed(new Runnable() {
            public void run() {
                mSwipeRefreshLayout.setRefreshing(false);
            }
        }, 600);
    }
});
//下拉刷新
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
    @Override
    public void onRefresh() {
        for(int i = 0; i < 3; i++){
            TextView textView = new TextView(getApplicationContext());
            textView.setTextSize(100);
            textView.setText(i + " -" +  i);
            recyclerView.addView(textView, 0);
            new Handler().postDelayed(new Runnable(){
                public void run(){
                    mSwipeRefreshLayout.setRefreshing(false);
                }
            },600);
        }
    }
});
//触底自动加载
ProgressBar progressBar = findViewById(R.id.progress);
ScrollView scrollView = findViewById(R.id.scroll);
scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
    @Override
    public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
        int height = scrollView.getChildAt(0).getMeasuredHeight();
        int Y = scrollView.getScrollY() + scrollView.getHeight();
        if(height <= Y){
            if(fadou){
                progressBar.setVisibility(View.VISIBLE);
                TextView et = new TextView(getApplicationContext());
                et.setText("whaha");
                et.setHeight(800);
                recyclerView.addView(et);
                fadou = false;//防抖
                new Handler().postDelayed(new Runnable(){
                    public void run(){
                        fadou = true;
                        progressBar.setVisibility(View.GONE);
                    }
                },1000);
            }
        }
    }
});

注:不使用ScrollView,可参考如下教程,下拉刷新、上拉加载
https://blog.csdn.net/huweiliyi/article/details/105779329?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164136338116780264070951%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=164136338116780264070951&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-105779329.first_rank_v2_pc_rank_v29&utm_term=RecyclerView&spm=1018.2226.3001.4187

16 Intent

// 从Fragment跳转到Activity,再从Activity返回Fragment
// 从Fragment跳转到Activity需使用Intent
private void goActivity() {
   Intent intent = new Intent(getActivity(), ChatActivity.class);
   startActivity(intent);
}
// 从Activity返回Fragment只需使用finish()
void back() {    
	finish();   
}
// 若想刷新Fragment,则将Fragment中的刷新方法放到onStart()中

16.1 页面跳转

16.1.1 Activity之间的跳转

startActivity(new Intent(ContactActivity.this, GroupActivity.class));
Intent(当前Activity.this, 目标Activity.class)

16.1.2 Fragment与Activity之间的跳转

getActivity().startActivity(new Intent(getActivity(), ContactActivity.class));
getActivity():在Fragment获取当前的Activity
ContactActivity:跳转的目标Activity

16.1.3 传值

(1)build.gradle下dependencies中添加Gson,可将对象转为json格式字符串格式
implementation 'com.google.code.gson:gson:2.8.2'
(2)存值

public void onClick(View view) {
    Intent intent = new Intent(getActivity(), CostDataAnalysis.class);
    intent.putExtra("data", new Gson().toJson(costList));
    intent.putExtra("date", checkDateStartAndEnd);
    startActivity(intent);
}

(3)取值

Intent intent = getIntent();
String str = intent.getStringExtra("data");
try {
   JSONArray costList = new JSONArray(str);
} catch (JSONException e) {
    e.printStackTrace();
}
String checkDateStartAndEnd = intent.getStringExtra("date");

16.2 打电话

Button buttonTel = getActivity().findViewById(R.id.imgBtn1Tel);
buttonTel.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 调用拨打电话,给10010拨打电话
        Uri uri = Uri.parse("tel:10010");
        Intent intent = new Intent(Intent.ACTION_DIAL, uri);
        startActivity(intent);
    }
});

16.3 打开浏览器进入指定网页

Button buttonTel2 = getActivity().findViewById(R.id.imgBtn2Tel);
buttonTel2.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 打开百度主页
        Uri uri = Uri.parse("https://www.baidu.com");
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
    }
});

16.4 地图

// 打开Google地图中国北京位置(北纬39.9,东经116.3)
Uri uri = Uri.parse("geo:39.9,116.3");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值