文章目录
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 下拉框
-
- 加入依赖
implementation 'com.github.arcadefire:nice-spinner:1.4.4'
- 加入依赖
-
- 布局
用户可以在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"/>
-
- 代码
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
-
- 加入依赖
implementation 'net.sourceforge.jexcelapi:jxl:2.6.12''
- 加入依赖
-
- 工具类
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();
}
}
-
- 调用
@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 配置环境
-
- 加入依赖
compile 'com.squareup.okhttp3:okhttp:3.6.0'
implementation 'com.google.code.gson:gson:2.8.2
- 加入依赖
-
- res下新建xml文件夹,在其中新建network_security_config.xml,其内容如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
-
- 在AndroidManifest.xml中application标签下添加:
android:networkSecurityConfig="@xml/network_security_config"
注意添加网络请求权限:
<uses-permission android:name="android.permission.INTERNET" />
- 在AndroidManifest.xml中application标签下添加:
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
-
- 引包
<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>
-
- 新建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
-
- 新建一个引入log4j的工具类
@ComponentScan
@ConfigurationProperties(“classpath:log4j.properties”)
public class Log4jConfigure {
}
-
- 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
-
- 在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>
-
- 增加自定义组件的容器activity_diy.xml
ScrollView:当容器中内容大于屏幕高度时,自动出现的滚动条
- 增加自定义组件的容器activity_diy.xml
<?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>
-
- 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 导航栏
-
- 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>
-
- 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/
-
- Fragment.java -> button添加监听器
(1)重写onActivityCreated,Fragment中的button监听必须在onActivityCreated中
(2)添加监听器
- Fragment.java -> button添加监听器
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);